/* Copyright (c) 2010 Oliver Tonnhofer , Omniscale // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. */ /* // This file implements a quantization using libimagequant, a part of pngquant. */ #include #include #include #include "QuantPngQuant.h" #ifdef HAVE_LIBIMAGEQUANT #include "libimagequant.h" int quantize_pngquant( Pixel *pixelData, uint32_t width, uint32_t height, uint32_t quantPixels, Pixel **palette, uint32_t *paletteLength, uint32_t **quantizedPixels, int withAlpha) { int result = 0; liq_image *image = NULL; liq_attr *attr = NULL; liq_result *remap = NULL; char *charMatrix = NULL; char **charMatrixRows = NULL; *palette = NULL; *paletteLength = 0; *quantizedPixels = NULL; /* configure pngquant */ attr = liq_attr_create(); if (!attr) { goto err; } if (quantPixels) { liq_set_max_colors(attr, quantPixels); } /* prepare input image */ image = liq_image_create_rgba( attr, pixelData, width, height, 0.45455 /* gamma */); if (!image) { goto err; } /* quantize the image */ remap = liq_quantize_image(attr, image); if (!remap) { goto err; } liq_set_output_gamma(remap, 0.45455); liq_set_dithering_level(remap, 1); /* write output palette */ const liq_palette *l_palette = liq_get_palette(remap); *paletteLength = l_palette->count; *palette = malloc(sizeof(Pixel) * l_palette->count); if (!*palette) { goto err; } for (unsigned int i = 0; i < l_palette->count; i++) { (*palette)[i].c.b = l_palette->entries[i].b; (*palette)[i].c.g = l_palette->entries[i].g; (*palette)[i].c.r = l_palette->entries[i].r; (*palette)[i].c.a = l_palette->entries[i].a; } /* write output pixels (pngquant uses char array) */ charMatrix = malloc(width * height); if (!charMatrix) { goto err; } charMatrixRows = malloc(height * sizeof(char*)); if (!charMatrixRows) { goto err; } for (unsigned int y = 0; y < height; y++) { charMatrixRows[y] = &charMatrix[y * width]; } if (LIQ_OK != liq_write_remapped_image_rows(remap, image, charMatrixRows)) { goto err; } /* transcribe output pixels (pillow uses uint32_t array) */ *quantizedPixels = malloc(sizeof(uint32_t) * width * height); if (!*quantizedPixels) { goto err; } for (int i = 0; i < width * height; i++) { (*quantizedPixels)[i] = charMatrix[i]; } result = 1; err: if (attr) liq_attr_destroy(attr); if (image) liq_image_destroy(image); if (remap) liq_result_destroy(remap); free(charMatrix); free(charMatrixRows); if (!result) { free(*quantizedPixels); free(*palette); } return result; } #else /* Offer dummy implementation */ int quantize_pngquant( Pixel *pixelData, uint32_t width, uint32_t height, uint32_t quantPixels, Pixel **palette, uint32_t *paletteLength, uint32_t **quantizedPixels, int withAlpha) { return 0; } #endif