Re: MagickSetImageType and gm convert: inconsistent behaviour

Bob Friesenhahn <[email protected]> Wed, 22 Sep 2010 22:29:57 -0500 (CDT)
Newsgroups gmane.comp.video.graphicsmagick.bugs
Message-ID <[email protected]>
On Thu, 23 Sep 2010, Graham Leggett wrote:
>
> Is a grayscale image supposed to be in the RGB colourspace, and am I
> misunderstanding this?

Grayscale is a form of RGB colorspace (at least as far as 
GraphicsMagick is currently concerned).

> It turns out the reason the gm tool's "convert" function "works" is
> because the convert function cheats and hardcodes the ImageType direct
> into a private structure within the image:
>
>         if (LocaleCompare("type",option+1) == 0)
>           {
>             resource_info.image_info->type=UndefinedType;
>             if (*option == '-')
>               {
>                 i++;
>                 if (i == argc)
>
> MagickFatalError(OptionFatalError,MissingArgument,option);
>                 option=argv[i];
>                 resource_info.image_info-
> >type=StringToImageType(option);
>                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>                 if (resource_info.image_info->type == UndefinedType)
>
> MagickFatalError(OptionFatalError,UnrecognizedImageType,
>                                    option);
>               }
>             break;
>           }
>         MagickFatalError(OptionFatalError,UnrecognizedOption,option);
>
> I am now confused - which behaviour is correct, the SetImageType()
> function that does all the colourspace conversion, or the "convert"
> function that hardcodes the ImageType value into the private structure
> directly?

It is easy to see why the behavior is confusing. 
MagickSetImageType() only operates on the image (Image struct).  The 
command line tool is also setting 'type' in ImageInfo, which is used 
when a file is saved.  MagickSetImageType() is not doing that. 
Perpaps this should be added to MagickSetImageType():

   wand->image_info->type=image_type;

So that the function looks like:

WandExport unsigned int MagickSetImageType(MagickWand *wand,
   const ImageType image_type)
{
   assert(wand != (MagickWand *) NULL);
   assert(wand->signature == MagickSignature);
   if (wand->images == (Image *) NULL)
     ThrowWandException(WandError,WandContainsNoImages,wand->id);
   wand->image_info->type=image_type;
   return(SetImageType(wand->image,image_type));
}

The drawback of this is that the Image type operates immediately on 
the pixels (if required) so that it is an image processing operation 
whereas the type stored in ImageInfo is only used when saving the 
image.  These are two somewhat different functions which may or may 
not always end up with the same result.  For example, there could be a 
request to convert the image to a gray image, and then something with 
the color red is composited on top of it.  The image is then a RGB 
image but would still be saved as gray (if possible) due to also 
setting ImageInfo to the desired type.  The user would need to 
remember to set the image back to an RGB color type.

> Why would the SetImageType() function think that a grayscale image is
> already in the RGB colourspace (unless it I am misunderstanding it)?

I think that part of the logic is ok.  What is missing is to assign 
the desired 'type' in ImageInfo so that it is also applied when the 
image is saved.  This is an easy fix, but I am not 100% sure it is the 
right solution.

Bob
-- 
Bob Friesenhahn
[email protected], http://www.simplesystems.org/users/bfriesen/
GraphicsMagick Maintainer,    http://www.GraphicsMagick.org/

------------------------------------------------------------------------------
Start uncovering the many advantages of virtual appliances
and start using them to simplify application deployment and
accelerate your shift to cloud computing.
http://p.sf.net/sfu/novell-sfdev2dev