PNG convert (magick core c api)

riccy
2013-02-05
2013-03-27
  • riccy
    riccy
    2013-02-05

    hi all,
    I am using gm magick core c api for PNG converting in nginx module.
    The pseudo code as following:
    1. get post body from http request;
    2. call BlobToImage() to convert the posted data to a image for image handling such as resize/crop etc.;
    3. call ImageToBlob() to format the handled image to blob and return to caller.
    As for common image types other than PNG, this works fine.
    When I want to convert a PNG file to the smallest filesize, i can not find the right way to set the effective params for ImageToBlob() , it tskes no effect!
    But i find using cmd line works! like that: gm convert input.png -resize120x120 -depth 8 -colors 256 -quality 75 output.png.
    With cmd line, parameter depth/colors/quality can works well.
    depth can be set 1/2/4/8/16/24/32.
    colors can be set 256.
    As I try many ways to set those params in ImageToBlob(ImageInfo, Image), like depth in ImageInfo, depth/colors in Image, all are useless, filesize is not decreased much.
    especially, depth set lower than 8 will be reset to 8 when call ImageToBlob.

    I have read source code of GM 1.3.17, hope to take advantage of  gm's implementation, but failed

    Anyone can help? thanks a lot.

     
  • Your command line is requesting several image processing operations (e.g. resize).  Between reading and writing the image, you would need to apply several image processing operations using the C API.  Most of the code which does this for the command line is in MogrifyImage() in magick/command.c.

    The PNG format itself does not support less "depth" than 8.

    Bob

     
  • The PNG format supports depths less than 8 for grayscale and indexed images, but I'm not sure that the GM png encoder does..  By the way, -quality 70 will probably give you better compression than 75 for less-than-257-color images.  If you are really concerned about PNG filesize, I recommend postprocessing them with pngcrush after you've written them with GM.

     
  • riccy
    riccy
    2013-02-05

    thanks to bfriesenand glennrp. I had read gm/coders/png.c, and found depth for png will be set to 8 if given less than 8. But how does gm make it with option -depth and -colors?
    During ResizeImage(), it does not require any depth and colors paramters.
    As for this:gm convert input.png -depth 8 -colors 256 -quality 75 output.png.
    this cmd also takes effect and decrease filesize much.
    So i am curious to find out how do GM to apply these options(depth and colors), as both of you say that PNG format does not support depth less than 8.

    looking forwards to your reply.

    riccy

     
  • riccy
    riccy
    2013-02-06

    Update:
    I use SetImageDepth() to decrease the depth of image, this works!
    Setting the depth from 8 to 4 reduceshalf of total filesize.

    Another api SetImageColor() should also take the same effect, i will try later.
    thanks all.

     
  • Be careful about using SetImageDepth().  This function actually modifies the image pixels so that each quantum (color-component value) is cleanly representable in the specified number of bits.  It does this by integer dividing and then multiplying.  This will definitely make the output file smaller but also causes a loss of color quality since each color quantum can have no more than 16 values rather than 256.  Using the image->depth=8 approach won't result in worse color quality.

     
  • riccy
    riccy
    2013-02-06

    hi bfriesen,
    I read code of MogrifyImage() and try to use QuantizeImage() with the given QuantizeInfo structure, this also works.
    No much difference between setting depth to 4 and setting colors to 256.
    The following is my code refer to the code of MogrifyImage() in magick/command.c:
    #define IMAGE_DEFAULT_DEPTH 24
    #define IMAGE_DEFAULT_COLORS  65535

        if (IMAGE_DEFAULT_DEPTH != param.depth) {
            SetImageDepth(imgs.processed_image, param.depth);
        }
        if (IMAGE_DEFAULT_COLORS != param.colors) {
            QuantizeInfo quantize_info;
            GetQuantizeInfo(&quantize_info);
            quantize_info.number_colors = param.colors;
            quantize_info.tree_depth = 0;
            quantize_info.dither = MagickTrue;
            if (IsGrayColorspace(quantize_info.colorspace)) {
                if (quantize_info.number_colors != 0)
                    (void) QuantizeImage(&quantize_info, imgs.processed_image);
                else
                    (void) TransformColorspace(imgs.processed_image, quantize_info.colorspace);
            } else {
                if (quantize_info.number_colors != 0) {
                    if ((imgs.processed_image->storage_class == DirectClass) ||
                          (imgs.processed_image->colors > quantize_info.number_colors)) {
                        (void) QuantizeImage(&quantize_info, imgs.processed_image);
                    } else {
                        CompressImageColormap(imgs.processed_image);
                    }   
                }   
            }   
        }   
    This code is supposed to take effect when given depth or colors parameters.

    thanks a lot.

    riccy

     
  • I see that you have IMAGE_DEFAULT_DEPTH set to 24.  Note that for an RGB image, image->depth would be 8 in that case.