How can I convert a PNG Image to a 1Bpp using SkiaSharp. I am currently using the SkiaSharp to do all the image processing for my .NET applications/services, and I have not been able to find an in-built way to encode an image from a SKCanvas or SKData to a 1bpp image format, I saw that Bmp & wbmp are available but they both return null in the following example:
byte[] imageBytes = *PNG Image Byte Array*
SKImage.FromEncodedData(imageBytes).Encode(SKEncodedImageFormat.Bmp, 100).ToArray();
SKImage.FromEncodedData(imageBytes).Encode(SKEncodedImageFormat.Wbmp, 100).ToArray();
Any ideas on how to accomplish this without doing a lot of custom code? Any help is most appreciated.
In the SkiaSharp, only three of these file formats (Jpeg, Png, and Webp) are actually supported by SkiaSharp. For all the other formats, the Encode method writes nothing into the stream and the resultant byte array is null. So this can not convert a PNG Image to a 1Bpp by using SkiaSharp.
Related
I'm using the BitMiracle.LibTiff v2.4.560.0 to convert oJPEG tiffs to Bitmap. This has worked out great until just recently. A Tiff, that I tried converting, is a document with a white background and black text. After converting the tiff, the result ends up with a black background and white text.
I'm using this Convert from Tiff to Bitmap sample for my conversion.
Is this a bug with the BitMiracle.LibTiff library or does there need to be modifications to the sample code? I made quite a few attempts of modifying the sample code, but with no success.
It turns out the image that causes the issue has a TiffTag.PHOTOMETRIC of Photometric.MINISWHITE. Changing that property to Photometric.MINISBLACK resolves the issue.
Added this snippet to Convert from Tiff to Bitmap
FieldValue[] value = tif.GetField(TiffTag.PHOTOMETRIC);
if (value[0].ToInt() == (int)Photometric.MINISWHITE)
{
tif.SetField(TiffTag.PHOTOMETRIC, Photometric.MINISBLACK);
}
Right now I am using System.Drawing.Bitmap to take an image and divide it into regions. I assume that Bitmap must decompress the image in order to perform operations on it.
However, the Bitmap class accepts these formats: BMP, GIF, EXIF, JPG, PNG and TIFF
Some of these formats are compressed, so if the data in the stream is compressed, doesn't it have to be decompressed to perform manipulations? If so, does that mean that the Bitmap class allocates more memory for the decompressed version of the stream?
i feel like if the bitmap class makes data modifications to the stream then it would have to decompress the stream which should make the bitmap class take the same amount of memory working with BMP streams as when it works with PNG streams, despite the fact that the PNG streams is smaller.
In fact it does, GDI needs raw pixel data to feed it to the graphic card and/or represent it, so yes, it's being decompressed, but may be you don't see the memory rising because it's done into the system/graphic card.
Some special cases are DXT textures and some other special types which are understood by the hardware and don't need to be decompressed to work.
I'm handling a lot of different image formats within my application. Luckily I was able to source out the biggest part of dealing with image formats to C#WPF. However, I've got an issue when saving images:
I'd like to save my images as JPEGs using JpegBitmapEncoder with an RGB profile. This works all fine for color image formats. However, when handling images i.e. of format Gray16 or Gray8, the resulting JPEGs will have a Grayscale profile. I really do need an RGB profile for my JPEGs!
I know that I could just create a new WriteableBitmap in Bgra32, copy to it the data and use it to create the JPEG. This however means, that I would need to handle the different image formats myself. Most importantly I believe that this detour would be quite inefficient computationally (I need to convert a lot of image data!).
Also I can't use any solutions outside of C#/WPF (like Imagemagick).
I hope that there's a way to solve this easily and efficiently. I found no way to configure JpegBitmapEncoder for this and I had a try with ColorConvertedBitmap but to no avail!
Any ideas?
The hint for FormatConvertedBitmap gave me the solution to my problem! Thanks RononDex!
FormatConvertedBitmap convertImg = new FormatConvertedBitmap(img, PixelFormats.Bgra32, null, 0);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(convertImg));
encoder.Save(stream);
to give a background on what this topic is about. I am trying to convert an image file to byte[] by using a memorystream to return the memorystream.ToArray();
However, i have noticed that the image quality decreases after the conversion inputBitmap -> byte[] -> outputBitmap.
outputBitmap has a lower quality than the inputBitmap.
My code to convert the image to byte[] is as follows
MemoryStream mstream = new MemoryStream();
myImage.Save(mstream,System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] buffer = mstream.ToArray();
and to convert from the byte[] back to an image,
MemoryStream mstream = new MemoryStream(buffer);
Image newImage = Image.FromStream(mstream);
can somebody explain why this is and hopefully guide me to correct this problem?
Note that before i used the inputBitmap as my pictureBox.Image, it looks great in quality. But after converting from byte[] to outputBitmap, setting outputBitmap as my pictureBox.Image becomes kind of blurred and low in quality.
A couple of things stand out for me.
You are saving to JPG rather than a lossless format like PNG.
You are not setting the quality of the compression used to save the image.
This means that you are probably compressing an image that has already been compressed thus losing even more information in the process.
I'd change to saving the file as PNG if I could, failing that make sure you set the quality of the JPG to 100% before you save it. This will reduce to a minimum the compression on the file and hence minimise the data loss.
If you're still seeing a difference in quality then the only thing that I can think of that might explain a this is a difference in the resolution (number of pixels and/or colour depth) between the screen shot and the saved file. Make sure you set the target bitmap size and colour depth to be the same as the source bitmap.
I'm trying to convert a 32bpp screenshot image to an 8bpp (or 4bpp, or 1bpp) format using C#. I've already looked at several stackoverflow answers on similar subjects and most suggest variations using the following code:
public static Bitmap Convert(Bitmap oldbmp)
{
Bitmap newbmp = new Bitmap(oldbmp.Width, oldbmp.Height, PixelFormat.Format8bppIndexed);
Graphics gr = Graphics.FromImage(newbmp);
gr.PageUnit = GraphicsUnit.Pixel;
gr.DrawImageUnscaled(oldbmp, 0, 0);
return newbmp;
}
However, when this executes, I get a the exception: A graphics object cannot be created from an image that has an indexed pixel format. I understand that 8, 4 and 1bpp images have colour table mappings rather than the actual colour pixels themselves (as in 32 or 16bpp images) so I assume I'm missing some conversion step somewhere, but I'm fairly new to C# (coming from a C++ background) and would prefer to be able do this using native C# calls rather than resorting to PInvoking BitBlt and GetDIBits etc. Anybody able to help me solve this? Thanks.
EDIT: I should point out that I need this to be backwardly compatible to .NET framework 2.0
GDI+ in general has very poor support for indexed pixel formats. There is no simple way to convert an image with 65536 or 16 million colors into one that only has 2, 16 or 256. Colors have to be removed from the source image and that is a lossy conversion that can have very poor results. There are multiple algorithms available to accomplish this, none of them are perfect for every kind of image. This is a job for a graphics editor.
There is one trick I found. GDI+ has an image encoder for GIF files. That's a graphics format that has only 256 colors, the encoder must limit the number of colors. It uses a dithering algorithm that's suitable for photos. It does have a knack for generating a grid pattern, you'll be less than thrilled when it does. Use it like this:
public static Image Convert(Bitmap oldbmp) {
using (var ms = new MemoryStream()) {
oldbmp.Save(ms, ImageFormat.Gif);
ms.Position = 0;
return Image.FromStream(ms);
}
}
The returned image has a 8bpp pixel format with the Palette entries calculated by the encoder. You can cast it to Bitmap if necessary. By far the best thing to do is to simply not bother with indexed formats. They date from the stone age of computing back when memory was severely constrained. Or use a professional graphics editor.
AForge library is doing it perfectly using Grayscale.
var bmp8bpp = Grayscale.CommonAlgorithms.BT709.Apply(bmp);
This class is the base class for image grayscaling [...]
The filter accepts 24, 32, 48 and 64 bpp color images and produces 8
(if source is 24 or 32 bpp image) or 16 (if source is 48 or 64 bpp
image) bpp grayscale image.
Negative stride signifies the image is bottom-up (inverted). Just use the absolute of the stride if you dont care. I know that works for 24bpp images, unaware if it works for others.
You can use System.Windows.Media.Imaging in PresentationCore Assembly take a look at here for more information