Accessing raw image data

Magick.NET is an object-oriented C# interface to ImageMagick. Use this forum to discuss, make suggestions about, or report bugs concerning Magick.NET
Post Reply
superstator
Posts: 16
Joined: 2017-12-08T10:44:16-07:00
Authentication code: 1152

Accessing raw image data

Post by superstator » 2017-12-08T10:55:17-07:00

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!

snibgo
Posts: 10514
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Accessing raw image data

Post by snibgo » 2017-12-08T12:05:59-07:00

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.
snibgo's IM pages: im.snibgo.com

superstator
Posts: 16
Joined: 2017-12-08T10:44:16-07:00
Authentication code: 1152

Re: Accessing raw image data

Post by superstator » 2017-12-08T12:49:19-07:00

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.

User avatar
dlemstra
Posts: 1476
Joined: 2013-05-04T15:28:54-07:00
Authentication code: 6789
Contact:

Re: Accessing raw image data

Post by dlemstra » 2017-12-09T05:49:42-07:00

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.
.NET + ImageMagick = Magick.NET https://github.com/dlemstra/Magick.NET, @MagickNET, Donate

superstator
Posts: 16
Joined: 2017-12-08T10:44:16-07:00
Authentication code: 1152

Re: Accessing raw image data

Post by superstator » 2017-12-11T11:20:07-07:00

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?

User avatar
dlemstra
Posts: 1476
Joined: 2013-05-04T15:28:54-07:00
Authentication code: 6789
Contact:

Re: Accessing raw image data

Post by dlemstra » 2017-12-11T12:32:39-07:00

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.
.NET + ImageMagick = Magick.NET https://github.com/dlemstra/Magick.NET, @MagickNET, Donate

superstator
Posts: 16
Joined: 2017-12-08T10:44:16-07:00
Authentication code: 1152

Re: Accessing raw image data

Post by superstator » 2017-12-11T13:35:01-07:00

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?

User avatar
dlemstra
Posts: 1476
Joined: 2013-05-04T15:28:54-07:00
Authentication code: 6789
Contact:

Re: Accessing raw image data

Post by dlemstra » 2017-12-11T14:29:51-07:00

You can use `pixels.GetIndex` to get the index of a specif channel. The order could be different.
.NET + ImageMagick = Magick.NET https://github.com/dlemstra/Magick.NET, @MagickNET, Donate

superstator
Posts: 16
Joined: 2017-12-08T10:44:16-07:00
Authentication code: 1152

Re: Accessing raw image data

Post by superstator » 2017-12-11T15:49:32-07:00

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.

User avatar
fmw42
Posts: 23627
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Accessing raw image data

Post by fmw42 » 2017-12-11T16:01:45-07:00

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.

superstator
Posts: 16
Joined: 2017-12-08T10:44:16-07:00
Authentication code: 1152

Re: Accessing raw image data

Post by superstator » 2017-12-11T16:33:47-07:00

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.

User avatar
fmw42
Posts: 23627
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Accessing raw image data

Post by fmw42 » 2017-12-11T16:42:36-07:00

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.

superstator
Posts: 16
Joined: 2017-12-08T10:44:16-07:00
Authentication code: 1152

Re: Accessing raw image data

Post by superstator » 2017-12-12T13:59:07-07:00

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?

User avatar
dlemstra
Posts: 1476
Joined: 2013-05-04T15:28:54-07:00
Authentication code: 6789
Contact:

Re: Accessing raw image data

Post by dlemstra » 2017-12-12T15:40:24-07:00

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.
.NET + ImageMagick = Magick.NET https://github.com/dlemstra/Magick.NET, @MagickNET, Donate

Post Reply