Page 1 of 1

Accessing raw image data

Posted: 2017-12-08T10:55:17-07:00
by superstator
I am porting an old imaging tool to .NET Core, and need to load image data for editing, and then save it back out. In the past we used the old GDI Bitmap class to lock the image bytes to an IntPtr - is there something similar in Magick.NET? I am able to load an image file using MagickImage() easily enough, and I see all the metadata and format properties I could ever want, but I didn't see anything obvious that would get me raw decompressed pixels.

Thanks!

Re: Accessing raw image data

Posted: 2017-12-08T12:05:59-07:00
by snibgo
What do you mean by "raw decompressed pixels"? If you mean pixel data as it appears in the file, no IM doesn't give you that. It always converts the file data into its own format, which depends on the Q-number and whether HDRI is used.

Re: Accessing raw image data

Posted: 2017-12-08T12:49:19-07:00
by superstator
I mean an array with one byte per channel per pixel for 8-bit color. I don't believe we have any need for 16-bit color support, so I don't think the Q16 builds will matter for us. As per usual, as soon as I posted the question I started getting some traction. After poking around some more, I think I have the basics working (at least for reading) just like this:

Code: Select all

var pixels = image.GetPixels();
var bytes = pixels.ToByteArray("RGB");
var pinnedArray = GCHandle.Alloc(bytes, GCHandleType.Pinned);
var ptr = pinnedArray.AddrOfPinnedObject();
I think the only question from here is if it will work as easily with other color systems like CMYK and LAB.

Re: Accessing raw image data

Posted: 2017-12-09T05:49:42-07:00
by dlemstra
If you need the pixels in a specific order then this is indeed the way to do it. And don't forget to dispose the `pixels` (IPixelCollection is IDisposable). When you also need to set the pixels it might be better to just call `.ToArray()` instead. This will return a byte array (for Q8) and you will get the channels of the pixel in the current order. With image.Channels you can get the channels of the image (maybe I should also add this to `IPixelCollection`) and then use pixels.GetIndex to get the index of the channel. Be aware that you are always working on a copy of the pixels so you will need to call `pixels.SetPixels` to change the pixels.

Re: Accessing raw image data

Posted: 2017-12-11T11:20:07-07:00
by superstator
So, the call to SetPixels() needs to have the bytes in the original channel order? That should be doable, if I can get the order reliably. Looking at the .Channels collection, it seems a little funky. For a grayscale image, it reports a single Cyan channel. For an sRGB it reports Cyan, Green, and Blue. For CMYK it reports Cyan, Green, Blue, Black. Is there another place to look?

Re: Accessing raw image data

Posted: 2017-12-11T12:32:39-07:00
by dlemstra
This is happening because of the following values in the Channels enumeration:

Code: Select all

        Red = 0x0001,

        Gray = 0x0001,

        Cyan = 0x0001,


As you can see they all have the same value and Visual Studio decides to use the last value to when it is printed.

Re: Accessing raw image data

Posted: 2017-12-11T13:35:01-07:00
by superstator
Gotcha. So, can I assume then that the underlying byte order will always be fixed for a given ColorSpace? IE, it will always be RGB or RGBA, and never BGR or ARGB, etc? Or is there another lookup to map a Channel index to a position in the byte order?

Re: Accessing raw image data

Posted: 2017-12-11T14:29:51-07:00
by dlemstra
You can use `pixels.GetIndex` to get the index of a specif channel. The order could be different.

Re: Accessing raw image data

Posted: 2017-12-11T15:49:32-07:00
by superstator
How about LAB? PixelChannel doesn't seem to cover LAB/YCbCr/etc, but my LAB samples seem to reliably load into channels 0-2 anyway.

Re: Accessing raw image data

Posted: 2017-12-11T16:01:45-07:00
by fmw42
All colorspace use the same notation for the first few channels 0 for red, cyan, gray, intensity, luminance, etc. whether RGB, CMYK, YCbCr or LAB. You have to keep track of which colorspace you are working in.

Re: Accessing raw image data

Posted: 2017-12-11T16:33:47-07:00
by superstator
Sure, that's what I'd expect, and I can understand why dlemstra might not want to pack the PixelChannel enum with every possible permutation for every colorspace. I just want to make sure I'm making reasonable assumptions before I hardcode them in.

Re: Accessing raw image data

Posted: 2017-12-11T16:42:36-07:00
by fmw42
I do not use Magick.Net, so I will leave confirmation to him. But that is the way it is in the command line version of ImageMagick.

Re: Accessing raw image data

Posted: 2017-12-12T13:59:07-07:00
by superstator
Another puzzle: For a grayscale JPEG, Magick.NET is reporting a ColorSpace of Gray, and the Channels collection on MagickImage has only a single value (Channel 0), as expected. However, ChannelCount == 2, and if I take GetPixels().ToArray() I get 2 channels worth of image data, with two identical bytes for each pixel value. If I use GetPixels().ToByteArray("I") I get a single intensity value as expected, but that leaves me with an alignment problem when I call SetPixels(). I know earlier versions of IM treated Grayscale as three equal channels, but I was under the impression newer versions used a single channel. Any idea where the extra channel is coming from?

Re: Accessing raw image data

Posted: 2017-12-12T15:40:24-07:00
by dlemstra
The other channel is prob an index channel if you don't get it in the channels property. You could check that with a call to GetIndex.