Pillow

Форк
0
/
ZipEncode.c 
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_LIBZ
20

21
#include "ZipCodecs.h"
22

23
int
24
ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
25
    ZIPSTATE *context = (ZIPSTATE *)state->context;
26
    int err;
27
    int compress_level, compress_type;
28
    UINT8 *ptr;
29
    int i, bpp, s, sum;
30
    ImagingSectionCookie cookie;
31

32
    if (!state->state) {
33
        /* Initialization */
34

35
        /* Valid modes are ZIP_PNG, ZIP_PNG_PALETTE, and ZIP_TIFF */
36

37
        /* overflow check for malloc */
38
        if (state->bytes > INT_MAX - 1) {
39
            state->errcode = IMAGING_CODEC_MEMORY;
40
            return -1;
41
        }
42

43
        /* Expand standard buffer to make room for the filter selector,
44
           and allocate filter buffers */
45
        free(state->buffer);
46
        /* malloc check ok, overflow checked above */
47
        state->buffer = (UINT8 *)malloc(state->bytes + 1);
48
        context->previous = (UINT8 *)malloc(state->bytes + 1);
49
        context->prior = (UINT8 *)malloc(state->bytes + 1);
50
        context->up = (UINT8 *)malloc(state->bytes + 1);
51
        context->average = (UINT8 *)malloc(state->bytes + 1);
52
        context->paeth = (UINT8 *)malloc(state->bytes + 1);
53
        if (!state->buffer || !context->previous || !context->prior || !context->up ||
54
            !context->average || !context->paeth) {
55
            free(context->paeth);
56
            free(context->average);
57
            free(context->up);
58
            free(context->prior);
59
            free(context->previous);
60
            state->errcode = IMAGING_CODEC_MEMORY;
61
            return -1;
62
        }
63

64
        /* Initialise filter buffers */
65
        state->buffer[0] = 0;
66
        context->prior[0] = 1;
67
        context->up[0] = 2;
68
        context->average[0] = 3;
69
        context->paeth[0] = 4;
70

71
        /* Initialise previous buffer to black */
72
        memset(context->previous, 0, state->bytes + 1);
73

74
        /* Setup compression context */
75
        context->z_stream.zalloc = (alloc_func)0;
76
        context->z_stream.zfree = (free_func)0;
77
        context->z_stream.opaque = (voidpf)0;
78
        context->z_stream.next_in = 0;
79
        context->z_stream.avail_in = 0;
80

81
        compress_level =
82
            (context->optimize) ? Z_BEST_COMPRESSION : context->compress_level;
83

84
        if (context->compress_type == -1) {
85
            compress_type =
86
                (context->mode == ZIP_PNG) ? Z_FILTERED : Z_DEFAULT_STRATEGY;
87
        } else {
88
            compress_type = context->compress_type;
89
        }
90

91
        err = deflateInit2(
92
            &context->z_stream,
93
            /* compression level */
94
            compress_level,
95
            /* compression method */
96
            Z_DEFLATED,
97
            /* compression memory resources */
98
            15,
99
            9,
100
            /* compression strategy (image data are filtered)*/
101
            compress_type
102
        );
103
        if (err < 0) {
104
            state->errcode = IMAGING_CODEC_CONFIG;
105
            return -1;
106
        }
107

108
        if (context->dictionary && context->dictionary_size > 0) {
109
            err = deflateSetDictionary(
110
                &context->z_stream,
111
                (unsigned char *)context->dictionary,
112
                context->dictionary_size
113
            );
114
            if (err < 0) {
115
                state->errcode = IMAGING_CODEC_CONFIG;
116
                return -1;
117
            }
118
        }
119

120
        /* Ready to decode */
121
        state->state = 1;
122
    }
123

124
    /* Setup the destination buffer */
125
    context->z_stream.next_out = buf;
126
    context->z_stream.avail_out = bytes;
127
    if (context->z_stream.next_in && context->z_stream.avail_in > 0) {
128
        /* We have some data from previous round, deflate it first */
129
        err = deflate(&context->z_stream, Z_NO_FLUSH);
130

131
        if (err < 0) {
132
            /* Something went wrong inside the compression library */
133
            if (err == Z_DATA_ERROR) {
134
                state->errcode = IMAGING_CODEC_BROKEN;
135
            } else if (err == Z_MEM_ERROR) {
136
                state->errcode = IMAGING_CODEC_MEMORY;
137
            } else {
138
                state->errcode = IMAGING_CODEC_CONFIG;
139
            }
140
            free(context->paeth);
141
            free(context->average);
142
            free(context->up);
143
            free(context->prior);
144
            free(context->previous);
145
            deflateEnd(&context->z_stream);
146
            return -1;
147
        }
148
    }
149

150
    ImagingSectionEnter(&cookie);
151
    for (;;) {
152
        switch (state->state) {
153
            case 1:
154

155
                /* Compress image data */
156
                while (context->z_stream.avail_out > 0) {
157
                    if (state->y >= state->ysize) {
158
                        /* End of image; now flush compressor buffers */
159
                        state->state = 2;
160
                        break;
161
                    }
162

163
                    /* Stuff image data into the compressor */
164
                    state->shuffle(
165
                        state->buffer + 1,
166
                        (UINT8 *)im->image[state->y + state->yoff] +
167
                            state->xoff * im->pixelsize,
168
                        state->xsize
169
                    );
170

171
                    state->y++;
172

173
                    context->output = state->buffer;
174

175
                    if (context->mode == ZIP_PNG) {
176
                        /* Filter the image data.  For each line, select
177
                           the filter that gives the least total distance
178
                           from zero for the filtered data (taken from
179
                           LIBPNG) */
180

181
                        bpp = (state->bits + 7) / 8;
182

183
                        /* 0. No filter */
184
                        for (i = 1, sum = 0; i <= state->bytes; i++) {
185
                            UINT8 v = state->buffer[i];
186
                            sum += (v < 128) ? v : 256 - v;
187
                        }
188

189
                        /* 2. Up.  We'll test this first to save time when
190
                           an image line is identical to the one above. */
191
                        if (sum > 0) {
192
                            for (i = 1, s = 0; i <= state->bytes; i++) {
193
                                UINT8 v = state->buffer[i] - context->previous[i];
194
                                context->up[i] = v;
195
                                s += (v < 128) ? v : 256 - v;
196
                            }
197
                            if (s < sum) {
198
                                context->output = context->up;
199
                                sum = s; /* 0 if line was duplicated */
200
                            }
201
                        }
202

203
                        /* 1. Prior */
204
                        if (sum > 0) {
205
                            for (i = 1, s = 0; i <= bpp; i++) {
206
                                UINT8 v = state->buffer[i];
207
                                context->prior[i] = v;
208
                                s += (v < 128) ? v : 256 - v;
209
                            }
210
                            for (; i <= state->bytes; i++) {
211
                                UINT8 v = state->buffer[i] - state->buffer[i - bpp];
212
                                context->prior[i] = v;
213
                                s += (v < 128) ? v : 256 - v;
214
                            }
215
                            if (s < sum) {
216
                                context->output = context->prior;
217
                                sum = s; /* 0 if line is solid */
218
                            }
219
                        }
220

221
                        /* 3. Average (not very common in real-life images,
222
                           so its only used with the optimize option) */
223
                        if (context->optimize && sum > 0) {
224
                            for (i = 1, s = 0; i <= bpp; i++) {
225
                                UINT8 v = state->buffer[i] - context->previous[i] / 2;
226
                                context->average[i] = v;
227
                                s += (v < 128) ? v : 256 - v;
228
                            }
229
                            for (; i <= state->bytes; i++) {
230
                                UINT8 v =
231
                                    state->buffer[i] -
232
                                    (state->buffer[i - bpp] + context->previous[i]) / 2;
233
                                context->average[i] = v;
234
                                s += (v < 128) ? v : 256 - v;
235
                            }
236
                            if (s < sum) {
237
                                context->output = context->average;
238
                                sum = s;
239
                            }
240
                        }
241

242
                        /* 4. Paeth */
243
                        if (sum > 0) {
244
                            for (i = 1, s = 0; i <= bpp; i++) {
245
                                UINT8 v = state->buffer[i] - context->previous[i];
246
                                context->paeth[i] = v;
247
                                s += (v < 128) ? v : 256 - v;
248
                            }
249
                            for (; i <= state->bytes; i++) {
250
                                UINT8 v;
251
                                int a, b, c;
252
                                int pa, pb, pc;
253

254
                                /* fetch pixels */
255
                                a = state->buffer[i - bpp];
256
                                b = context->previous[i];
257
                                c = context->previous[i - bpp];
258

259
                                /* distances to surrounding pixels */
260
                                pa = abs(b - c);
261
                                pb = abs(a - c);
262
                                pc = abs(a + b - 2 * c);
263

264
                                /* pick predictor with the shortest distance */
265
                                v = state->buffer[i] - ((pa <= pb && pa <= pc) ? a
266
                                                        : (pb <= pc)           ? b
267
                                                                               : c);
268
                                context->paeth[i] = v;
269
                                s += (v < 128) ? v : 256 - v;
270
                            }
271
                            if (s < sum) {
272
                                context->output = context->paeth;
273
                                sum = s;
274
                            }
275
                        }
276
                    }
277

278
                    /* Compress this line */
279
                    context->z_stream.next_in = context->output;
280
                    context->z_stream.avail_in = state->bytes + 1;
281

282
                    err = deflate(&context->z_stream, Z_NO_FLUSH);
283

284
                    if (err < 0) {
285
                        /* Something went wrong inside the compression library */
286
                        if (err == Z_DATA_ERROR) {
287
                            state->errcode = IMAGING_CODEC_BROKEN;
288
                        } else if (err == Z_MEM_ERROR) {
289
                            state->errcode = IMAGING_CODEC_MEMORY;
290
                        } else {
291
                            state->errcode = IMAGING_CODEC_CONFIG;
292
                        }
293
                        free(context->paeth);
294
                        free(context->average);
295
                        free(context->up);
296
                        free(context->prior);
297
                        free(context->previous);
298
                        deflateEnd(&context->z_stream);
299
                        ImagingSectionLeave(&cookie);
300
                        return -1;
301
                    }
302

303
                    /* Swap buffer pointers */
304
                    ptr = state->buffer;
305
                    state->buffer = context->previous;
306
                    context->previous = ptr;
307
                }
308

309
                if (context->z_stream.avail_out == 0) {
310
                    break; /* Buffer full */
311
                }
312

313
            case 2:
314

315
                /* End of image data; flush compressor buffers */
316

317
                while (context->z_stream.avail_out > 0) {
318
                    err = deflate(&context->z_stream, Z_FINISH);
319

320
                    if (err == Z_STREAM_END) {
321
                        free(context->paeth);
322
                        free(context->average);
323
                        free(context->up);
324
                        free(context->prior);
325
                        free(context->previous);
326

327
                        deflateEnd(&context->z_stream);
328

329
                        state->errcode = IMAGING_CODEC_END;
330

331
                        break;
332
                    }
333

334
                    if (context->z_stream.avail_out == 0) {
335
                        break; /* Buffer full */
336
                    }
337
                }
338
        }
339
        ImagingSectionLeave(&cookie);
340
        return bytes - context->z_stream.avail_out;
341
    }
342

343
    /* Should never ever arrive here... */
344
    state->errcode = IMAGING_CODEC_CONFIG;
345
    ImagingSectionLeave(&cookie);
346
    return -1;
347
}
348

349
/* -------------------------------------------------------------------- */
350
/* Cleanup                                                              */
351
/* -------------------------------------------------------------------- */
352

353
int
354
ImagingZipEncodeCleanup(ImagingCodecState state) {
355
    ZIPSTATE *context = (ZIPSTATE *)state->context;
356

357
    if (context->dictionary) {
358
        free(context->dictionary);
359
        context->dictionary = NULL;
360
    }
361

362
    return -1;
363
}
364

365
const char *
366
ImagingZipVersion(void) {
367
    return zlibVersion();
368
}
369

370
#endif
371

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.