EncodeParameters deinterlace bmp - c#

I'm looking for a way to take in a 32 bit bitmap and save it again however deinterlacing the frames. When the image is taken two fields are visible but only the last one is necessary. Is this possible to do using EncoderParameters. This is what I've tried so far:
using (Image source = Image.FromFile(#"C:\Users\Martin vanPutten\Desktop\test.bmp"))
{
ImageCodecInfo codec = ImageCodecInfo.GetImageEncoders().First(c => c.MimeType == "image/bmp");
EncoderParameters parameters = new EncoderParameters(3);
parameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
parameters.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.ScanMethod, (int)EncoderValue.LastFrame);
parameters.Param[2] = new EncoderParameter(System.Drawing.Imaging.Encoder.RenderMethod, (int)EncoderValue.RenderNonProgressive);
source.Save(#"C:\Users\Martin vanPutten\Desktop\test2.bmp", codec, parameters);
}
Is there another way to do this? All I need to do is remove the second overlapping frame in an image.
Quick update, its not that it has two frames, but 2 fields in 1 frame.

Related

C# saving bitmap to jpeg with colour space information

I've been trying to find a ways to write in information about jpeg colour space information, since regular saving does not do that, and barely anyone talks about it. Part of the code I use to save into jpeg:
using (Bitmap bmp = new Bitmap(bitmapPicture))
{
ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg);
System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 100L);
myEncoderParameters.Param[0] = myEncoderParameter;
bmp.Save(textBox1.Text + "\\" + textBox2.Text + ".jpg", jpgEncoder, myEncoderParameters);
}
It does the trick, but it doesn't add colour space information which I think is one of the problems when opening that picture with different applications. The colours appears to be incorrect. Also for some reason bitmap brush only uses argb colour space (notice code below). If I'd type in '.FromSrgb' or '.FromRgb' it errors it out (apparently no such thing exists). This is example how I create bitmap which later on is being saved:
using (Graphics gfx = Graphics.FromImage(bitmapPicture))
using (SolidBrush brush = new SolidBrush(System.Drawing.Color.FromArgb(255, 255, 255)))
{
gfx.FillRectangle(brush, 0, 0, with, height);
gfx.DrawImage(addOtherImageOnSameBitmap, xCoordinate, yCoordinate, with2, height2);
}
Also tried doing that with Save File Dialog (code below), but the result is the same - jpeg colours is way off and has no information about colour space.
SaveFileDialog save = new SaveFileDialog();
save.Filter = "Images|*.jpg";
ImageFormat format = ImageFormat.Png;
if (save.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string ext = System.IO.Path.GetExtension(save.FileName);
switch (ext)
{
case ".jpg":
format = ImageFormat.Jpeg;
break;
}
pictureBox1.Image.Save(save.FileName, format);
}
The problem is fixed when opening that image in photoshop and saving it with sRGB colour space. Is it possible to do that in C#? To save jpeg in sRGB and adding this information to jpeg file itself? Because going into photoshop to fix this problem seems to be a bit too much of a hassle (especially when dealing with a lot of pictures).
P.S. sorry if posted codes seems somewhat off, I just started learning C# couple days ago.

How can I get good-quality text when using a RenderTargetBitmap?

I need to create a small, simple TIFF image that is just black text on a white background, as part of a support library we use across several of our products. (Think a simple receipt or deposit ticket, that kind of thing). I would prefer not to have to use any third-party libraries, to avoid requiring us to add additional dependencies to all of the existing products that use the library.
I have almost gotten the problem solved using just WPF, based on the code from this question. The TIFF is created and rendered properly, but the text quality is horrible. As far as I can determine, the problem is that RenderTargetBitmap, at least the way I'm using it, isn't doing any kind of anti-aliasing, isn't using ClearType, or otherwise is just really bad at rendering plain text, e.g.:
I've read similar questions, such as this one or this one, but they all seem to discuss how to capture text from a visual control or window handle without reducing the quality. I'm doing this entirely off-screen, so I'm not clear if/how I can apply those solutions to my problem.
What I'm currently doing is:
var visual = new DrawingVisual();
using (var draw = visual.RenderOpen())
{
// 'background' is a pre-loaded blank white bitmap
draw.DrawImage(background, new Rect(0, 0, IMG_WIDTH, IMG_HEIGHT));
var font = new Typeface("Segoe UI");
Func<string, FormattedText> format = s => new FormattedText(
s,
CultureInfo.CurrentUICulture,
FlowDirection.LeftToRight,
font,
16,
Brushes.Black);
draw.DrawText(format("Some text"), new Point(HEADER_LEFT, HEADER_TOP);
// Call draw.DrawText a whole bunch more times.
.
.
.
}
var render = new RenderTargetBitmap(IMG_WIDTH, IMG_HEIGHT, IMG_DPI, IMG_DPI, PixelFormats.Default);
render.Render(visual);
var encoder = new TiffBitmapEncoder()
{
Compression = TiffCompressOption.Ccitt4
};
encoder.Frames.Add(BitmapFrame.Create(render));
var stream = new MemoryStream();
encoder.Save(stream);
Is there something else I can put in there to get the text quality better than what it is?
Don't use Ccitt4, it's for black-and-white images only. Try Default instead.
UPDATE:
It's a TT font and you're trying to render it at a small size, no matter what you do it's going to look pretty crap. Still, if you insist then don't use a visual. Screen elements use hardware acceleration, when you use them with a render target as you are here it has to fall back to a software approach which isn't always pixel-for-pixel the same. And either way you always get at least some aliasing. If you really do want proper bitonal then you'll have to use a Graphics object which will use GDI:
var bitmap = new Bitmap(512, 256);
var graphics = Graphics.FromImage(bitmap);
graphics.Clear(System.Drawing.Color.White);
var font = new Font("Segoe UI", 16);
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
graphics.DrawString("Hello World", font, System.Drawing.Brushes.Black, 0, 0);
ImageCodecInfo myImageCodecInfo = GetEncoderInfo("image/tiff");
var myEncoderParameters = new EncoderParameters(1);
myEncoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)EncoderValue.CompressionCCITT4);
bitmap.Save(#"myimage.tif", myImageCodecInfo, myEncoderParameters);
graphics.Dispose();
private static ImageCodecInfo GetEncoderInfo(String mimeType)
{
int j;
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for (j = 0; j < encoders.Length; ++j)
{
if (encoders[j].MimeType == mimeType)
return encoders[j];
}
return null;
}
Result (which SO is blurring a bit itself):

Converting to real 8bpp Jpeg

I already searched and tried all the suggestions given it at SO, AForge, FreeImage and couple more websites, but I'm unable to transform an image into a real 8bpp one. I always get the JPEG saved as 24bpp instead of 8.
After the grayscale conversion I have a MemoryBMP (according to myImage.RawFormat), so when I save it like this
myImage.Save("image.jpg");
I get a 3Mb+ image (so I assume it's saved in BMP) which Windows tells me is 8bpp (but I need it to be JPEG). But if I save it like this
myImage.Save("image_JPEG.jpg", ImageFormat.Jpeg);
I get a 400Kb image (so I assume it's saved in JPEG) but it's in 24bpp.
Any ideas what can be causing this?
EDIT
As JYelton mentioned this is a limitation of Image.Save() method, so I changed to saving the image with the FreeImage library: FreeImage.SaveBitmap() works like a charm.
UPDATE: The Image.Save() method does not support 8 bit per pixel for JPEG format. You may want to use the FreeImage library instead, as mentioned in the comments below.
If you want to reduce color depth to 8 bits per pixel, typically that is the same as converting from 24-bit color to grayscale, where each color channel has 8 bits per pixel to begin with. (In other words, reducing 3 channels of color information to 1.)
The default encoder when using Image.Save() and specifying ImageFormat.Jpeg is 24 bpp, so you'll need to specify an encoder and supply some parameters:
ImageCodecInfo[] availableCodecs = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo jpgCodec = availableCodecs.FirstOrDefault(codec => codec.MimeType == "image/jpeg");
if (jpgCodec == null)
throw new NotSupportedException("Encoder for JPEG not found.");
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = new EncoderParameter(Encoder.ColorDepth, 8L);
myImage.Save("image_JPEG.jpg", jpgCodec, encoderParams);
This is a modified example from a longer explanation I found at aspnet-answers.com.
Here is one way to verify if ImageFormat.Jpeg supports Encoder.ColorDepth:
using System.Linq;
bool IsSupportedParameters(ImageFormat imageFormat, Encoder encoder)
{
var codec = ImageCodecInfo.GetImageEncoders().First(c => c.FormatID == imageFormat.Guid);
Bitmap bitmap = new Bitmap(1, 1);
EncoderParameters? paramList = bitmap.GetEncoderParameterList(codec.Clsid);
if (paramList != null)
{
return paramList.Param.Any(encParams => encParams.Encoder.Guid == encoder.Guid);
}
return false;
}
Lead to:
IsSupportedParameters(ImageFormat.Jpeg, Encoder.ColorDepth); // false
IsSupportedParameters(ImageFormat.Jpeg, Encoder.ChrominanceTable); // true
So you need to use another library to achieve what you want. For example see:
https://stackoverflow.com/a/31962503/136285
References:
How to: Determine the Parameters Supported by an Encoder
Encoder.ColorDepth Field

Saving encoded image returns GDI+ error

Here's the deal. I'm trying to use a function to compress an image from my notebook camera while using a standard code to do that:
public static byte[] EncodeImage(this Image image)
{
using (MemoryStream ms = new MemoryStream())
{
ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 80);
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
image.Save(ms, jpegCodec, encoderParams);
return ms.ToArray();
}
}
After the compression is done, I save it to the database. Works good, providing me with a good amount of compression (500 000 bytes vs 32 000). Some time later, I need to show the image to the user in a winforms application.
using (MemoryStream ms = new MemoryStream(entity.Photo))
fotoPictureBox.Image = Image.FromStream(ms);
Again, this displays a nice image. However, then I want the user to be able to download the image and save where he sees suitable. And this is when all the problems arise.
If I use this code:
fotoPictureBox.Image.Save(imageSaveFileDialog.FileName);
I receieve a typical generic GDI+ error.
If I try to save the image by using the code I've encoded it
public static void SaveEncodedImage(this Image image, string targetPath)
{
ImageCodecInfo jpegCodec = Pomocne.GetEncoderInfo("image/jpeg");
EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 80);
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
image.Save(targetPath, jpegCodec, encoderParams);
}
I get this error (pointing to the line image.Save(targetPath, jpegCodec, encoderParams);):
An unhandled exception of type System.ArgumentException occurred in System.Drawing.dll
Additional information: Parameter is not valid.
Can please anyone help? It's rather urgent, thank you.
To address some questions/answers you will probably start with - if I don't compress the image with this code, I can save the image to the chosen path without any problems. So there's clearly some problem with decoding or something like that. Don't ask me if I have sufficient permissions, because I have.
For some reason this code works great:
File.WriteAllBytes(targetPath, byteArray);
I guess sometimes the easiest solution is the right one. Not sure about the exact explanation (you can provide one, I'll surely vote up), but this is resolved.
Thanks anyway.

how to make Image.Save save as a 24-bit image?

How do I get C# to force bitmap images that are saved to be saved as 24-bit images as can be seen when you get the right-click properties of the image in Windows. All the images I save are set to 32-bit.
I tried the below code with no luck. The source images are all 24-bit as well but are always saved as 32-bit images.
ImageCodecInfo bmpCodec = FindEncoder(ImageFormat.Bmp);
EncoderParameters parameters = new EncoderParameters();
parameters.Param[0] = new EncoderParameter(Encoder.ColorDepth, 24);
imgCheque.Save(DestinationFile.ToString(), bmpCodec, parameters);
The images have to be properly 24 bit as the are read by a different program that can't handle 32-bit images.
Thanks in advance,
Soultech
Is this any use?
// imgCheque source created somewhere else up here
using (Bitmap blankImage = new Bitmap(imgCheque.Width, imgCheque.Height, PixelFormat.Format24bppRgb))
{
using (Graphics g = Graphics.FromImage(blankImage))
{
g.DrawImageUnscaledAndClipped(imgCheque, new Rectangle(Point.Empty, imgCheque.Size));
}
ImageCodecInfo bmpCodec = FindEncoder(ImageFormat.Bmp);
blankImage.Save(#"C:\TEMP\output.bmp", bmpCodec, null);
}
Try this?
ImageCodecInfo bmpCodec = FindEncoder(ImageFormat.Bmp);
EncoderParameters parameters = new EncoderParameters();
parameters.Param[0] = new EncoderParameter(Encoder.ColorDepth, 24L);
imgCheque.Save(DestinationFile.ToString(), bmpCodec, parameters);

Categories

Resources