Pillow
370 строк · 13.3 Кб
1/*
2* The Python Imaging Library.
3* $Id$
4*
5* coder for ZIP (deflated) image data
6*
7* History:
8* 96-12-29 fl created
9* 96-12-30 fl adaptive filter selection, encoder tuning
10*
11* Copyright (c) Fredrik Lundh 1996.
12* Copyright (c) Secret Labs AB 1997.
13*
14* See the README file for information on usage and redistribution.
15*/
16
17#include "Imaging.h"18
19#ifdef HAVE_LIBZ20
21#include "ZipCodecs.h"22
23int
24ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {25ZIPSTATE *context = (ZIPSTATE *)state->context;26int err;27int compress_level, compress_type;28UINT8 *ptr;29int i, bpp, s, sum;30ImagingSectionCookie cookie;31
32if (!state->state) {33/* Initialization */34
35/* Valid modes are ZIP_PNG, ZIP_PNG_PALETTE, and ZIP_TIFF */36
37/* overflow check for malloc */38if (state->bytes > INT_MAX - 1) {39state->errcode = IMAGING_CODEC_MEMORY;40return -1;41}42
43/* Expand standard buffer to make room for the filter selector,44and allocate filter buffers */
45free(state->buffer);46/* malloc check ok, overflow checked above */47state->buffer = (UINT8 *)malloc(state->bytes + 1);48context->previous = (UINT8 *)malloc(state->bytes + 1);49context->prior = (UINT8 *)malloc(state->bytes + 1);50context->up = (UINT8 *)malloc(state->bytes + 1);51context->average = (UINT8 *)malloc(state->bytes + 1);52context->paeth = (UINT8 *)malloc(state->bytes + 1);53if (!state->buffer || !context->previous || !context->prior || !context->up ||54!context->average || !context->paeth) {55free(context->paeth);56free(context->average);57free(context->up);58free(context->prior);59free(context->previous);60state->errcode = IMAGING_CODEC_MEMORY;61return -1;62}63
64/* Initialise filter buffers */65state->buffer[0] = 0;66context->prior[0] = 1;67context->up[0] = 2;68context->average[0] = 3;69context->paeth[0] = 4;70
71/* Initialise previous buffer to black */72memset(context->previous, 0, state->bytes + 1);73
74/* Setup compression context */75context->z_stream.zalloc = (alloc_func)0;76context->z_stream.zfree = (free_func)0;77context->z_stream.opaque = (voidpf)0;78context->z_stream.next_in = 0;79context->z_stream.avail_in = 0;80
81compress_level =82(context->optimize) ? Z_BEST_COMPRESSION : context->compress_level;83
84if (context->compress_type == -1) {85compress_type =86(context->mode == ZIP_PNG) ? Z_FILTERED : Z_DEFAULT_STRATEGY;87} else {88compress_type = context->compress_type;89}90
91err = deflateInit2(92&context->z_stream,93/* compression level */94compress_level,95/* compression method */96Z_DEFLATED,97/* compression memory resources */9815,999,100/* compression strategy (image data are filtered)*/101compress_type
102);103if (err < 0) {104state->errcode = IMAGING_CODEC_CONFIG;105return -1;106}107
108if (context->dictionary && context->dictionary_size > 0) {109err = deflateSetDictionary(110&context->z_stream,111(unsigned char *)context->dictionary,112context->dictionary_size113);114if (err < 0) {115state->errcode = IMAGING_CODEC_CONFIG;116return -1;117}118}119
120/* Ready to decode */121state->state = 1;122}123
124/* Setup the destination buffer */125context->z_stream.next_out = buf;126context->z_stream.avail_out = bytes;127if (context->z_stream.next_in && context->z_stream.avail_in > 0) {128/* We have some data from previous round, deflate it first */129err = deflate(&context->z_stream, Z_NO_FLUSH);130
131if (err < 0) {132/* Something went wrong inside the compression library */133if (err == Z_DATA_ERROR) {134state->errcode = IMAGING_CODEC_BROKEN;135} else if (err == Z_MEM_ERROR) {136state->errcode = IMAGING_CODEC_MEMORY;137} else {138state->errcode = IMAGING_CODEC_CONFIG;139}140free(context->paeth);141free(context->average);142free(context->up);143free(context->prior);144free(context->previous);145deflateEnd(&context->z_stream);146return -1;147}148}149
150ImagingSectionEnter(&cookie);151for (;;) {152switch (state->state) {153case 1:154
155/* Compress image data */156while (context->z_stream.avail_out > 0) {157if (state->y >= state->ysize) {158/* End of image; now flush compressor buffers */159state->state = 2;160break;161}162
163/* Stuff image data into the compressor */164state->shuffle(165state->buffer + 1,166(UINT8 *)im->image[state->y + state->yoff] +167state->xoff * im->pixelsize,168state->xsize169);170
171state->y++;172
173context->output = state->buffer;174
175if (context->mode == ZIP_PNG) {176/* Filter the image data. For each line, select177the filter that gives the least total distance
178from zero for the filtered data (taken from
179LIBPNG) */
180
181bpp = (state->bits + 7) / 8;182
183/* 0. No filter */184for (i = 1, sum = 0; i <= state->bytes; i++) {185UINT8 v = state->buffer[i];186sum += (v < 128) ? v : 256 - v;187}188
189/* 2. Up. We'll test this first to save time when190an image line is identical to the one above. */
191if (sum > 0) {192for (i = 1, s = 0; i <= state->bytes; i++) {193UINT8 v = state->buffer[i] - context->previous[i];194context->up[i] = v;195s += (v < 128) ? v : 256 - v;196}197if (s < sum) {198context->output = context->up;199sum = s; /* 0 if line was duplicated */200}201}202
203/* 1. Prior */204if (sum > 0) {205for (i = 1, s = 0; i <= bpp; i++) {206UINT8 v = state->buffer[i];207context->prior[i] = v;208s += (v < 128) ? v : 256 - v;209}210for (; i <= state->bytes; i++) {211UINT8 v = state->buffer[i] - state->buffer[i - bpp];212context->prior[i] = v;213s += (v < 128) ? v : 256 - v;214}215if (s < sum) {216context->output = context->prior;217sum = s; /* 0 if line is solid */218}219}220
221/* 3. Average (not very common in real-life images,222so its only used with the optimize option) */
223if (context->optimize && sum > 0) {224for (i = 1, s = 0; i <= bpp; i++) {225UINT8 v = state->buffer[i] - context->previous[i] / 2;226context->average[i] = v;227s += (v < 128) ? v : 256 - v;228}229for (; i <= state->bytes; i++) {230UINT8 v =231state->buffer[i] -232(state->buffer[i - bpp] + context->previous[i]) / 2;233context->average[i] = v;234s += (v < 128) ? v : 256 - v;235}236if (s < sum) {237context->output = context->average;238sum = s;239}240}241
242/* 4. Paeth */243if (sum > 0) {244for (i = 1, s = 0; i <= bpp; i++) {245UINT8 v = state->buffer[i] - context->previous[i];246context->paeth[i] = v;247s += (v < 128) ? v : 256 - v;248}249for (; i <= state->bytes; i++) {250UINT8 v;251int a, b, c;252int pa, pb, pc;253
254/* fetch pixels */255a = state->buffer[i - bpp];256b = context->previous[i];257c = context->previous[i - bpp];258
259/* distances to surrounding pixels */260pa = abs(b - c);261pb = abs(a - c);262pc = abs(a + b - 2 * c);263
264/* pick predictor with the shortest distance */265v = state->buffer[i] - ((pa <= pb && pa <= pc) ? a266: (pb <= pc) ? b267: c);268context->paeth[i] = v;269s += (v < 128) ? v : 256 - v;270}271if (s < sum) {272context->output = context->paeth;273sum = s;274}275}276}277
278/* Compress this line */279context->z_stream.next_in = context->output;280context->z_stream.avail_in = state->bytes + 1;281
282err = deflate(&context->z_stream, Z_NO_FLUSH);283
284if (err < 0) {285/* Something went wrong inside the compression library */286if (err == Z_DATA_ERROR) {287state->errcode = IMAGING_CODEC_BROKEN;288} else if (err == Z_MEM_ERROR) {289state->errcode = IMAGING_CODEC_MEMORY;290} else {291state->errcode = IMAGING_CODEC_CONFIG;292}293free(context->paeth);294free(context->average);295free(context->up);296free(context->prior);297free(context->previous);298deflateEnd(&context->z_stream);299ImagingSectionLeave(&cookie);300return -1;301}302
303/* Swap buffer pointers */304ptr = state->buffer;305state->buffer = context->previous;306context->previous = ptr;307}308
309if (context->z_stream.avail_out == 0) {310break; /* Buffer full */311}312
313case 2:314
315/* End of image data; flush compressor buffers */316
317while (context->z_stream.avail_out > 0) {318err = deflate(&context->z_stream, Z_FINISH);319
320if (err == Z_STREAM_END) {321free(context->paeth);322free(context->average);323free(context->up);324free(context->prior);325free(context->previous);326
327deflateEnd(&context->z_stream);328
329state->errcode = IMAGING_CODEC_END;330
331break;332}333
334if (context->z_stream.avail_out == 0) {335break; /* Buffer full */336}337}338}339ImagingSectionLeave(&cookie);340return bytes - context->z_stream.avail_out;341}342
343/* Should never ever arrive here... */344state->errcode = IMAGING_CODEC_CONFIG;345ImagingSectionLeave(&cookie);346return -1;347}
348
349/* -------------------------------------------------------------------- */
350/* Cleanup */
351/* -------------------------------------------------------------------- */
352
353int
354ImagingZipEncodeCleanup(ImagingCodecState state) {355ZIPSTATE *context = (ZIPSTATE *)state->context;356
357if (context->dictionary) {358free(context->dictionary);359context->dictionary = NULL;360}361
362return -1;363}
364
365const char *366ImagingZipVersion(void) {367return zlibVersion();368}
369
370#endif371