comparison mupdf-source/thirdparty/leptonica/src/jpegio.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
27 /*!
28 * \file jpegio.c
29 * <pre>
30 *
31 * Read jpeg from file
32 * PIX *pixReadJpeg() [special top level]
33 * PIX *pixReadStreamJpeg()
34 *
35 * Read jpeg metadata from file
36 * l_int32 readHeaderJpeg()
37 * l_int32 freadHeaderJpeg()
38 * l_int32 fgetJpegResolution()
39 * l_int32 fgetJpegComment()
40 *
41 * Write jpeg to file
42 * l_int32 pixWriteJpeg() [special top level]
43 * l_int32 pixWriteStreamJpeg()
44 *
45 * Read/write to memory
46 * PIX *pixReadMemJpeg()
47 * l_int32 readHeaderMemJpeg()
48 * l_int32 readResolutionMemJpeg()
49 * l_int32 pixWriteMemJpeg()
50 *
51 * Setting special flag for chroma sampling on write
52 * l_int32 pixSetChromaSampling()
53 *
54 * Static system helpers
55 * static void jpeg_error_catch_all_1()
56 * static void jpeg_error_catch_all_2()
57 * static l_uint8 jpeg_getc()
58 * static l_int32 jpeg_comment_callback()
59 *
60 * Documentation: libjpeg.doc can be found, along with all
61 * source code, at ftp://ftp.uu.net/graphics/jpeg
62 * Download and untar the file: jpegsrc.v6b.tar.gz
63 * A good paper on jpeg can also be found there: wallace.ps.gz
64 *
65 * The functions in libjpeg make it very simple to compress
66 * and decompress images. On input (decompression from file),
67 * 3 component color images can be read into either an 8 bpp Pix
68 * with a colormap or a 32 bpp Pix with RGB components. For output
69 * (compression to file), all color Pix, whether 8 bpp with a
70 * colormap or 32 bpp, are written compressed as a set of three
71 * 8 bpp (rgb) images.
72 *
73 * Low-level error handling
74 * ------------------------
75 * The default behavior of the jpeg library is to call exit.
76 * This is often undesirable, and the caller should make the
77 * decision when to abort a process. To prevent the jpeg library
78 * from calling exit(), setjmp() has been inserted into all
79 * readers and writers, and the cinfo struct has been set up so that
80 * the low-level jpeg library will call a special error handler
81 * that doesn't exit, instead of the default function error_exit().
82 *
83 * To avoid race conditions and make these functions thread-safe in
84 * the rare situation where calls to two threads are simultaneously
85 * failing on bad jpegs, we insert a local copy of the jmp_buf struct
86 * into the cinfo.client_data field, and use this on longjmp.
87 * For extracting the jpeg comment, we have the added complication
88 * that the client_data field must also return the jpeg comment,
89 * and we use a different error handler.
90 *
91 * How to avoid subsampling the chroma channels
92 * --------------------------------------------
93 * By default, the U,V (chroma) channels use 2x2 subsampling (aka 4.2.0).
94 * Higher quality for color, using full resolution (4.4.4) for the chroma,
95 * is obtained by setting a field in the pix before writing:
96 * pixSetChromaSampling(pix, L_NO_CHROMA_SAMPLING_JPEG);
97 * The field can be reset for default 4.2.0 subsampling with
98 * pixSetChromaSampling(pix, 0);
99 *
100 * How to extract just the luminance channel in reading RGB
101 * --------------------------------------------------------
102 * For higher resolution and faster decoding of an RGB image, you
103 * can extract just the 8 bpp luminance channel, using pixReadJpeg(),
104 * where you use L_JPEG_READ_LUMINANCE for the %hint arg.
105 *
106 * How to continue to read if the data is corrupted
107 * ------------------------------------------------
108 * By default, if data is corrupted we make every effort to fail
109 * to return a pix. (Failure is not always possible with bad
110 * data, because in some situations, such as during arithmetic
111 * decoding, the low-level jpeg library will not abort or raise
112 * a warning.) To attempt to ignore warnings and get a pix when data
113 * is corrupted, use L_JPEG_CONTINUE_WITH_BAD_DATA in the %hint arg.
114 *
115 * Compressing to memory and decompressing from memory
116 * ---------------------------------------------------
117 * On systems like Windows without fmemopen() and open_memstream(),
118 * we write data to a temp file and read it back for operations
119 * between pix and compressed-data, such as pixReadMemJpeg() and
120 * pixWriteMemJpeg().
121 * </pre>
122 */
123
124 #ifdef HAVE_CONFIG_H
125 #include <config_auto.h>
126 #endif /* HAVE_CONFIG_H */
127
128 #include <string.h>
129 #include "allheaders.h"
130 #include "pix_internal.h"
131
132 /* --------------------------------------------*/
133 #if HAVE_LIBJPEG /* defined in environ.h */
134 /* --------------------------------------------*/
135
136 #include <setjmp.h>
137
138 /* jconfig.h makes the error of setting
139 * #define HAVE_STDLIB_H
140 * which conflicts with config_auto.h (where it is set to 1) and results
141 * for some gcc compiler versions in a warning. The conflict is harmless
142 * but we suppress it by undefining the variable. */
143 #undef HAVE_STDLIB_H
144 #include "jpeglib.h"
145
146 static void jpeg_error_catch_all_1(j_common_ptr cinfo);
147 static void jpeg_error_catch_all_2(j_common_ptr cinfo);
148 static l_uint8 jpeg_getc(j_decompress_ptr cinfo);
149
150 /* Note: 'boolean' is defined in jmorecfg.h. We use it explicitly
151 * here because for Windows where __MINGW32__ is defined,
152 * the prototype for jpeg_comment_callback() is given as
153 * returning a boolean. */
154 static boolean jpeg_comment_callback(j_decompress_ptr cinfo);
155
156 /* This is saved in the client_data field of cinfo, and used both
157 * to retrieve the comment from its callback and to handle
158 * exceptions with a longjmp. */
159 struct callback_data {
160 jmp_buf jmpbuf;
161 l_uint8 *comment;
162 };
163
164 #ifndef NO_CONSOLE_IO
165 #define DEBUG_INFO 0
166 #endif /* ~NO_CONSOLE_IO */
167
168
169 /*---------------------------------------------------------------------*
170 * Read jpeg from file (special function) *
171 *---------------------------------------------------------------------*/
172 /*!
173 * \brief pixReadJpeg()
174 *
175 * \param[in] filename
176 * \param[in] cmapflag 0 for no colormap in returned pix;
177 * 1 to return an 8 bpp cmapped pix if spp = 3 or 4
178 * \param[in] reduction scaling factor: 1, 2, 4 or 8
179 * \param[out] pnwarn [optional] number of warnings about
180 * corrupted data
181 * \param[in] hint a bitwise OR of L_JPEG_* values; 0 for default
182 * \return pix, or NULL on error
183 *
184 * <pre>
185 * Notes:
186 * (1) This is a special function for reading jpeg files.
187 * (2) Use this if you want the jpeg library to create
188 * an 8 bpp colormapped image.
189 * (3) Images reduced by factors of 2, 4 or 8 can be returned
190 * significantly faster than full resolution images.
191 * (4) If the jpeg data is bad, depending on the severity of the
192 * data corruption one of two things will happen:
193 * (a) 0 or more warnings are generated, or
194 * (b) the library will immediately attempt to exit. This is
195 * caught by our error handler and no pix will be returned.
196 * If data corruption causes a warning, the default action
197 * is to abort the read. The reason is that malformed jpeg
198 * data sequences exist that prevent termination of the read.
199 * To allow the decoding to continue after corrupted data is
200 * encountered, include L_JPEG_CONTINUE_WITH_BAD_DATA in %hint.
201 * (5) The possible hint values are given in the enum in imageio.h:
202 * * L_JPEG_READ_LUMINANCE
203 * * L_JPEG_CONTINUE_WITH_BAD_DATA
204 * Default (0) is to do neither, and to fail on warning of data
205 * corruption.
206 * </pre>
207 */
208 PIX *
209 pixReadJpeg(const char *filename,
210 l_int32 cmapflag,
211 l_int32 reduction,
212 l_int32 *pnwarn,
213 l_int32 hint)
214 {
215 l_int32 ret;
216 l_uint8 *comment;
217 FILE *fp;
218 PIX *pix;
219
220 if (pnwarn) *pnwarn = 0;
221 if (!filename)
222 return (PIX *)ERROR_PTR("filename not defined", __func__, NULL);
223 if (cmapflag != 0 && cmapflag != 1)
224 cmapflag = 0; /* default */
225 if (reduction != 1 && reduction != 2 && reduction != 4 && reduction != 8)
226 return (PIX *)ERROR_PTR("reduction not in {1,2,4,8}", __func__, NULL);
227
228 if ((fp = fopenReadStream(filename)) == NULL)
229 return (PIX *)ERROR_PTR_1("image file not found",
230 filename, __func__, NULL);
231 pix = pixReadStreamJpeg(fp, cmapflag, reduction, pnwarn, hint);
232 if (pix) {
233 ret = fgetJpegComment(fp, &comment);
234 if (!ret && comment)
235 pixSetText(pix, (char *)comment);
236 LEPT_FREE(comment);
237 }
238 fclose(fp);
239
240 if (!pix)
241 return (PIX *)ERROR_PTR_1("image not returned",
242 filename, __func__, NULL);
243 return pix;
244 }
245
246
247 /*!
248 * \brief pixReadStreamJpeg()
249 *
250 * \param[in] fp file stream
251 * \param[in] cmapflag 0 for no colormap in returned pix;
252 * 1 to return an 8 bpp cmapped pix if spp = 3 or 4
253 * \param[in] reduction scaling factor: 1, 2, 4 or 8
254 * \param[out] pnwarn [optional] number of warnings
255 * \param[in] hint a bitwise OR of L_JPEG_* values; 0 for default
256 * \return pix, or NULL on error
257 *
258 * <pre>
259 * Notes:
260 * (1) For usage, see pixReadJpeg().
261 * (2) The jpeg comment, if it exists, is not stored in the pix.
262 * </pre>
263 */
264 PIX *
265 pixReadStreamJpeg(FILE *fp,
266 l_int32 cmapflag,
267 l_int32 reduction,
268 l_int32 *pnwarn,
269 l_int32 hint)
270 {
271 l_int32 cyan, yellow, magenta, black, nwarn;
272 l_int32 i, j, k, rval, gval, bval;
273 l_int32 nlinesread, abort_on_warning;
274 l_int32 w, h, wpl, spp, ncolors, cindex, ycck, cmyk;
275 l_uint32 *data;
276 l_uint32 *line, *ppixel;
277 JSAMPROW rowbuffer;
278 PIX *pix;
279 PIXCMAP *cmap;
280 struct jpeg_decompress_struct cinfo = { 0 };
281 struct jpeg_error_mgr jerr = { 0 };
282 jmp_buf jmpbuf; /* must be local to the function */
283
284 if (pnwarn) *pnwarn = 0;
285 if (!fp)
286 return (PIX *)ERROR_PTR("fp not defined", __func__, NULL);
287 if (cmapflag != 0 && cmapflag != 1)
288 cmapflag = 0; /* default */
289 if (reduction != 1 && reduction != 2 && reduction != 4 && reduction != 8)
290 return (PIX *)ERROR_PTR("reduction not in {1,2,4,8}", __func__, NULL);
291
292 if (BITS_IN_JSAMPLE != 8) /* set in jmorecfg.h */
293 return (PIX *)ERROR_PTR("BITS_IN_JSAMPLE != 8", __func__, NULL);
294
295 rewind(fp);
296 pix = NULL;
297 rowbuffer = NULL;
298
299 /* Modify the jpeg error handling to catch fatal errors */
300 cinfo.err = jpeg_std_error(&jerr);
301 jerr.error_exit = jpeg_error_catch_all_1;
302 cinfo.client_data = (void *)&jmpbuf;
303 if (setjmp(jmpbuf)) {
304 jpeg_destroy_decompress(&cinfo);
305 pixDestroy(&pix);
306 LEPT_FREE(rowbuffer);
307 return (PIX *)ERROR_PTR("internal jpeg error", __func__, NULL);
308 }
309
310 /* Initialize jpeg structs for decompression */
311 jpeg_create_decompress(&cinfo);
312 jpeg_stdio_src(&cinfo, fp);
313 jpeg_read_header(&cinfo, TRUE);
314 cinfo.scale_denom = reduction;
315 cinfo.scale_num = 1;
316 jpeg_calc_output_dimensions(&cinfo);
317 if (hint & L_JPEG_READ_LUMINANCE) {
318 cinfo.out_color_space = JCS_GRAYSCALE;
319 spp = 1;
320 L_INFO("reading luminance channel only\n", __func__);
321 } else {
322 spp = cinfo.out_color_components;
323 }
324
325 /* Allocate the image and a row buffer */
326 w = cinfo.output_width;
327 h = cinfo.output_height;
328 ycck = (cinfo.jpeg_color_space == JCS_YCCK && spp == 4 && cmapflag == 0);
329 cmyk = (cinfo.jpeg_color_space == JCS_CMYK && spp == 4 && cmapflag == 0);
330 if (spp != 1 && spp != 3 && !ycck && !cmyk) {
331 jpeg_destroy_decompress(&cinfo);
332 return (PIX *)ERROR_PTR("spp must be 1 or 3, or YCCK or CMYK",
333 __func__, NULL);
334 }
335 if ((spp == 3 && cmapflag == 0) || ycck || cmyk) { /* rgb or 4 bpp color */
336 rowbuffer = (JSAMPROW)LEPT_CALLOC(sizeof(JSAMPLE), (size_t)spp * w);
337 pix = pixCreate(w, h, 32);
338 } else { /* 8 bpp gray or colormapped */
339 rowbuffer = (JSAMPROW)LEPT_CALLOC(sizeof(JSAMPLE), w);
340 pix = pixCreate(w, h, 8);
341 }
342 if (!rowbuffer || !pix) {
343 LEPT_FREE(rowbuffer);
344 rowbuffer = NULL;
345 pixDestroy(&pix);
346 jpeg_destroy_decompress(&cinfo);
347 return (PIX *)ERROR_PTR("rowbuffer or pix not made", __func__, NULL);
348 }
349 pixSetInputFormat(pix, IFF_JFIF_JPEG);
350
351 /* Initialize decompression.
352 * Set up a colormap for color quantization if requested.
353 * Arithmetic coding is rarely used on the jpeg data, but if it
354 * is, jpeg_start_decompress() handles the decoding.
355 * With corrupted encoded data, this can take an arbitrarily
356 * long time, and fuzzers are finding examples. Unfortunately,
357 * there is no way to get a callback from an error in this phase. */
358 if (spp == 1) { /* Grayscale or colormapped */
359 jpeg_start_decompress(&cinfo);
360 } else { /* Color; spp == 3 or YCCK or CMYK */
361 if (cmapflag == 0) { /* 24 bit color in 32 bit pix or YCCK/CMYK */
362 cinfo.quantize_colors = FALSE;
363 jpeg_start_decompress(&cinfo);
364 } else { /* Color quantize to 8 bits */
365 cinfo.quantize_colors = TRUE;
366 cinfo.desired_number_of_colors = 256;
367 jpeg_start_decompress(&cinfo);
368
369 /* Construct a pix cmap */
370 cmap = pixcmapCreate(8);
371 ncolors = cinfo.actual_number_of_colors;
372 for (cindex = 0; cindex < ncolors; cindex++) {
373 rval = cinfo.colormap[0][cindex];
374 gval = cinfo.colormap[1][cindex];
375 bval = cinfo.colormap[2][cindex];
376 pixcmapAddColor(cmap, rval, gval, bval);
377 }
378 pixSetColormap(pix, cmap);
379 }
380 }
381 wpl = pixGetWpl(pix);
382 data = pixGetData(pix);
383
384 /* Decompress. It appears that jpeg_read_scanlines() always
385 * returns 1 when you ask for one scanline, but we test anyway.
386 * During decoding of scanlines, warnings are issued if corrupted
387 * data is found. The default behavior is to abort reading
388 * when a warning is encountered. By setting the hint to have
389 * the same bit set as in L_JPEG_CONTINUE_WITH_BAD_DATA, e.g.,
390 * hint = hint | L_JPEG_CONTINUE_WITH_BAD_DATA
391 * reading will continue after warnings, in an attempt to return
392 * the (possibly corrupted) image. */
393 abort_on_warning = (hint & L_JPEG_CONTINUE_WITH_BAD_DATA) ? 0 : 1;
394 for (i = 0; i < h; i++) {
395 nlinesread = jpeg_read_scanlines(&cinfo, &rowbuffer, (JDIMENSION)1);
396 nwarn = cinfo.err->num_warnings;
397 if (nlinesread == 0 || (abort_on_warning && nwarn > 0)) {
398 L_ERROR("read error at scanline %d; nwarn = %d\n",
399 __func__, i, nwarn);
400 pixDestroy(&pix);
401 jpeg_destroy_decompress(&cinfo);
402 LEPT_FREE(rowbuffer);
403 rowbuffer = NULL;
404 if (pnwarn) *pnwarn = nwarn;
405 return (PIX *)ERROR_PTR("bad data", __func__, NULL);
406 }
407
408 /* -- 24 bit color -- */
409 if ((spp == 3 && cmapflag == 0) || ycck || cmyk) {
410 ppixel = data + i * wpl;
411 if (spp == 3) {
412 for (j = k = 0; j < w; j++) {
413 SET_DATA_BYTE(ppixel, COLOR_RED, rowbuffer[k++]);
414 SET_DATA_BYTE(ppixel, COLOR_GREEN, rowbuffer[k++]);
415 SET_DATA_BYTE(ppixel, COLOR_BLUE, rowbuffer[k++]);
416 ppixel++;
417 }
418 } else {
419 /* This is a conversion from CMYK -> RGB that ignores
420 color profiles, and is invoked when the image header
421 claims to be in CMYK or YCCK colorspace. If in YCCK,
422 libjpeg may be doing YCCK -> CMYK under the hood.
423 To understand why the colors need to be inverted on
424 read-in for the Adobe marker, see the "Special
425 color spaces" section of "Using the IJG JPEG
426 Library" by Thomas G. Lane:
427 http://www.jpegcameras.com/libjpeg/libjpeg-3.html#ss3.1
428 The non-Adobe conversion is equivalent to:
429 rval = black - black * cyan / 255
430 ...
431 The Adobe conversion is equivalent to:
432 rval = black - black * (255 - cyan) / 255
433 ...
434 Note that cyan is the complement to red, and we
435 are subtracting the complement color (weighted
436 by black) from black. For Adobe conversions,
437 where they've already inverted the CMY but not
438 the K, we have to invert again. The results
439 must be clipped to [0 ... 255]. */
440 for (j = k = 0; j < w; j++) {
441 cyan = rowbuffer[k++];
442 magenta = rowbuffer[k++];
443 yellow = rowbuffer[k++];
444 black = rowbuffer[k++];
445 if (cinfo.saw_Adobe_marker) {
446 rval = (black * cyan) / 255;
447 gval = (black * magenta) / 255;
448 bval = (black * yellow) / 255;
449 } else {
450 rval = black * (255 - cyan) / 255;
451 gval = black * (255 - magenta) / 255;
452 bval = black * (255 - yellow) / 255;
453 }
454 rval = L_MIN(L_MAX(rval, 0), 255);
455 gval = L_MIN(L_MAX(gval, 0), 255);
456 bval = L_MIN(L_MAX(bval, 0), 255);
457 composeRGBPixel(rval, gval, bval, ppixel);
458 ppixel++;
459 }
460 }
461 } else { /* 8 bpp grayscale or colormapped pix */
462 line = data + i * wpl;
463 for (j = 0; j < w; j++)
464 SET_DATA_BYTE(line, j, rowbuffer[j]);
465 }
466 }
467
468 /* If the pixel density is neither 1 nor 2, it may not be defined.
469 * In that case, don't set the resolution. */
470 if (cinfo.density_unit == 1) { /* pixels per inch */
471 pixSetXRes(pix, cinfo.X_density);
472 pixSetYRes(pix, cinfo.Y_density);
473 } else if (cinfo.density_unit == 2) { /* pixels per centimeter */
474 pixSetXRes(pix, (l_int32)((l_float32)cinfo.X_density * 2.54 + 0.5));
475 pixSetYRes(pix, (l_int32)((l_float32)cinfo.Y_density * 2.54 + 0.5));
476 }
477
478 if (cinfo.output_components != spp)
479 lept_stderr("output spp = %d, spp = %d\n",
480 cinfo.output_components, spp);
481
482 jpeg_finish_decompress(&cinfo);
483 jpeg_destroy_decompress(&cinfo);
484 LEPT_FREE(rowbuffer);
485 rowbuffer = NULL;
486 if (pnwarn) *pnwarn = nwarn;
487 if (nwarn > 0)
488 L_WARNING("%d warning(s) of bad data\n", __func__, nwarn);
489 return pix;
490 }
491
492
493 /*---------------------------------------------------------------------*
494 * Read jpeg metadata from file *
495 *---------------------------------------------------------------------*/
496 /*!
497 * \brief readHeaderJpeg()
498 *
499 * \param[in] filename
500 * \param[out] pw [optional]
501 * \param[out] ph [optional]
502 * \param[out] pspp [optional] samples/pixel
503 * \param[out] pycck [optional] 1 if ycck color space; 0 otherwise
504 * \param[out] pcmyk [optional] 1 if cmyk color space; 0 otherwise
505 * \return 0 if OK, 1 on error
506 */
507 l_ok
508 readHeaderJpeg(const char *filename,
509 l_int32 *pw,
510 l_int32 *ph,
511 l_int32 *pspp,
512 l_int32 *pycck,
513 l_int32 *pcmyk)
514 {
515 l_int32 ret;
516 FILE *fp;
517
518 if (pw) *pw = 0;
519 if (ph) *ph = 0;
520 if (pspp) *pspp = 0;
521 if (pycck) *pycck = 0;
522 if (pcmyk) *pcmyk = 0;
523 if (!filename)
524 return ERROR_INT("filename not defined", __func__, 1);
525 if (!pw && !ph && !pspp && !pycck && !pcmyk)
526 return ERROR_INT("no results requested", __func__, 1);
527
528 if ((fp = fopenReadStream(filename)) == NULL)
529 return ERROR_INT_1("image file not found", filename, __func__, 1);
530 ret = freadHeaderJpeg(fp, pw, ph, pspp, pycck, pcmyk);
531 fclose(fp);
532 return ret;
533 }
534
535
536 /*!
537 * \brief freadHeaderJpeg()
538 *
539 * \param[in] fp file stream
540 * \param[out] pw [optional]
541 * \param[out] ph [optional]
542 * \param[out] pspp [optional] samples/pixel
543 * \param[out] pycck [optional] 1 if ycck color space; 0 otherwise
544 * \param[out] pcmyk [optional] 1 if cmyk color space; 0 otherwise
545 * \return 0 if OK, 1 on error
546 */
547 l_ok
548 freadHeaderJpeg(FILE *fp,
549 l_int32 *pw,
550 l_int32 *ph,
551 l_int32 *pspp,
552 l_int32 *pycck,
553 l_int32 *pcmyk)
554 {
555 l_int32 spp, w, h;
556 struct jpeg_decompress_struct cinfo = { 0 };
557 struct jpeg_error_mgr jerr = { 0 };
558 jmp_buf jmpbuf; /* must be local to the function */
559
560 if (pw) *pw = 0;
561 if (ph) *ph = 0;
562 if (pspp) *pspp = 0;
563 if (pycck) *pycck = 0;
564 if (pcmyk) *pcmyk = 0;
565 if (!fp)
566 return ERROR_INT("stream not defined", __func__, 1);
567 if (!pw && !ph && !pspp && !pycck && !pcmyk)
568 return ERROR_INT("no results requested", __func__, 1);
569
570 rewind(fp);
571
572 /* Modify the jpeg error handling to catch fatal errors */
573 cinfo.err = jpeg_std_error(&jerr);
574 cinfo.client_data = (void *)&jmpbuf;
575 jerr.error_exit = jpeg_error_catch_all_1;
576 if (setjmp(jmpbuf))
577 return ERROR_INT("internal jpeg error", __func__, 1);
578
579 /* Initialize the jpeg structs for reading the header */
580 jpeg_create_decompress(&cinfo);
581 jpeg_stdio_src(&cinfo, fp);
582 jpeg_read_header(&cinfo, TRUE);
583 jpeg_calc_output_dimensions(&cinfo);
584 spp = cinfo.out_color_components;
585 w = cinfo.output_width;
586 h = cinfo.output_height;
587 if (w < 1 || h < 1 || spp < 1 || spp > 4) {
588 jpeg_destroy_decompress(&cinfo);
589 rewind(fp);
590 return ERROR_INT("bad jpeg image parameters", __func__, 1);
591 }
592
593 if (pspp) *pspp = spp;
594 if (pw) *pw = cinfo.output_width;
595 if (ph) *ph = cinfo.output_height;
596 if (pycck) *pycck =
597 (cinfo.jpeg_color_space == JCS_YCCK && spp == 4);
598 if (pcmyk) *pcmyk =
599 (cinfo.jpeg_color_space == JCS_CMYK && spp == 4);
600
601 jpeg_destroy_decompress(&cinfo);
602 rewind(fp);
603 return 0;
604 }
605
606
607 /*
608 * \brief fgetJpegResolution()
609 *
610 * \param[in] fp file stream
611 * \param[out] pxres, pyres resolutions
612 * \return 0 if OK; 1 on error
613 *
614 * <pre>
615 * Notes:
616 * (1) If neither resolution field is set, this is not an error;
617 * the returned resolution values are 0 (designating 'unknown').
618 * (2) Side-effect: this rewinds the stream.
619 * </pre>
620 */
621 l_int32
622 fgetJpegResolution(FILE *fp,
623 l_int32 *pxres,
624 l_int32 *pyres)
625 {
626 struct jpeg_decompress_struct cinfo = { 0 };
627 struct jpeg_error_mgr jerr = { 0 };
628 jmp_buf jmpbuf; /* must be local to the function */
629
630 if (pxres) *pxres = 0;
631 if (pyres) *pyres = 0;
632 if (!pxres || !pyres)
633 return ERROR_INT("&xres and &yres not both defined", __func__, 1);
634 if (!fp)
635 return ERROR_INT("stream not opened", __func__, 1);
636
637 rewind(fp);
638
639 /* Modify the jpeg error handling to catch fatal errors */
640 cinfo.err = jpeg_std_error(&jerr);
641 cinfo.client_data = (void *)&jmpbuf;
642 jerr.error_exit = jpeg_error_catch_all_1;
643 if (setjmp(jmpbuf))
644 return ERROR_INT("internal jpeg error", __func__, 1);
645
646 /* Initialize the jpeg structs for reading the header */
647 jpeg_create_decompress(&cinfo);
648 jpeg_stdio_src(&cinfo, fp);
649 jpeg_read_header(&cinfo, TRUE);
650
651 /* It is common for the input resolution to be omitted from the
652 * jpeg file. If density_unit is not 1 or 2, simply return 0. */
653 if (cinfo.density_unit == 1) { /* pixels/inch */
654 *pxres = cinfo.X_density;
655 *pyres = cinfo.Y_density;
656 } else if (cinfo.density_unit == 2) { /* pixels/cm */
657 *pxres = (l_int32)((l_float32)cinfo.X_density * 2.54 + 0.5);
658 *pyres = (l_int32)((l_float32)cinfo.Y_density * 2.54 + 0.5);
659 }
660
661 jpeg_destroy_decompress(&cinfo);
662 rewind(fp);
663 return 0;
664 }
665
666
667 /*
668 * \brief fgetJpegComment()
669 *
670 * \param[in] fp file stream opened for read
671 * \param[out] pcomment comment
672 * \return 0 if OK; 1 on error
673 *
674 * <pre>
675 * Notes:
676 * (1) Side-effect: this rewinds the stream.
677 * </pre>
678 */
679 l_int32
680 fgetJpegComment(FILE *fp,
681 l_uint8 **pcomment)
682 {
683 struct jpeg_decompress_struct cinfo = { 0 };
684 struct jpeg_error_mgr jerr = { 0 };
685 struct callback_data cb_data = { 0 }; /* contains local jmp_buf */
686
687 if (!pcomment)
688 return ERROR_INT("&comment not defined", __func__, 1);
689 *pcomment = NULL;
690 if (!fp)
691 return ERROR_INT("stream not opened", __func__, 1);
692
693 rewind(fp);
694
695 /* Modify the jpeg error handling to catch fatal errors */
696 cinfo.err = jpeg_std_error(&jerr);
697 jerr.error_exit = jpeg_error_catch_all_2;
698 cb_data.comment = NULL;
699 cinfo.client_data = (void *)&cb_data;
700 if (setjmp(cb_data.jmpbuf)) {
701 LEPT_FREE(cb_data.comment);
702 return ERROR_INT("internal jpeg error", __func__, 1);
703 }
704
705 /* Initialize the jpeg structs for reading the header */
706 jpeg_create_decompress(&cinfo);
707 jpeg_set_marker_processor(&cinfo, JPEG_COM, jpeg_comment_callback);
708 jpeg_stdio_src(&cinfo, fp);
709 jpeg_read_header(&cinfo, TRUE);
710
711 /* Save the result */
712 *pcomment = cb_data.comment;
713 jpeg_destroy_decompress(&cinfo);
714 rewind(fp);
715 return 0;
716 }
717
718
719 /*---------------------------------------------------------------------*
720 * Writing Jpeg *
721 *---------------------------------------------------------------------*/
722 /*!
723 * \brief pixWriteJpeg()
724 *
725 * \param[in] filename
726 * \param[in] pix any depth; cmap is OK
727 * \param[in] quality 1 - 100; 75 is default
728 * \param[in] progressive 0 for baseline sequential; 1 for progressive
729 * \return 0 if OK; 1 on error
730 */
731 l_ok
732 pixWriteJpeg(const char *filename,
733 PIX *pix,
734 l_int32 quality,
735 l_int32 progressive)
736 {
737 FILE *fp;
738
739 if (!pix)
740 return ERROR_INT("pix not defined", __func__, 1);
741 if (!filename)
742 return ERROR_INT("filename not defined", __func__, 1);
743
744 if ((fp = fopenWriteStream(filename, "wb+")) == NULL)
745 return ERROR_INT_1("stream not opened", filename, __func__, 1);
746
747 if (pixWriteStreamJpeg(fp, pix, quality, progressive)) {
748 fclose(fp);
749 return ERROR_INT_1("pix not written to stream", filename, __func__, 1);
750 }
751
752 fclose(fp);
753 return 0;
754 }
755
756
757 /*!
758 * \brief pixWriteStreamJpeg()
759 *
760 * \param[in] fp file stream
761 * \param[in] pixs any depth; cmap is OK
762 * \param[in] quality 1 - 100; 75 is default value; 0 is also default
763 * \param[in] progressive 0 for baseline sequential; 1 for progressive
764 * \return 0 if OK, 1 on error
765 *
766 * <pre>
767 * Notes:
768 * (1) Progressive encoding gives better compression, at the
769 * expense of slower encoding and decoding.
770 * (2) Standard chroma subsampling is 2x2 on both the U and V
771 * channels. For highest quality, use no subsampling; this
772 * option is set by pixSetChromaSampling(pix, 0).
773 * (3) The only valid pixel depths in leptonica are 1, 2, 4, 8, 16
774 * and 32 bpp. However, it is possible, and in some cases desirable,
775 * to write out a jpeg file using an rgb pix that has 24 bpp.
776 * This can be created by appending the raster data for a 24 bpp
777 * image (with proper scanline padding) directly to a 24 bpp
778 * pix that was created without a data array.
779 * (4) There are two compression paths in this function:
780 * * Grayscale image, no colormap: compress as 8 bpp image.
781 * * rgb full color image: copy each line into the color
782 * line buffer, and compress as three 8 bpp images.
783 * (5) Under the covers, the jpeg library transforms rgb to a
784 * luminance-chromaticity triple, each component of which is
785 * also 8 bits, and compresses that. It uses 2 Huffman tables,
786 * a higher resolution one (with more quantization levels)
787 * for luminosity and a lower resolution one for the chromas.
788 * </pre>
789 */
790 l_ok
791 pixWriteStreamJpeg(FILE *fp,
792 PIX *pixs,
793 l_int32 quality,
794 l_int32 progressive)
795 {
796 l_int32 xres, yres;
797 l_int32 i, j, k;
798 l_int32 w, h, d, wpl, spp, colorflag, rowsamples;
799 l_uint32 *ppixel, *line, *data;
800 JSAMPROW rowbuffer;
801 PIX *pix;
802 struct jpeg_compress_struct cinfo = { 0 };
803 struct jpeg_error_mgr jerr = { 0 };
804 char *text;
805 jmp_buf jmpbuf; /* must be local to the function */
806
807 if (!fp)
808 return ERROR_INT("stream not open", __func__, 1);
809 if (!pixs)
810 return ERROR_INT("pixs not defined", __func__, 1);
811 if (quality <= 0) quality = 75; /* default */
812 if (quality > 100) {
813 L_ERROR("invalid jpeg quality; setting to 75\n", __func__);
814 quality = 75;
815 }
816
817 /* If necessary, convert the pix so that it can be jpeg compressed.
818 * The colormap is removed based on the source, so if the colormap
819 * has only gray colors, the image will be compressed with spp = 1. */
820 pixGetDimensions(pixs, &w, &h, &d);
821 pix = NULL;
822 if (pixGetColormap(pixs) != NULL) {
823 L_INFO("removing colormap; may be better to compress losslessly\n",
824 __func__);
825 pix = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
826 } else if (d >= 8 && d != 16) { /* normal case; no rewrite */
827 pix = pixClone(pixs);
828 } else if (d < 8 || d == 16) {
829 L_INFO("converting from %d to 8 bpp\n", __func__, d);
830 pix = pixConvertTo8(pixs, 0); /* 8 bpp, no cmap */
831 } else {
832 L_ERROR("unknown pix type with d = %d and no cmap\n", __func__, d);
833 return 1;
834 }
835 if (!pix)
836 return ERROR_INT("pix not made", __func__, 1);
837 pixSetPadBits(pix, 0);
838
839 rewind(fp);
840 rowbuffer = NULL;
841
842 /* Modify the jpeg error handling to catch fatal errors */
843 cinfo.err = jpeg_std_error(&jerr);
844 cinfo.client_data = (void *)&jmpbuf;
845 jerr.error_exit = jpeg_error_catch_all_1;
846 if (setjmp(jmpbuf)) {
847 LEPT_FREE(rowbuffer);
848 pixDestroy(&pix);
849 return ERROR_INT("internal jpeg error", __func__, 1);
850 }
851
852 /* Initialize the jpeg structs for compression */
853 jpeg_create_compress(&cinfo);
854 jpeg_stdio_dest(&cinfo, fp);
855 cinfo.image_width = w;
856 cinfo.image_height = h;
857
858 /* Set the color space and number of components */
859 d = pixGetDepth(pix);
860 if (d == 8) {
861 colorflag = 0; /* 8 bpp grayscale; no cmap */
862 cinfo.input_components = 1;
863 cinfo.in_color_space = JCS_GRAYSCALE;
864 } else { /* d == 32 || d == 24 */
865 colorflag = 1; /* rgb */
866 cinfo.input_components = 3;
867 cinfo.in_color_space = JCS_RGB;
868 }
869
870 jpeg_set_defaults(&cinfo);
871
872 /* Setting optimize_coding to TRUE seems to improve compression
873 * by approx 2-4 percent, and increases comp time by approx 20%. */
874 cinfo.optimize_coding = FALSE;
875
876 /* Set resolution in pixels/in (density_unit: 1 = in, 2 = cm) */
877 xres = pixGetXRes(pix);
878 yres = pixGetYRes(pix);
879 if ((xres != 0) && (yres != 0)) {
880 cinfo.density_unit = 1; /* designates pixels per inch */
881 cinfo.X_density = xres;
882 cinfo.Y_density = yres;
883 }
884
885 /* Set the quality and progressive parameters */
886 jpeg_set_quality(&cinfo, quality, TRUE);
887 if (progressive)
888 jpeg_simple_progression(&cinfo);
889
890 /* Set the chroma subsampling parameters. This is done in
891 * YUV color space. The Y (intensity) channel is never subsampled.
892 * The standard subsampling is 2x2 on both the U and V channels.
893 * Notation on this is confusing. For a nice illustrations, see
894 * http://en.wikipedia.org/wiki/Chroma_subsampling
895 * The standard subsampling is written as 4:2:0.
896 * We allow high quality where there is no subsampling on the
897 * chroma channels: denoted as 4:4:4. */
898 if (pixs->special == L_NO_CHROMA_SAMPLING_JPEG) {
899 cinfo.comp_info[0].h_samp_factor = 1;
900 cinfo.comp_info[0].v_samp_factor = 1;
901 cinfo.comp_info[1].h_samp_factor = 1;
902 cinfo.comp_info[1].v_samp_factor = 1;
903 cinfo.comp_info[2].h_samp_factor = 1;
904 cinfo.comp_info[2].v_samp_factor = 1;
905 }
906
907 jpeg_start_compress(&cinfo, TRUE);
908
909 /* Cap the text the length limit, 65533, for JPEG_COM payload.
910 * Just to be safe, subtract 100 to cover the Adobe name space. */
911 if ((text = pixGetText(pix)) != NULL) {
912 if (strlen(text) > 65433) {
913 L_WARNING("text is %zu bytes; clipping to 65433\n",
914 __func__, strlen(text));
915 text[65433] = '\0';
916 }
917 jpeg_write_marker(&cinfo, JPEG_COM, (const JOCTET *)text, strlen(text));
918 }
919
920 /* Allocate row buffer */
921 spp = cinfo.input_components;
922 rowsamples = spp * w;
923 if ((rowbuffer = (JSAMPROW)LEPT_CALLOC(sizeof(JSAMPLE), rowsamples))
924 == NULL) {
925 pixDestroy(&pix);
926 return ERROR_INT("calloc fail for rowbuffer", __func__, 1);
927 }
928
929 data = pixGetData(pix);
930 wpl = pixGetWpl(pix);
931 for (i = 0; i < h; i++) {
932 line = data + i * wpl;
933 if (colorflag == 0) { /* 8 bpp gray */
934 for (j = 0; j < w; j++)
935 rowbuffer[j] = GET_DATA_BYTE(line, j);
936 } else { /* colorflag == 1 */
937 if (d == 24) { /* See note 3 above; special case of 24 bpp rgb */
938 jpeg_write_scanlines(&cinfo, (JSAMPROW *)&line, 1);
939 } else { /* standard 32 bpp rgb */
940 ppixel = line;
941 for (j = k = 0; j < w; j++) {
942 rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
943 rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
944 rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
945 ppixel++;
946 }
947 }
948 }
949 if (d != 24)
950 jpeg_write_scanlines(&cinfo, &rowbuffer, 1);
951 }
952 jpeg_finish_compress(&cinfo);
953
954 pixDestroy(&pix);
955 LEPT_FREE(rowbuffer);
956 rowbuffer = NULL;
957 jpeg_destroy_compress(&cinfo);
958 return 0;
959 }
960
961
962 /*---------------------------------------------------------------------*
963 * Read/write to memory *
964 *---------------------------------------------------------------------*/
965
966 /*!
967 * \brief pixReadMemJpeg()
968 *
969 * \param[in] data const; jpeg-encoded
970 * \param[in] size of data
971 * \param[in] cmflag colormap flag 0 means return RGB image if color;
972 * 1 means create a colormap and return
973 * an 8 bpp colormapped image if color
974 * \param[in] reduction scaling factor: 1, 2, 4 or 8
975 * \param[out] pnwarn [optional] number of warnings
976 * \param[in] hint a bitwise OR of L_JPEG_* values; 0 for default
977 * \return pix, or NULL on error
978 *
979 * <pre>
980 * Notes:
981 * (1) The %size byte of %data must be a null character.
982 * (2) The only hint flag so far is L_JPEG_READ_LUMINANCE,
983 * given in the enum in imageio.h.
984 * (3) See pixReadJpeg() for usage.
985 * </pre>
986 */
987 PIX *
988 pixReadMemJpeg(const l_uint8 *data,
989 size_t size,
990 l_int32 cmflag,
991 l_int32 reduction,
992 l_int32 *pnwarn,
993 l_int32 hint)
994 {
995 l_int32 ret;
996 l_uint8 *comment;
997 FILE *fp;
998 PIX *pix;
999
1000 if (pnwarn) *pnwarn = 0;
1001 if (!data)
1002 return (PIX *)ERROR_PTR("data not defined", __func__, NULL);
1003
1004 if ((fp = fopenReadFromMemory(data, size)) == NULL)
1005 return (PIX *)ERROR_PTR("stream not opened", __func__, NULL);
1006 pix = pixReadStreamJpeg(fp, cmflag, reduction, pnwarn, hint);
1007 if (pix) {
1008 ret = fgetJpegComment(fp, &comment);
1009 if (!ret && comment) {
1010 pixSetText(pix, (char *)comment);
1011 LEPT_FREE(comment);
1012 }
1013 }
1014 fclose(fp);
1015 if (!pix) L_ERROR("pix not read\n", __func__);
1016 return pix;
1017 }
1018
1019
1020 /*!
1021 * \brief readHeaderMemJpeg()
1022 *
1023 * \param[in] data const; jpeg-encoded
1024 * \param[in] size of data
1025 * \param[out] pw [optional] width
1026 * \param[out] ph [optional] height
1027 * \param[out] pspp [optional] samples/pixel
1028 * \param[out] pycck [optional] 1 if ycck color space; 0 otherwise
1029 * \param[out] pcmyk [optional] 1 if cmyk color space; 0 otherwise
1030 * \return 0 if OK, 1 on error
1031 */
1032 l_ok
1033 readHeaderMemJpeg(const l_uint8 *data,
1034 size_t size,
1035 l_int32 *pw,
1036 l_int32 *ph,
1037 l_int32 *pspp,
1038 l_int32 *pycck,
1039 l_int32 *pcmyk)
1040 {
1041 l_int32 ret;
1042 FILE *fp;
1043
1044 if (pw) *pw = 0;
1045 if (ph) *ph = 0;
1046 if (pspp) *pspp = 0;
1047 if (pycck) *pycck = 0;
1048 if (pcmyk) *pcmyk = 0;
1049 if (!data)
1050 return ERROR_INT("data not defined", __func__, 1);
1051 if (!pw && !ph && !pspp && !pycck && !pcmyk)
1052 return ERROR_INT("no results requested", __func__, 1);
1053
1054 if ((fp = fopenReadFromMemory(data, size)) == NULL)
1055 return ERROR_INT("stream not opened", __func__, 1);
1056 ret = freadHeaderJpeg(fp, pw, ph, pspp, pycck, pcmyk);
1057 fclose(fp);
1058 return ret;
1059 }
1060
1061
1062 /*!
1063 * \brief readResolutionMemJpeg()
1064 *
1065 * \param[in] data const; jpeg-encoded
1066 * \param[in] size of data
1067 * \param[out] pxres [optional]
1068 * \param[out] pyres [optional]
1069 * \return 0 if OK, 1 on error
1070 */
1071 l_ok
1072 readResolutionMemJpeg(const l_uint8 *data,
1073 size_t size,
1074 l_int32 *pxres,
1075 l_int32 *pyres)
1076 {
1077 l_int32 ret;
1078 FILE *fp;
1079
1080 if (pxres) *pxres = 0;
1081 if (pyres) *pyres = 0;
1082 if (!data)
1083 return ERROR_INT("data not defined", __func__, 1);
1084 if (!pxres && !pyres)
1085 return ERROR_INT("no results requested", __func__, 1);
1086
1087 if ((fp = fopenReadFromMemory(data, size)) == NULL)
1088 return ERROR_INT("stream not opened", __func__, 1);
1089 ret = fgetJpegResolution(fp, pxres, pyres);
1090 fclose(fp);
1091 return ret;
1092 }
1093
1094
1095 /*!
1096 * \brief pixWriteMemJpeg()
1097 *
1098 * \param[out] pdata data of jpeg compressed image
1099 * \param[out] psize size of returned data
1100 * \param[in] pix any depth; cmap is OK
1101 * \param[in] quality 1 - 100; 75 is default value; 0 is also default
1102 * \param[in] progressive 0 for baseline sequential; 1 for progressive
1103 * \return 0 if OK, 1 on error
1104 *
1105 * <pre>
1106 * Notes:
1107 * (1) See pixWriteStreamJpeg() for usage. This version writes to
1108 * memory instead of to a file stream.
1109 * </pre>
1110 */
1111 l_ok
1112 pixWriteMemJpeg(l_uint8 **pdata,
1113 size_t *psize,
1114 PIX *pix,
1115 l_int32 quality,
1116 l_int32 progressive)
1117 {
1118 l_int32 ret;
1119 FILE *fp;
1120
1121 if (pdata) *pdata = NULL;
1122 if (psize) *psize = 0;
1123 if (!pdata)
1124 return ERROR_INT("&data not defined", __func__, 1 );
1125 if (!psize)
1126 return ERROR_INT("&size not defined", __func__, 1 );
1127 if (!pix)
1128 return ERROR_INT("&pix not defined", __func__, 1 );
1129
1130 #if HAVE_FMEMOPEN
1131 if ((fp = open_memstream((char **)pdata, psize)) == NULL)
1132 return ERROR_INT("stream not opened", __func__, 1);
1133 ret = pixWriteStreamJpeg(fp, pix, quality, progressive);
1134 fputc('\0', fp);
1135 fclose(fp);
1136 if (*psize > 0) *psize = *psize - 1;
1137 #else
1138 L_INFO("no fmemopen API --> work-around: write to temp file\n", __func__);
1139 #ifdef _WIN32
1140 if ((fp = fopenWriteWinTempfile()) == NULL)
1141 return ERROR_INT("tmpfile stream not opened", __func__, 1);
1142 #else
1143 if ((fp = tmpfile()) == NULL)
1144 return ERROR_INT("tmpfile stream not opened", __func__, 1);
1145 #endif /* _WIN32 */
1146 ret = pixWriteStreamJpeg(fp, pix, quality, progressive);
1147 rewind(fp);
1148 *pdata = l_binaryReadStream(fp, psize);
1149 fclose(fp);
1150 #endif /* HAVE_FMEMOPEN */
1151 return ret;
1152 }
1153
1154
1155 /*---------------------------------------------------------------------*
1156 * Setting special flag for chroma sampling on write *
1157 *---------------------------------------------------------------------*/
1158 /*!
1159 * \brief pixSetChromaSampling()
1160 *
1161 * \param[in] pix
1162 * \param[in] sampling 1 for subsampling; 0 for no subsampling
1163 * \return 0 if OK, 1 on error
1164 *
1165 * <pre>
1166 * Notes:
1167 * (1) The default is for 2x2 chroma subsampling because the files are
1168 * considerably smaller and the appearance is typically satisfactory.
1169 * To get full resolution output in the chroma channels for
1170 * jpeg writing, call this with %sampling == 0.
1171 * </pre>
1172 */
1173 l_ok
1174 pixSetChromaSampling(PIX *pix,
1175 l_int32 sampling)
1176 {
1177 if (!pix)
1178 return ERROR_INT("pix not defined", __func__, 1 );
1179 if (sampling)
1180 pixSetSpecial(pix, 0); /* default */
1181 else
1182 pixSetSpecial(pix, L_NO_CHROMA_SAMPLING_JPEG);
1183 return 0;
1184 }
1185
1186
1187 /*---------------------------------------------------------------------*
1188 * Static system helpers *
1189 *---------------------------------------------------------------------*/
1190 /*!
1191 * \brief jpeg_error_catch_all_1()
1192 *
1193 * Notes:
1194 * (1) The default jpeg error_exit() kills the process, but we
1195 * never want a call to leptonica to kill a process. If you
1196 * do want this behavior, remove the calls to these error handlers.
1197 * (2) This is used where cinfo->client_data holds only jmpbuf.
1198 */
1199 static void
1200 jpeg_error_catch_all_1(j_common_ptr cinfo)
1201 {
1202 jmp_buf *pjmpbuf = (jmp_buf *)cinfo->client_data;
1203 (*cinfo->err->output_message) (cinfo);
1204 jpeg_destroy(cinfo);
1205 longjmp(*pjmpbuf, 1);
1206 }
1207
1208 /*!
1209 * \brief jpeg_error_catch_all_2()
1210 *
1211 * Notes:
1212 * (1) This is used where cinfo->client_data needs to hold both
1213 * the jmpbuf and the jpeg comment data.
1214 * (2) On error, the comment data will be freed by the caller.
1215 */
1216 static void
1217 jpeg_error_catch_all_2(j_common_ptr cinfo)
1218 {
1219 struct callback_data *pcb_data;
1220
1221 pcb_data = (struct callback_data *)cinfo->client_data;
1222 (*cinfo->err->output_message) (cinfo);
1223 jpeg_destroy(cinfo);
1224 longjmp(pcb_data->jmpbuf, 1);
1225 }
1226
1227 /* This function was borrowed from libjpeg */
1228 static l_uint8
1229 jpeg_getc(j_decompress_ptr cinfo)
1230 {
1231 struct jpeg_source_mgr *datasrc;
1232
1233 datasrc = cinfo->src;
1234 if (datasrc->bytes_in_buffer == 0) {
1235 if (! (*datasrc->fill_input_buffer) (cinfo)) {
1236 return 0;
1237 }
1238 }
1239 datasrc->bytes_in_buffer--;
1240 return GETJOCTET(*datasrc->next_input_byte++);
1241 }
1242
1243 /*!
1244 * \brief jpeg_comment_callback()
1245 *
1246 * Notes:
1247 * (1) This is used to read the jpeg comment (JPEG_COM).
1248 * See the note above the declaration for why it returns
1249 * a "boolean".
1250 */
1251 static boolean
1252 jpeg_comment_callback(j_decompress_ptr cinfo)
1253 {
1254 l_int32 length, i;
1255 l_uint8 *comment;
1256 struct callback_data *pcb_data;
1257
1258 /* Get the size of the comment */
1259 length = jpeg_getc(cinfo) << 8;
1260 length += jpeg_getc(cinfo);
1261 length -= 2;
1262 if (length <= 0)
1263 return 1;
1264
1265 /* Extract the comment from the file */
1266 if ((comment = (l_uint8 *)LEPT_CALLOC(length + 1, sizeof(l_uint8))) == NULL)
1267 return 0;
1268 for (i = 0; i < length; i++)
1269 comment[i] = jpeg_getc(cinfo);
1270
1271 /* Save the comment and return */
1272 pcb_data = (struct callback_data *)cinfo->client_data;
1273 if (pcb_data->comment) { /* clear before overwriting previous comment */
1274 LEPT_FREE(pcb_data->comment);
1275 pcb_data->comment = NULL;
1276 }
1277 pcb_data->comment = comment;
1278 return 1;
1279 }
1280
1281 /* --------------------------------------------*/
1282 #endif /* HAVE_LIBJPEG */
1283 /* --------------------------------------------*/