Page 1 of 1

How does one discard an image's palette using MagickCore?

Posted: 2016-11-28T23:58:00-07:00
by grendell
This is my first night diving into MagickCore in hopes of speeding up some image processing I have been doing via the CLI. I've run into an issue when I try to manipulate the pixels of a paletted/indexed png and then write that image back out to file.

Test image creation:

Code: Select all

convert -resize 256x256 xc:blue png24:1.png
convert -resize 256x256 xc:blue 2.png
This forces 1.png to be full RGB888 while 2.png becomes a paletted png.

Simple negate program to familiarize myself with MagickCore:

Code: Select all

#include <stdio.h>
#include <string.h>
#include <magick/MagickCore.h>

int main(int argc, char ** argv) {
    if (argc != 3) {
        fprintf(stderr, "usage: %s <input> <output>\n", argv[0]);
        return 1;
    }

    MagickCoreGenesis(*argv, MagickTrue);
    ExceptionInfo * exception = AcquireExceptionInfo();

    ImageInfo * info = CloneImageInfo(NULL);
    strncpy(info->filename, argv[1], MaxTextExtent);

    Image * image = ReadImage(info, exception);
    if (exception->severity != UndefinedException) {
        CatchException(exception);
    }

    if (image == NULL) {
        fprintf(stderr, "unable to read %s\n", argv[1]);
        return 2;
    }

    PixelPacket * packets = GetAuthenticPixels(image, 0, 0, image->columns, image->rows, exception);
    if (exception->severity != UndefinedException) {
        CatchException(exception);
    }

    for (size_t r = 0; r < image->rows; ++r) {
        for (size_t c = 0; c < image->columns; ++c) {
            int offset = image->columns * r + c;

            packets[offset].red = QuantumRange - packets[offset].red;
            packets[offset].green = QuantumRange - packets[offset].green;
            packets[offset].blue = QuantumRange - packets[offset].blue;
        }
    }

    SyncAuthenticPixels(image, exception);
    if (exception->severity != UndefinedException) {
        CatchException(exception);
    }

    strncpy(image->filename, argv[2], MaxTextExtent);
    if(!WriteImage(info, image)) {
        fprintf(stderr, "unable to write %s\n", argv[2]);
        return 3;
    }

    image = DestroyImage(image);
    info = DestroyImageInfo(info);
    exception = DestroyExceptionInfo(exception);
    MagickCoreTerminus();

    return 0;
}
The output of this code when given 1.png is a paletted, yellow square as a png. Perfect!
The output of this code when given 2.png is a paletted, blue square as a png. Argh!

My assumption is that the blue is still present in the palette, and that's why the output is blue, but I cannot figure out how to discard the palette. I have tried manually setting colors = 0 and colormap = NULL. Neither of these worked, and quite honestly I'm sure there's a better way anyway.

Alternatively, I would be open to creating a new Image for the modified pixels, but I don't know the best way to adapt this code to use ConstituteImage (or something similar). When I tried, I don't think I had the storage parameter correctly set, so my code was aborting.

Any advice would be most appreciated! Thanks in advance!

ImageMagick version info:

Code: Select all

Version: ImageMagick 6.9.6-6 Q16 x86_64 2016-11-28 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2016 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Features: Cipher DPC Modules 
Delegates (built-in): bzlib freetype jng jpeg ltdl lzma png tiff xml zlib
Operating System:

Code: Select all

OSX 10.9.5

Re: How does one discard an image's palette using MagickCore?

Posted: 2016-11-29T09:22:13-07:00
by snibgo
For de-paletting in MagickCore, I use SetImageStorageClass().

If you are interested in examples of MagickCore usage, see my "Process modules" page.

Re: How does one discard an image's palette using MagickCore?

Posted: 2016-11-30T17:28:46-07:00
by grendell
That's exactly what I needed to do. Thanks!