ImageSharp
ImageSharp copied to clipboard
Load Image from an array of Bytes invert color
Prerequisites
- [X] I have written a descriptive issue title
- [X] I have verified that I am running the latest version of ImageSharp
- [X] I have verified if the problem exist in both
DEBUG
andRELEASE
mode - [X] I have searched open and closed issues to ensure it has not already been reported
ImageSharp version
2.1.1
Other ImageSharp packages and versions
2.1.1
Environment (Operating system, version and so on)
Windows 10
.NET Framework version
Net Core 3.1
Description
Hello again; I can load an image (tiff format with differents sizes) from an array of bytes using "FrameDecodingMode.First"; so far so god. But randomly, the library load the image inverting colors (black & white, insted white & black). the original image is white with black lines; sometimes, it load the image as black with white lines. Any help? Thanks a lot...
Steps to Reproduce
byte[] tiffImage = GetImageFromBytes(); // this load the array with one image from a database TiffDecoder decoder = new TiffDecoder(); decoder.DecodingMode = FrameDecodingMode.First; using (Image img = Image.load(tiffImage, decoder); { }
Images
No response
You’re supposed to provide means to reproduce issues. You have not done that.
If you are unable to do so we will have to close this issue.
Sorry, my mistake; I send you two images; they are only examples. I can not send you the real images, but i think they represent the situation.
@dfornero the images you have provided are jpg images and not tiff images.
Hi; Unfortunely I can not send you the original images; they are confidential information. I send you two jpg just to ilustrate what happen in this case.
Then I’m afraid the only way this potential issue could be fixed is by someone from your side submitting a PR with the fix. Without a means to replicate we have nothing to debug.
Ok, thanks any way.
@brianpopow wait, TIFF images can be encoded with jpeg YccK color, right?
Usually such 'inverted' images could be generated via invalid rgb -> ycck conversion formula:
// rgb -> cmyk
CmykScalar.ConvertFromRgb(in values, maxValue, rLane, gLane, bLane);
// cmyk -> ycck
Span<float> c = values.Component0;
Span<float> m = values.Component1;
Span<float> y = values.Component2;
for (int i = 0; i < y.Length; i++)
{
// color inversion here
// sometimes people on the internet miss it as YccK is super rare and poorly documented
// leading to negative images
float r = maxValue - c[i];
float g = maxValue - m[i];
float b = maxValue - y[i];
// k value is passed untouched from rgb -> cmyk conversion
c[i] = (0.299f * r) + (0.587f * g) + (0.114f * b);
m[i] = halfValue - (0.168736f * r) - (0.331264f * g) + (0.5f * b);
y[i] = halfValue + (0.5f * r) - (0.418688f * g) - (0.081312f * b);
}
We also don't write APP14 marker for CMYK images which can be misinterpreted by some image showing software. CMYK/YccK is the only part in the jpeg format which can cause this (is given images actually used jpeg compression).
@brianpopow wait, TIFF images can be encoded with jpeg YccK color, right?
@br3aker Yes that's correct, but it's unclear if the tiff image here actually uses Jpeg compression. Since it is a black and white image, it is very likely using one of the compression schema's for black and whit (fax3/fax4 maybe).
My bet is, that there is something going wrong here with the PhotometricInterpretation
(its tells how the pixel data is to be interpreted) during decoding the image. This can be BlackIsZero
or WhiteIsZero
.
@dfornero maybe you could provide more meta data about the image in question? A useful tool for that is tiffinfo
, which comes with libtiff: http://www.libtiff.org/tools.html
Just use tiffinfo image.tiff
Or imagemagick:
magick identify -verbose image.tiff
SixLabors ImageSharp 2.1.2 and .Net Core 6.0.
Same issue here working with images from a repository. They have confidential information so I can't attach the originals as in the OP's case. I'll see if I can recreate a multi-page tiff image with the same issues but I'm not sure how to do that at this point.
I can see that the existing images in my case have a 2 color indexed palette (black/white), CCITT T6 compression, while the ImageSharp tiff metadata shows null for all of the colorspaces when I load one of the images. The OPs image looks like greyscale though.
SaveAsTiff with encoder options doesn't change the results even with different PhotometricInterpretation options. So, do we have to use a pixel by pixel color space conversion to invert the black/white on our images? I don't see any automatic whole-image colorspace conversions to try unless I missed that.
@CREFaulk without the image, it's nearly impossible to tell what's wrong (I guess something goes wrong while decoding).
What happens, when you convert the image to a png with imagemagick?
magick convert image.tiff image.png
Does the resulting png look as you expect? Is it different from what ImageSharp produces when you save it as a PNG?
Here is the image info from imagemagick. https://pastebin.com/eaB7puQ6
tiff:photometric: min-is-black
If I convert to a png it looks as it should although obviously as separate images. I'll see if I can create a test image in our repository that can reproduce the issue.
Thanks for the image info. Nothing too fancy there. Endianess is lsb, tiff:photometric: min-is-black and compression is group4. We have such test images in our unit tests working.
If I convert to a png it looks as it should although obviously as separate images. I'll see if I can create a test image in our repository that can reproduce the issue.
How did you convert it? Does converting with imagemagick work as expected or converting with ImageSharp to PNG also works as expected, but not when you encode it as Tiff?
I used the imagemagick command you suggested to convert the original tiff to png file(s) and they looked like they should.
In c#, I tried converting the tiff pages to tiff, png, and jpg with the same inverted black/white results. I'm loading the pages into a pdf. The pages are right but just with the black/white reversed.
Just changing the encoding options in the saveas statement doesn't seem to have an effect on what the result looks like. That doesn't convert anything. I'd need to convert the pixels before saving to do that, right?
My wip code is in the next message. Apologies to OP for hijacking the thread but hopefully this is the same issue since the results are identical.
public byte[] PdfFromImage( string fileName, byte[] documentBytes )
{
byte[] byteResult;
using ( var ms = new MemoryStream( documentBytes ) )
{
var document = new Aspose.Pdf.Document();
ms.Position = 0;
IImageFormat format;
var imageHeight = 0;
var imageWidth = 0;
var bytes = ms.ToArray();
using ( SixLabors.ImageSharp.Image bitmap = SixLabors.ImageSharp.Image.Load( ms, out format ) )
{
for ( var i = 0; i < bitmap.Frames.Count; i++ )
{
var frame = bitmap.Frames.CloneFrame( i );
// If bitmapStream is disposed then pdf will not save with "Cannot access a closed Stream."
// If declared separately then every page is the first page
var bitmapStream = new MemoryStream();
frame.SaveAsPng( bitmapStream );
imageHeight = frame.Height;
imageWidth = frame.Width;
var newPage = document.Pages.Add();
Aspose.Pdf.Image img = new Aspose.Pdf.Image();
img.ImageStream = bitmapStream;
img.HorizontalAlignment = HorizontalAlignment.Center;
img.VerticalAlignment = VerticalAlignment.Center;
newPage.Paragraphs.Add( img );
newPage.Background = Aspose.Pdf.Color.White;
newPage.PageInfo.IsLandscape = imageWidth > imageHeight;
newPage.PageInfo.Height = newPage.PageInfo.IsLandscape ? imageWidth : imageHeight;
newPage.PageInfo.Width = newPage.PageInfo.IsLandscape ? imageHeight : imageWidth;
if ( newPage.PageInfo.Height < PORTRAIT_PAGE_HEIGHT )
{
newPage.PageInfo.Height = PORTRAIT_PAGE_HEIGHT;
}
if ( newPage.PageInfo.Width < PORTRAIT_PAGE_WIDTH )
{
newPage.PageInfo.Width = PORTRAIT_PAGE_WIDTH;
}
newPage.PageInfo.Margin.Bottom = 1;
newPage.PageInfo.Margin.Top = 1;
newPage.PageInfo.Margin.Left = 1;
newPage.PageInfo.Margin.Right = 1;
}
using ( var pdfStream = new MemoryStream() )
{
document.Save( pdfStream, SaveFormat.Pdf );
byteResult = pdfStream.ToArray();
}
}
ms.Close();
}
return byteResult;
}
In c#, I tried converting the tiff pages to tiff, png, and jpg with the same inverted black/white results. I'm loading the pages into a pdf. The pages are right but just with the black/white reversed.
That means the decoder could be the problem. Again without a test image, I cannot do much.
My wip code is in the next message. Apologies to OP for hijacking the thread but hopefully this is the same issue since the results are identical.
Most of the code has nothing to do with ImageSharp, try simplify the example.
Well, I guess I could have tried the obvious...
if(format.Name.Equals("TIFF"))
{
frame.Mutate( x => x.Invert() );
}
I'm getting images from a third party repository and in my case they have social security numbers and whatnot in them so creating a test image that matches the original might be tricky. Pretty sure the issue is with the original PhotoMetric setting.
I'll see if I can reproduce with an image I create manually and write a unit test but the above will work for now as long as they are all reversed 2-color images. :|
Standard system.drawing.common code didn't have the reversed appearance issue but only worked in Windows and not at all in the current non-windows environment I deploy to even with the System.Drawing.EnableUnixSupport template option.
Edit: TiffFrameMetadata info = bitmap.Frames.RootFrame.Metadata.GetTiffMetadata();
- info {SixLabors.ImageSharp.Formats.Tiff.TiffFrameMetadata} SixLabors.ImageSharp.Formats.Tiff.TiffFrameMetadata
BitsPerPixel Bit1 SixLabors.ImageSharp.Formats.Tiff.TiffBitsPerPixel?
- BitsPerSample {TiffBitsPerSample(1, 0, 0)} SixLabors.ImageSharp.Formats.Tiff.TiffBitsPerSample?
Channel0 1 ushort
Channel1 0 ushort
Channel2 0 ushort
Channel3 0 ushort
Channels 1 byte
Compression CcittGroup4Fax SixLabors.ImageSharp.Formats.Tiff.Constants.TiffCompression?
PhotometricInterpretation BlackIsZero SixLabors.ImageSharp.Formats.Tiff.Constants.TiffPhotometricInterpretation?
Predictor null SixLabors.ImageSharp.Formats.Tiff.Constants.TiffPredictor?
Closing this now, because without a test image this can not be reproduced. @CREFaulk feel free to open/comment here again, if you manage to get a image with that issue (which can be shared).