I've inherited a C# .Net Windows Forms project which receives a Device Independent Bitmap (as an array of bytes) from a Managed pre-compiled DLL. The C# code makes a dummy BMP file from the DIB so that it can create a Bitmap which can then be drawn using System.Drawing.Graphics.DrawImage.
using (MemoryStream ms = new MemoryStream())
{
ms.Write(fileHeader, 0, fileHeader.Length);
ms.Write(dibBuffer, 0, dibBuffer.Length);
Bitmap img = (Bitmap)Image.FromStream(ms);
g.DrawImage(img, 0, 0, width, height);
}
This works when the DIB contains uncompressed pixel data but on some hardware, the pixel data is in YV12 format and Image.FromStream raises a System.ArgumentException which I think indicates that the underlying code (GDI+?) considers the BMP to be in an invalid or unsupported format.
In this scenario, the DIB's BITMAPINFOHEADER (first 40 bytes) has these values:
biSize: 40
biWidth:640
biHeight: 480
biPlanes: 1
biBitCount: 12
biCompression: 'YV12'
biSizeImage: 460800
biXPelsPerMeter: 0
biYPelsPerMeter: 0
biClrUsed: 0
biClrImportant: 0
Does the BMP format even support YV12? I can't find any example
images online.
Is there a different way of handling the DIB to make it suitable for
DrawImage? The above code seems to jump through hoops.
Related
I have a file that I can view in ImageJ but most software just shows it in black. I am trying to view it in C# but it just comes up black, it is also not viewable in paint but I can view it in INcarta and ImageJ. The file is a 16 bit tiff that seems to have LZW compression
I am trying to use ImageSharp to decode this image and then show it as a bitmap. Here is a link to the file https://drive.google.com/file/d/16Xotc-2CJ6HkEJDysfKBkjClkU1OGiyQ/view?usp=sharing
byte[] data = File.ReadAllBytes(fileToDisplay1);
SixLabors.ImageSharp.Formats.Tiff.TiffDecoder decoder = new SixLabors.ImageSharp.Formats.Tiff.TiffDecoder();
SixLabors.ImageSharp.Formats.Tiff.TiffEncoder encoder = new SixLabors.ImageSharp.Formats.Tiff.TiffEncoder();
SixLabors.ImageSharp.Image? image = SixLabors.ImageSharp.Image.Load(data, decoder);
System.Drawing.Bitmap bMap;
using (var ms = new MemoryStream())
{
image.Save(ms, encoder);
bMap = new Bitmap(ms);
}
I have also tried ImageMagickQ16
byte[] data = File.ReadAllBytes(fileToDisplay1);
var decoder = new SixLabors.ImageSharp.Formats.Tiff.TiffDecoder();
var encoder = new SixLabors.ImageSharp.Formats.Tiff.TiffEncoder();
//encoder.BitsPerPixel = SixLabors.ImageSharp.Formats.Tiff.TiffBitsPerPixel.Bit16;
var image = SixLabors.ImageSharp.Image.Load(data, decoder);
MagickImage im2;
using (var ms = new MemoryStream())
{
image.Save(ms, encoder);
im2 = new MagickImage(ms.ToArray());
}
//im2.Depth = 16;
//im2.Grayscale();
im2.AutoLevel();
return im2.ToBitmap();
The File Looks like this: in ImageJ but is black when I upload it or when I try to use other software.
I I have commented out other things I have tried
Imagemagick identify -verbose thinks your data is binary, just black and white. So there is some error in Imagemagick.
Image:
Filename: mystery.tif
Format: TIFF (Tagged Image File Format)
Mime type: image/tiff
Class: DirectClass
Geometry: 2040x2040+0+0
Units: PixelsPerInch
Colorspace: Gray
Type: Bilevel
Base type: Grayscale
Endianness: LSB
Depth: 16/1-bit
Channel depth:
gray: 1-bit
Channel statistics:
Pixels: 4161600
Gray:
min: 0 (0)
max: 0 (0)
mean: 0 (0)
standard deviation: 0 (0)
kurtosis: -3
skewness: 0
entropy: 0
Colors: 1
Histogram:
4161600: (0,0,0) #000000000000 gray(0)
Rendering intent: Perceptual
Gamma: 0.454545
Chromaticity:
red primary: (0.64,0.33)
green primary: (0.3,0.6)
blue primary: (0.15,0.06)
white point: (0.3127,0.329)
Background color: gray(255)
Border color: gray(223)
Matte color: gray(189)
Transparent color: gray(0)
Interlace: None
Intensity: Undefined
Compose: Over
Page geometry: 2040x2040+0+0
Dispose: Undefined
Iterations: 0
Compression: LZW
Orientation: TopLeft
Properties:
date:create: 2022-09-27T00:43:06+00:00
date:modify: 2022-09-27T00:42:39+00:00
date:timestamp: 2022-09-27T00:43:25+00:00
signature: 28f00fa3c1987b7b8f92961ef3a2d442cca23dbbb7c568b8908cc2fa2271de60
tiff:alpha: unspecified
tiff:endian: lsb
tiff:photometric: min-is-black
Artifacts:
filename: mystery.tif
verbose: true
Tainted: False
Filesize: 48240B
Number pixels: 4161600
Pixels per second: 84.8629MB
User time: 0.060u
Elapsed time: 0:01.049
Version: ImageMagick 6.9.12-64 Q16 aarch64 17467 https://legacy.imagemagick.org
Mac Preview, GraphicConverter and Photoshop can read your image, but the gray levels are very low for a 16-bit range. Thus they appear at first glance as black. If the image dynamic range is stretched, the features show up.
But this does not work with Imagemagick since it thinks the data is binary and as such all the data values being very low have been put into the black bin.
Post and error to the Imagemagick web site at https://github.com/ImageMagick/ImageMagick/issues
This is either a bug in Imagemagick or your file is malformed according to the tiff documentation. The IM developers will need to decide which.
By default, the TiffDecoder will decode images as Rgba32 when using the non-generic API, (something we can look into updating for v3 based upon the bit depth), so you will not be capturing the image information since you are squashing 16bpp info into 8bpp.
Currently you can use Image.Identify(...) to determine the correct bit depth and make intelligent decoding choices, however, given that you know this image is grayscale and has a high dynamic range let's just decode it using L16 (16bit single luminance component) and then stretch the histogram using the newly added method for V3. https://github.com/SixLabors/ImageSharp/pull/2235
using Image<La16> image = Image.Load<La16>(...);
image.Mutate(x => x.HistogramEqualization(new()
{
LuminanceLevels = 65536,
Method = HistogramEqualizationMethod.AutoLevel
}));
image.SaveAsPng(...)
The result is as expected.
PM> Install-Package SixLabors.ImageSharp -Version 3.0.0-alpha.0.52 -Source https://www.myget.org/F/sixlabors/api/v3/index.json
We have a system that provides images in 8-bit grayscale either tiff or jpg formats. However, the component we have to process the images expects image to be in 8-bit jpg format.
When I use .Net to save the tiff images as jpg it convets it to 24-bit image.
Is there a way, hopefully simple and fast, to convert 8-bit grayscale tiff images to equivalent jpg?
I tried and tried just to conclude that I'm sorry: .Net library's Bitmap class DOES NOT save JPEG as 8bpp even when explicitly stated and data is in grayscale.
(note: although stated in some places, JPEG format DOES support 8bpp).
At Convert an image to grayscale you may find code snipet to convert to grayscale any Image.
Using that code, I was able to save a 8bpp grayscale Image instance with '.jpeg' extension, but stating ImageFormat.Gif... that's a cheat...
My findings show as solution an entirely different approach.
The FreeImage library offers powerful APIs, including the feature needed to solve your problem.
It's home page is at http://freeimage.sourceforge.net/faq.html
But, I could not easily compile it in my Win2008 + VS 2010 machine.
One ought to sweat a lot to make it run on modern environments.
Some hints on how to accomplish that are found at http://www.sambeauvois.be/blog/2010/05/freeimage-and-x64-projects-yes-you-can/
Good luck!
Image img = Image.FromFile(filePathOriginal);
Bitmap bmp = ConvertTo8bpp(img);
EncoderParameters parameters = new EncoderParameters();
parameters.Param[0] = new EncoderParameter(Encoder.ColorDepth, 8);
bmp.Save(filePathNew, jpgCodec, parameters);
bmp.Dispose();
img.Dispose();
...
private static Bitmap ConvertTo8bpp(Image img) {
var bmp = new Bitmap(img.Width, img.Height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
using (var gr = Graphics.FromImage(bmp))
{
gr.DrawImage(img, new Rectangle(0, 0, img.Width, img.Height));
}
return bmp;
}
I am using Bit Miracle LibTiff.Net.
I cannot find any sample code to take a 32bpp ARGB colour image and write the bitmap to a TIFF using this library.
Has anyone else attempted this?
Here is my sample code. It produces a file, but it cannot be viewed by any software that I have.
EDIT: The code now works, but the colors are wrong!
public static void WriteTiff(Image image, string fileName)
{
Bitmap target = image as Bitmap;
BitmapData bmd = target.LockBits(
target.GetRectangle(),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb);
var bits = new byte[bmd.Stride * bmd.Height];
Marshal.Copy(bmd.Scan0, bits, 0, bits.Length);
target.UnlockBits(bmd);
Tiff tiff = Tiff.Open(fileName, "w");
tiff.SetField(TiffTag.IMAGEWIDTH, target.Width);
tiff.SetField(TiffTag.IMAGELENGTH, target.Height);
tiff.SetField(TiffTag.COMPRESSION, Compression.NONE);
tiff.SetField(TiffTag.PHOTOMETRIC, Photometric.RGB);
tiff.SetField(TiffTag.BITSPERSAMPLE, 8);
tiff.SetField(TiffTag.SAMPLESPERPIXEL, 4);
tiff.SetField(TiffTag.ROWSPERSTRIP, target.Height);
tiff.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);
tiff.WriteEncodedStrip(0, bits, bits.Length);
tiff.Close();
}
Thanks
EDIT
The latest build of LibTiff.Net contains samples for conversion of a System.Drawing.Bitmap to 32-bit or 24-bit color LZW compressed TIFF images.
There is also samples for conversion of a TIFF image to 32-bit or 24-bit System.Drawing.Bitmaps.
/EDIT
You may also want to review "Graphics programming with LibTiff.Net" (part 1, part 2) article
in documentation. It should give you basic information about creating
color TIFF files.
Disclaimer: I am one of the maintainers of the library.
I am writing a program that resizes pictures like this:
Image originalImage = Image.FromFile(pathToOriginalPicture);
Bitmap b = new Bitmap(newWidth, newHeight);
Graphics g = Graphics.FromImage(b);
g.DrawImage(originalImage, 0, 0, newWidth, newHeight);
g.Dispose();
b.Save(pathToOutputPicture, ImageFormat.Jpeg);
I tried to set:
newWidth = originalImage.Width;
newHeight = originalImage.Height;
The result was that the rezised picture file became ~900K while the original file was ~4M.
Why this is happening ?
Is the quality of the original picture better than the resized one ? How?
I opened both pictures in Photoshop and I see that the original picture was 72ppi, while the resized one became 96ppi. Why is that ? Can I control this ?
Thanks a lot for your time !
You're not telling us the original format of your picture but you're saving as a JPEG:
b.Save(pathToOutputPicture, ImageFormat.Jpeg);
JPEG is a lossy compression format.
In addition to being lossy, JPEG also can output different quality (which is configurable).
This is what is happening to your file size: it is shrinking because you went, say, from a lossless format to the lossy JPEG or because you went from JPEG to JPEG-with-a-lower-quality.
Hence the size reduction.
Besides the format you need to set DPI, compression level settings etc. Check your Save function for overloads that will accept this type of input. See this documentation.
I have image file which is 6k jpg file with width: 172px and hight: 172px.
I use the following code try to resize it to 128*128px jpg file:
public static Image ResizeImage(Image img, int width, int height)
{
var b = new Bitmap(width, height, PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(b))
{
g.DrawImage(img, 0, 0, width, height);
}
return b;
}
This code has strangely increased the file size to 50k, can any one explain why? and how to resize the image to 128*128px and keep the size about 6k.
Many thanks.
DY
It depends on the algorithm that was used to compress the jpeg file. Certain algorithms are more lossy (lose image quality) than others but benefit from a smaller size.
What's happening is that in code, the jpeg is being expanded into a bitmap while in memory. When it went to save the 128x128 jpeg out, the code used an algorithm which does less compressing than the one used to save the original picture. This caused it to produce a larger jpeg file, even though the image size itself is smaller.
In the code posted, you are not returning JPEG file, but bitmap (128x128 24bpp uncompressed bitmap has size 48kB). You have to compress it again, this tutorial might help.