Pillow

Форк
0
/
JpegEncode.c 
391 строка · 13.4 Кб
1
/*
2
 * The Python Imaging Library.
3
 * $Id$
4
 *
5
 * coder for JPEG data
6
 *
7
 * history:
8
 * 1996-05-06 fl   created
9
 * 1996-07-16 fl   don't drop last block of encoded data
10
 * 1996-12-30 fl   added quality and progressive settings
11
 * 1997-01-08 fl   added streamtype settings
12
 * 1998-01-31 fl   adapted to libjpeg 6a
13
 * 1998-07-12 fl   added YCbCr support
14
 * 2001-04-16 fl   added DPI write support
15
 *
16
 * Copyright (c) 1997-2001 by Secret Labs AB
17
 * Copyright (c) 1995-1997 by Fredrik Lundh
18
 *
19
 * See the README file for details on usage and redistribution.
20
 */
21

22
#include "Imaging.h"
23

24
#ifdef HAVE_LIBJPEG
25

26
#undef HAVE_PROTOTYPES
27
#undef HAVE_STDLIB_H
28
#undef HAVE_STDDEF_H
29
#undef UINT8
30
#undef UINT16
31
#undef UINT32
32
#undef INT16
33
#undef INT32
34

35
#include "Jpeg.h"
36

37
/* -------------------------------------------------------------------- */
38
/* Suspending output handler                                            */
39
/* -------------------------------------------------------------------- */
40

41
METHODDEF(void)
42
stub(j_compress_ptr cinfo) { /* empty */ }
43

44
METHODDEF(boolean)
45
empty_output_buffer(j_compress_ptr cinfo) {
46
    /* Suspension */
47
    return FALSE;
48
}
49

50
GLOBAL(void)
51
jpeg_buffer_dest(j_compress_ptr cinfo, JPEGDESTINATION *destination) {
52
    cinfo->dest = (void *)destination;
53

54
    destination->pub.init_destination = stub;
55
    destination->pub.empty_output_buffer = empty_output_buffer;
56
    destination->pub.term_destination = stub;
57
}
58

59
/* -------------------------------------------------------------------- */
60
/* Error handler                                                        */
61
/* -------------------------------------------------------------------- */
62

63
METHODDEF(void)
64
error(j_common_ptr cinfo) {
65
    JPEGERROR *error;
66
    error = (JPEGERROR *)cinfo->err;
67
    (*cinfo->err->output_message)(cinfo);
68
    longjmp(error->setjmp_buffer, 1);
69
}
70

71
/* -------------------------------------------------------------------- */
72
/* Encoder                                                              */
73
/* -------------------------------------------------------------------- */
74

75
int
76
ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
77
    JPEGENCODERSTATE *context = (JPEGENCODERSTATE *)state->context;
78
    int ok;
79

80
    if (setjmp(context->error.setjmp_buffer)) {
81
        /* JPEG error handler */
82
        jpeg_destroy_compress(&context->cinfo);
83
        state->errcode = IMAGING_CODEC_BROKEN;
84
        return -1;
85
    }
86

87
    if (!state->state) {
88
        /* Setup compression context (very similar to the decoder) */
89
        context->cinfo.err = jpeg_std_error(&context->error.pub);
90
        context->error.pub.error_exit = error;
91
        jpeg_create_compress(&context->cinfo);
92
        jpeg_buffer_dest(&context->cinfo, &context->destination);
93

94
        context->extra_offset = 0;
95

96
        /* Ready to encode */
97
        state->state = 1;
98
    }
99

100
    /* Load the destination buffer */
101
    context->destination.pub.next_output_byte = buf;
102
    context->destination.pub.free_in_buffer = bytes;
103

104
    switch (state->state) {
105
        case 1:
106

107
            context->cinfo.image_width = state->xsize;
108
            context->cinfo.image_height = state->ysize;
109

110
            switch (state->bits) {
111
                case 8:
112
                    context->cinfo.input_components = 1;
113
                    context->cinfo.in_color_space = JCS_GRAYSCALE;
114
                    break;
115
                case 24:
116
                    context->cinfo.input_components = 3;
117
                    if (strcmp(im->mode, "YCbCr") == 0) {
118
                        context->cinfo.in_color_space = JCS_YCbCr;
119
                    } else {
120
                        context->cinfo.in_color_space = JCS_RGB;
121
                    }
122
                    break;
123
                case 32:
124
                    context->cinfo.input_components = 4;
125
                    context->cinfo.in_color_space = JCS_CMYK;
126
#ifdef JCS_EXTENSIONS
127
                    if (strcmp(context->rawmode, "RGBX") == 0) {
128
                        context->cinfo.in_color_space = JCS_EXT_RGBX;
129
                    }
130
#endif
131
                    break;
132
                default:
133
                    state->errcode = IMAGING_CODEC_CONFIG;
134
                    return -1;
135
            }
136

137
            /* Compressor configuration */
138
            jpeg_set_defaults(&context->cinfo);
139

140
            /* Prevent RGB -> YCbCr conversion */
141
            if (context->keep_rgb) {
142
                switch (context->cinfo.in_color_space) {
143
                    case JCS_RGB:
144
#ifdef JCS_EXTENSIONS
145
                    case JCS_EXT_RGBX:
146
#endif
147
                        switch (context->subsampling) {
148
                            case -1: /* Default */
149
                            case 0:  /* No subsampling */
150
                                break;
151
                            default:
152
                                /* Would subsample the green and blue
153
                                   channels, which doesn't make sense */
154
                                state->errcode = IMAGING_CODEC_CONFIG;
155
                                return -1;
156
                        }
157
                        jpeg_set_colorspace(&context->cinfo, JCS_RGB);
158
                        break;
159
                    default:
160
                        break;
161
                }
162
            }
163

164
            /* Use custom quantization tables */
165
            if (context->qtables) {
166
                int i;
167
                int quality = 100;
168
                int last_q = 0;
169
                if (context->quality != -1) {
170
                    quality = context->quality;
171
                }
172
                for (i = 0; i < context->qtablesLen; i++) {
173
                    jpeg_add_quant_table(
174
                        &context->cinfo,
175
                        i,
176
                        &context->qtables[i * DCTSIZE2],
177
                        quality,
178
                        FALSE
179
                    );
180
                    context->cinfo.comp_info[i].quant_tbl_no = i;
181
                    last_q = i;
182
                }
183
                if (context->qtablesLen == 1) {
184
                    // jpeg_set_defaults created two qtables internally, but we only
185
                    // wanted one.
186
                    jpeg_add_quant_table(
187
                        &context->cinfo, 1, &context->qtables[0], quality, FALSE
188
                    );
189
                }
190
                for (i = last_q; i < context->cinfo.num_components; i++) {
191
                    context->cinfo.comp_info[i].quant_tbl_no = last_q;
192
                }
193
            } else if (context->quality != -1) {
194
                jpeg_set_quality(&context->cinfo, context->quality, TRUE);
195
            }
196

197
            /* Set subsampling options */
198
            switch (context->subsampling) {
199
                case 0: /* 1x1 1x1 1x1 (4:4:4) : None */
200
                {
201
                    context->cinfo.comp_info[0].h_samp_factor = 1;
202
                    context->cinfo.comp_info[0].v_samp_factor = 1;
203
                    context->cinfo.comp_info[1].h_samp_factor = 1;
204
                    context->cinfo.comp_info[1].v_samp_factor = 1;
205
                    context->cinfo.comp_info[2].h_samp_factor = 1;
206
                    context->cinfo.comp_info[2].v_samp_factor = 1;
207
                    break;
208
                }
209
                case 1: /* 2x1, 1x1, 1x1 (4:2:2) : Medium */
210
                {
211
                    context->cinfo.comp_info[0].h_samp_factor = 2;
212
                    context->cinfo.comp_info[0].v_samp_factor = 1;
213
                    context->cinfo.comp_info[1].h_samp_factor = 1;
214
                    context->cinfo.comp_info[1].v_samp_factor = 1;
215
                    context->cinfo.comp_info[2].h_samp_factor = 1;
216
                    context->cinfo.comp_info[2].v_samp_factor = 1;
217
                    break;
218
                }
219
                case 2: /* 2x2, 1x1, 1x1 (4:2:0) : High */
220
                {
221
                    context->cinfo.comp_info[0].h_samp_factor = 2;
222
                    context->cinfo.comp_info[0].v_samp_factor = 2;
223
                    context->cinfo.comp_info[1].h_samp_factor = 1;
224
                    context->cinfo.comp_info[1].v_samp_factor = 1;
225
                    context->cinfo.comp_info[2].h_samp_factor = 1;
226
                    context->cinfo.comp_info[2].v_samp_factor = 1;
227
                    break;
228
                }
229
                default: {
230
                    /* Use the lib's default */
231
                    break;
232
                }
233
            }
234
            if (context->progressive) {
235
                jpeg_simple_progression(&context->cinfo);
236
            }
237
            context->cinfo.smoothing_factor = context->smooth;
238
            context->cinfo.optimize_coding = (boolean)context->optimize;
239
            context->cinfo.restart_interval = context->restart_marker_blocks;
240
            context->cinfo.restart_in_rows = context->restart_marker_rows;
241
            if (context->xdpi > 0 && context->ydpi > 0) {
242
                context->cinfo.write_JFIF_header = TRUE;
243
                context->cinfo.density_unit = 1; /* dots per inch */
244
                context->cinfo.X_density = context->xdpi;
245
                context->cinfo.Y_density = context->ydpi;
246
            }
247
            switch (context->streamtype) {
248
                case 1:
249
                    /* tables only */
250
                    jpeg_write_tables(&context->cinfo);
251
                    goto cleanup;
252
                case 2:
253
                    /* image only */
254
                    jpeg_suppress_tables(&context->cinfo, TRUE);
255
                    jpeg_start_compress(&context->cinfo, FALSE);
256
                    /* suppress extra section */
257
                    context->extra_offset = context->extra_size;
258
                    break;
259
                default:
260
                    /* interchange stream */
261
                    jpeg_start_compress(&context->cinfo, TRUE);
262
                    break;
263
            }
264
            state->state++;
265
            /* fall through */
266

267
        case 2:
268
            // check for exif len + 'APP1' header bytes
269
            if (context->rawExifLen + 5 > context->destination.pub.free_in_buffer) {
270
                break;
271
            }
272
            // add exif header
273
            if (context->rawExifLen > 0) {
274
                jpeg_write_marker(
275
                    &context->cinfo,
276
                    JPEG_APP0 + 1,
277
                    (unsigned char *)context->rawExif,
278
                    context->rawExifLen
279
                );
280
            }
281

282
            state->state++;
283
            /* fall through */
284
        case 3:
285

286
            if (context->extra) {
287
                /* copy extra buffer to output buffer */
288
                unsigned int n = context->extra_size - context->extra_offset;
289
                if (n > context->destination.pub.free_in_buffer) {
290
                    n = context->destination.pub.free_in_buffer;
291
                }
292
                memcpy(
293
                    context->destination.pub.next_output_byte,
294
                    context->extra + context->extra_offset,
295
                    n
296
                );
297
                context->destination.pub.next_output_byte += n;
298
                context->destination.pub.free_in_buffer -= n;
299
                context->extra_offset += n;
300
                if (context->extra_offset >= context->extra_size) {
301
                    state->state++;
302
                } else {
303
                    break;
304
                }
305
            } else {
306
                state->state++;
307
            }
308

309
        case 4:
310

311
            if (context->comment) {
312
                jpeg_write_marker(
313
                    &context->cinfo,
314
                    JPEG_COM,
315
                    (unsigned char *)context->comment,
316
                    context->comment_size
317
                );
318
            }
319
            state->state++;
320

321
        case 5:
322
            if (1024 > context->destination.pub.free_in_buffer) {
323
                break;
324
            }
325

326
            ok = 1;
327
            while (state->y < state->ysize) {
328
                state->shuffle(
329
                    state->buffer,
330
                    (UINT8 *)im->image[state->y + state->yoff] +
331
                        state->xoff * im->pixelsize,
332
                    state->xsize
333
                );
334
                ok = jpeg_write_scanlines(&context->cinfo, &state->buffer, 1);
335
                if (ok != 1) {
336
                    break;
337
                }
338
                state->y++;
339
            }
340

341
            if (ok != 1) {
342
                break;
343
            }
344
            state->state++;
345
            /* fall through */
346

347
        case 6:
348

349
            /* Finish compression */
350
            if (context->destination.pub.free_in_buffer < 100) {
351
                break;
352
            }
353
            jpeg_finish_compress(&context->cinfo);
354

355
cleanup:
356
            /* Clean up */
357
            if (context->comment) {
358
                free(context->comment);
359
                context->comment = NULL;
360
            }
361
            if (context->extra) {
362
                free(context->extra);
363
                context->extra = NULL;
364
            }
365
            if (context->rawExif) {
366
                free(context->rawExif);
367
                context->rawExif = NULL;
368
            }
369
            if (context->qtables) {
370
                free(context->qtables);
371
                context->qtables = NULL;
372
            }
373

374
            jpeg_destroy_compress(&context->cinfo);
375
            /* if (jerr.pub.num_warnings) return BROKEN; */
376
            state->errcode = IMAGING_CODEC_END;
377
            break;
378
    }
379

380
    /* Return number of bytes in output buffer */
381
    return context->destination.pub.next_output_byte - buf;
382
}
383

384
const char *
385
ImagingJpegVersion(void) {
386
    static char version[20];
387
    sprintf(version, "%d.%d", JPEG_LIB_VERSION / 10, JPEG_LIB_VERSION % 10);
388
    return version;
389
}
390

391
#endif
392

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

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

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

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