Re: Grayscale Image Objects
Bob Friesenhahn <[email protected]> Sun, 4 Jan 2009 17:35:11 -0600 (CST)
| Newsgroups | gmane.comp.video.graphicsmagick.apis |
|---|---|
| Message-ID | <[email protected]> |
On Wed, 31 Dec 2008, [email protected] wrote: > I am using GM 1.2.6 on Windows through the Magic++ API. In several > instances I have to construct an Image object from my own internal > buffers. I setup the type, colorspace, etc. without issue and populate > the pixel (and possibly colormap) data. The problem comes down to the > internal flags for the image type. Specifically when I create a grayscale > image the "is_grayscale" member never gets set to True which causes > problems for some of the imaging functions and encoders. Since > is_grayscale is not true for instance the JPEG encoder writes out a three > channel JPEG file instead of a single channel file. This is much more > computationally and file size expensive than it should be. Not good. The is_grayscale and is_monochrome private members provide hints to help the software go faster. Internally, the image is always stored as RGBA. The problem is that if gray pixels are stored as RGBA, then all of the pixels need to be inspected to see if they are gray when the file is about to be written. The optimization works by automatically clearing these flags whenever a pixel is updated. The algorithm doing the updates then decides if the pixels should still be gray (or are gray) and then resets the flags appropriately. If the algorithm does not maintain this information, then the image is treated as RGB until proven otherwise. A workaround to automatically produce a more compact image is to use the image type method to set the image type to OptimizeType: image.type(OptimizeType); and this forces the pixels to be inspected (as required) when the image is saved. The annoyance is that if the image is gray, then all of the pixels need to be checked in order to prove it. > There appears to be a method internally (IsGrayImage) that is called some > a few functions that sets the is_grayscale member properly however I have > not found any way to have this function execute via the Magic++ interface. > I believe that the is_monochrome member suffers from the same problem. All of the C functions are in the MagickLib namespace. This means that you can execute IsGrayImage() using an incantation like this: image.modifyImage(); MagickLib::IsGrayImage(image.image()); You are also able to access raw structure members using this image accessor to the underlying Image structure. Of course bypassing Magick++ could cause your code to not work with a newer version in the future. > While I am here I might also ask if there is a recommended combination > (most efficient) form of grayscale storage for GM? I ask since they can > be DirectColor or PseudoColor, and even GrayscaleType and RGBColorspace. There are two storage models, and they can exist simultaneously. One is the DirectClass model where the pixels are like an array of RGBA pixel structures (of type PixelPacket). The other is a PsuedoClass model, where the pixels are like an array of colormap indexes (of type IndexPacket). If the image storage class is set to PseudoClass, then indexes exist, and they refer to a colormap. If the image storage class is set to DirectClass, then only the RGBA pixels are valid. Even if the image is set to PseudoClass, each algorithm assures that the DirectClass representation is also up to date before it returns. It is ok for the representations to diverge for a while but they should be brought up to date before being passed to the next algorithm, or saved. It often helps to load grayscale images as PsuedoClass using a linear ramped grayscale colormap (which AllocateImageColormap() produces by default). In fact (with only a few exceptions) this is how grayscale images are read into GraphicsMagick. It can be very time consumptive to produce a new colormap given direct pixels so it helps a lot to start with a colormap. The only exception that I am aware of at the moment is for the TIFF format which supports both native bilevel/grayscale and colormapped in the format, and so it is useful to remember the original representation. Most TIFF users are not happy if they started with a true gray representation and they ended up with a colormapped representation. The PsuedoClass representation is actually even less memory efficient than the DirectClass representation since the DirectClass representation always exists. From a performance standpoint, DirectClass will be faster unless a colormap is needed, and even then there is a fast transformation of a gray image to colormapped. Bob ====================================== Bob Friesenhahn [email protected], http://www.simplesystems.org/users/bfriesen/ GraphicsMagick Maintainer, http://www.GraphicsMagick.org/ ------------------------------------------------------------------------------