123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375 |
- /*
- * The Python Imaging Library.
- * $Id$
- *
- * coder for ZIP (deflated) image data
- *
- * History:
- * 96-12-29 fl created
- * 96-12-30 fl adaptive filter selection, encoder tuning
- *
- * Copyright (c) Fredrik Lundh 1996.
- * Copyright (c) Secret Labs AB 1997.
- *
- * See the README file for information on usage and redistribution.
- */
- #include "Imaging.h"
- #ifdef HAVE_LIBZ
- #include "Zip.h"
- int
- ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
- {
- ZIPSTATE* context = (ZIPSTATE*) state->context;
- int err;
- int compress_level, compress_type;
- UINT8* ptr;
- int i, bpp, s, sum;
- ImagingSectionCookie cookie;
- if (!state->state) {
- /* Initialization */
- /* Valid modes are ZIP_PNG, ZIP_PNG_PALETTE, and ZIP_TIFF */
- /* overflow check for malloc */
- if (state->bytes > INT_MAX - 1) {
- state->errcode = IMAGING_CODEC_MEMORY;
- return -1;
- }
- /* Expand standard buffer to make room for the filter selector,
- and allocate filter buffers */
- free(state->buffer);
- /* malloc check ok, overflow checked above */
- state->buffer = (UINT8*) malloc(state->bytes+1);
- context->previous = (UINT8*) malloc(state->bytes+1);
- context->prior = (UINT8*) malloc(state->bytes+1);
- context->up = (UINT8*) malloc(state->bytes+1);
- context->average = (UINT8*) malloc(state->bytes+1);
- context->paeth = (UINT8*) malloc(state->bytes+1);
- if (!state->buffer || !context->previous || !context->prior ||
- !context->up || !context->average || !context->paeth) {
- free(context->paeth);
- free(context->average);
- free(context->up);
- free(context->prior);
- free(context->previous);
- state->errcode = IMAGING_CODEC_MEMORY;
- return -1;
- }
- /* Initialise filter buffers */
- state->buffer[0] = 0;
- context->prior[0] = 1;
- context->up[0] = 2;
- context->average[0] = 3;
- context->paeth[0] = 4;
- /* Initialise previous buffer to black */
- memset(context->previous, 0, state->bytes+1);
- /* Setup compression context */
- context->z_stream.zalloc = (alloc_func)0;
- context->z_stream.zfree = (free_func)0;
- context->z_stream.opaque = (voidpf)0;
- context->z_stream.next_in = 0;
- context->z_stream.avail_in = 0;
- compress_level = (context->optimize) ? Z_BEST_COMPRESSION
- : context->compress_level;
- if (context->compress_type == -1) {
- compress_type = (context->mode == ZIP_PNG) ? Z_FILTERED
- : Z_DEFAULT_STRATEGY;
- } else {
- compress_type = context->compress_type;
- }
- err = deflateInit2(&context->z_stream,
- /* compression level */
- compress_level,
- /* compression method */
- Z_DEFLATED,
- /* compression memory resources */
- 15, 9,
- /* compression strategy (image data are filtered)*/
- compress_type);
- if (err < 0) {
- state->errcode = IMAGING_CODEC_CONFIG;
- return -1;
- }
- if (context->dictionary && context->dictionary_size > 0) {
- err = deflateSetDictionary(&context->z_stream, (unsigned char *)context->dictionary,
- context->dictionary_size);
- if (err < 0) {
- state->errcode = IMAGING_CODEC_CONFIG;
- return -1;
- }
- }
- /* Ready to decode */
- state->state = 1;
- }
- /* Setup the destination buffer */
- context->z_stream.next_out = buf;
- context->z_stream.avail_out = bytes;
- if (context->z_stream.next_in && context->z_stream.avail_in > 0) {
- /* We have some data from previous round, deflate it first */
- err = deflate(&context->z_stream, Z_NO_FLUSH);
- if (err < 0) {
- /* Something went wrong inside the compression library */
- if (err == Z_DATA_ERROR)
- state->errcode = IMAGING_CODEC_BROKEN;
- else if (err == Z_MEM_ERROR)
- state->errcode = IMAGING_CODEC_MEMORY;
- else
- state->errcode = IMAGING_CODEC_CONFIG;
- free(context->paeth);
- free(context->average);
- free(context->up);
- free(context->prior);
- free(context->previous);
- deflateEnd(&context->z_stream);
- return -1;
- }
- }
- ImagingSectionEnter(&cookie);
- for (;;) {
- switch (state->state) {
- case 1:
- /* Compress image data */
- while (context->z_stream.avail_out > 0) {
- if (state->y >= state->ysize) {
- /* End of image; now flush compressor buffers */
- state->state = 2;
- break;
- }
- /* Stuff image data into the compressor */
- state->shuffle(state->buffer+1,
- (UINT8*) im->image[state->y + state->yoff] +
- state->xoff * im->pixelsize,
- state->xsize);
- state->y++;
- context->output = state->buffer;
- if (context->mode == ZIP_PNG) {
- /* Filter the image data. For each line, select
- the filter that gives the least total distance
- from zero for the filtered data (taken from
- LIBPNG) */
- bpp = (state->bits + 7) / 8;
- /* 0. No filter */
- for (i = 1, sum = 0; i <= state->bytes; i++) {
- UINT8 v = state->buffer[i];
- sum += (v < 128) ? v : 256 - v;
- }
- /* 2. Up. We'll test this first to save time when
- an image line is identical to the one above. */
- if (sum > 0) {
- for (i = 1, s = 0; i <= state->bytes; i++) {
- UINT8 v = state->buffer[i] - context->previous[i];
- context->up[i] = v;
- s += (v < 128) ? v : 256 - v;
- }
- if (s < sum) {
- context->output = context->up;
- sum = s; /* 0 if line was duplicated */
- }
- }
- /* 1. Prior */
- if (sum > 0) {
- for (i = 1, s = 0; i <= bpp; i++) {
- UINT8 v = state->buffer[i];
- context->prior[i] = v;
- s += (v < 128) ? v : 256 - v;
- }
- for (; i <= state->bytes; i++) {
- UINT8 v = state->buffer[i] - state->buffer[i-bpp];
- context->prior[i] = v;
- s += (v < 128) ? v : 256 - v;
- }
- if (s < sum) {
- context->output = context->prior;
- sum = s; /* 0 if line is solid */
- }
- }
- /* 3. Average (not very common in real-life images,
- so its only used with the optimize option) */
- if (context->optimize && sum > 0) {
- for (i = 1, s = 0; i <= bpp; i++) {
- UINT8 v = state->buffer[i] - context->previous[i]/2;
- context->average[i] = v;
- s += (v < 128) ? v : 256 - v;
- }
- for (; i <= state->bytes; i++) {
- UINT8 v = state->buffer[i] -
- (state->buffer[i-bpp] + context->previous[i])/2;
- context->average[i] = v;
- s += (v < 128) ? v : 256 - v;
- }
- if (s < sum) {
- context->output = context->average;
- sum = s;
- }
- }
- /* 4. Paeth */
- if (sum > 0) {
- for (i = 1, s = 0; i <= bpp; i++) {
- UINT8 v = state->buffer[i] - context->previous[i];
- context->paeth[i] = v;
- s += (v < 128) ? v : 256 - v;
- }
- for (; i <= state->bytes; i++) {
- UINT8 v;
- int a, b, c;
- int pa, pb, pc;
- /* fetch pixels */
- a = state->buffer[i-bpp];
- b = context->previous[i];
- c = context->previous[i-bpp];
- /* distances to surrounding pixels */
- pa = abs(b - c);
- pb = abs(a - c);
- pc = abs(a + b - 2*c);
- /* pick predictor with the shortest distance */
- v = state->buffer[i] -
- ((pa <= pb && pa <= pc) ? a :
- (pb <= pc) ? b : c);
- context->paeth[i] = v;
- s += (v < 128) ? v : 256 - v;
- }
- if (s < sum) {
- context->output = context->paeth;
- sum = s;
- }
- }
- }
- /* Compress this line */
- context->z_stream.next_in = context->output;
- context->z_stream.avail_in = state->bytes+1;
- err = deflate(&context->z_stream, Z_NO_FLUSH);
- if (err < 0) {
- /* Something went wrong inside the compression library */
- if (err == Z_DATA_ERROR)
- state->errcode = IMAGING_CODEC_BROKEN;
- else if (err == Z_MEM_ERROR)
- state->errcode = IMAGING_CODEC_MEMORY;
- else
- state->errcode = IMAGING_CODEC_CONFIG;
- free(context->paeth);
- free(context->average);
- free(context->up);
- free(context->prior);
- free(context->previous);
- deflateEnd(&context->z_stream);
- ImagingSectionLeave(&cookie);
- return -1;
- }
- /* Swap buffer pointers */
- ptr = state->buffer;
- state->buffer = context->previous;
- context->previous = ptr;
- }
- if (context->z_stream.avail_out == 0)
- break; /* Buffer full */
- case 2:
- /* End of image data; flush compressor buffers */
- while (context->z_stream.avail_out > 0) {
- err = deflate(&context->z_stream, Z_FINISH);
- if (err == Z_STREAM_END) {
- free(context->paeth);
- free(context->average);
- free(context->up);
- free(context->prior);
- free(context->previous);
- deflateEnd(&context->z_stream);
- state->errcode = IMAGING_CODEC_END;
- break;
- }
- if (context->z_stream.avail_out == 0)
- break; /* Buffer full */
- }
- }
- ImagingSectionLeave(&cookie);
- return bytes - context->z_stream.avail_out;
- }
- /* Should never ever arrive here... */
- state->errcode = IMAGING_CODEC_CONFIG;
- ImagingSectionLeave(&cookie);
- return -1;
- }
- /* -------------------------------------------------------------------- */
- /* Cleanup */
- /* -------------------------------------------------------------------- */
- int
- ImagingZipEncodeCleanup(ImagingCodecState state) {
- ZIPSTATE* context = (ZIPSTATE*) state->context;
- if (context->dictionary) {
- free (context->dictionary);
- context->dictionary = NULL;
- }
- return -1;
- }
- const char*
- ImagingZipVersion(void)
- {
- return ZLIB_VERSION;
- }
- #endif
|