/src/leptonica/src/writefile.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*====================================================================* |
2 | | - Copyright (C) 2001-2016 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 | | * writefile.c |
29 | | * |
30 | | * Set jpeg quality for pixWrite() and pixWriteMem() |
31 | | * l_int32 l_jpegSetQuality() |
32 | | * |
33 | | * Set global variable LeptDebugOK for writing to named temp files |
34 | | * l_int32 setLeptDebugOK() |
35 | | * |
36 | | * High-level procedures for writing images to file: |
37 | | * l_int32 pixaWriteFiles() |
38 | | * l_int32 pixWriteDebug() |
39 | | * l_int32 pixWrite() |
40 | | * l_int32 pixWriteAutoFormat() |
41 | | * l_int32 pixWriteStream() |
42 | | * l_int32 pixWriteImpliedFormat() |
43 | | * |
44 | | * Selection of output format if default is requested |
45 | | * l_int32 pixChooseOutputFormat() |
46 | | * l_int32 getImpliedFileFormat() |
47 | | * l_int32 getFormatFromExtension() |
48 | | * l_int32 pixGetAutoFormat() |
49 | | * const char *getFormatExtension() |
50 | | * |
51 | | * Write to memory |
52 | | * l_int32 pixWriteMem() |
53 | | * |
54 | | * Image display for debugging |
55 | | * l_int32 l_fileDisplay() |
56 | | * l_int32 pixDisplay() |
57 | | * l_int32 pixDisplayWithTitle() |
58 | | * PIX *pixMakeColorSquare() |
59 | | * void l_chooseDisplayProg() |
60 | | * |
61 | | * Change format for missing library |
62 | | * void changeFormatForMissingLib() |
63 | | * |
64 | | * Nonfunctional stub of pix output for debugging |
65 | | * l_int32 pixDisplayWrite() |
66 | | * |
67 | | * Supported file formats: |
68 | | * (1) Writing is supported without any external libraries: |
69 | | * bmp |
70 | | * pnm (including pbm, pgm, etc) |
71 | | * spix (raw serialized) |
72 | | * (2) Writing is supported with installation of external libraries: |
73 | | * png |
74 | | * jpg (standard jfif version) |
75 | | * tiff (including most varieties of compression) |
76 | | * gif |
77 | | * webp |
78 | | * jp2 (jpeg2000) |
79 | | * (3) Writing is supported through special interfaces: |
80 | | * ps (PostScript, in psio1.c, psio2.c): |
81 | | * level 1 (uncompressed) |
82 | | * level 2 (g4 and dct encoding: requires tiff, jpg) |
83 | | * level 3 (g4, dct and flate encoding: requires tiff, jpg, zlib) |
84 | | * pdf (PDF, in pdfio.c): |
85 | | * level 1 (g4 and dct encoding: requires tiff, jpg) |
86 | | * level 2 (g4, dct and flate encoding: requires tiff, jpg, zlib) |
87 | | */ |
88 | | |
89 | | #ifdef HAVE_CONFIG_H |
90 | | #include <config_auto.h> |
91 | | #endif /* HAVE_CONFIG_H */ |
92 | | |
93 | | #include <string.h> |
94 | | #include "allheaders.h" |
95 | | |
96 | | /* Set defaults for the display program (xv, xli, xzgv, open, irfanview) |
97 | | * that is invoked by pixDisplay() */ |
98 | | #ifdef _WIN32 |
99 | | static l_int32 var_DISPLAY_PROG = L_DISPLAY_WITH_IV; /* default */ |
100 | | #elif defined(__APPLE__) |
101 | | static l_int32 var_DISPLAY_PROG = L_DISPLAY_WITH_OPEN; /* default */ |
102 | | #else |
103 | | static l_int32 var_DISPLAY_PROG = L_DISPLAY_WITH_XZGV; /* default */ |
104 | | #endif /* _WIN32 */ |
105 | | |
106 | 0 | #define Bufsize 512 |
107 | | static const l_int32 MaxDisplayWidth = 1000; |
108 | | static const l_int32 MaxDisplayHeight = 800; |
109 | | static const l_int32 MaxSizeForPng = 200; |
110 | | |
111 | | /* PostScript output for printing */ |
112 | | static const l_float32 DefaultScaling = 1.0; |
113 | | |
114 | | /* Global array of image file format extension names. */ |
115 | | /* This is in 1-1 correspondence with format enum in imageio.h. */ |
116 | | /* The empty string at the end represents the serialized format, */ |
117 | | /* which has no recognizable extension name, but the array must */ |
118 | | /* be padded to agree with the format enum. */ |
119 | | /* (Note on 'const': The size of the array can't be defined 'const' */ |
120 | | /* because that makes it static. The 'const' in the definition of */ |
121 | | /* the array refers to the strings in the array; the ptr to the */ |
122 | | /* array is not const and can be used 'extern' in other files.) */ |
123 | | LEPT_DLL l_int32 NumImageFileFormatExtensions = 20; /* array size */ |
124 | | LEPT_DLL const char *ImageFileFormatExtensions[] = |
125 | | {"unknown", |
126 | | "bmp", |
127 | | "jpg", |
128 | | "png", |
129 | | "tif", |
130 | | "tif", |
131 | | "tif", |
132 | | "tif", |
133 | | "tif", |
134 | | "tif", |
135 | | "tif", |
136 | | "pnm", |
137 | | "ps", |
138 | | "gif", |
139 | | "jp2", |
140 | | "webp", |
141 | | "pdf", |
142 | | "tif", |
143 | | "default", |
144 | | ""}; |
145 | | |
146 | | /* Local map of image file name extension to output format. |
147 | | * Note that the extension string always includes a '.' */ |
148 | | struct ExtensionMap |
149 | | { |
150 | | char extension[16]; |
151 | | l_int32 format; |
152 | | }; |
153 | | static const struct ExtensionMap extension_map[] = |
154 | | { { ".bmp", IFF_BMP }, |
155 | | { ".jpg", IFF_JFIF_JPEG }, |
156 | | { ".jpeg", IFF_JFIF_JPEG }, |
157 | | { ".JPG", IFF_JFIF_JPEG }, |
158 | | { ".png", IFF_PNG }, |
159 | | { ".tif", IFF_TIFF }, |
160 | | { ".tiff", IFF_TIFF }, |
161 | | { ".tiffg4", IFF_TIFF_G4 }, |
162 | | { ".pbm", IFF_PNM }, |
163 | | { ".pgm", IFF_PNM }, |
164 | | { ".pnm", IFF_PNM }, |
165 | | { ".gif", IFF_GIF }, |
166 | | { ".jp2", IFF_JP2 }, |
167 | | { ".j2k", IFF_JP2 }, |
168 | | { ".ps", IFF_PS }, |
169 | | { ".pdf", IFF_LPDF }, |
170 | | { ".webp", IFF_WEBP } }; |
171 | | |
172 | | |
173 | | /*---------------------------------------------------------------------* |
174 | | * Set jpeg quality for pixWrite() and pixWriteMem() * |
175 | | *---------------------------------------------------------------------*/ |
176 | | /* Parameter that controls jpeg quality for high-level calls. */ |
177 | | static l_int32 var_JPEG_QUALITY = 75; /* default */ |
178 | | |
179 | | /*! |
180 | | * \brief l_jpegSetQuality() |
181 | | * |
182 | | * \param[in] new_quality 1 - 100; 75 is default; 0 defaults to 75 |
183 | | * \return prev previous quality |
184 | | * |
185 | | * <pre> |
186 | | * Notes: |
187 | | * (1) This variable is used in pixWriteStream() and pixWriteMem(), |
188 | | * to control the jpeg quality. The default is 75. |
189 | | * (2) It returns the previous quality, so for example: |
190 | | * l_int32 prev = l_jpegSetQuality(85); //sets to 85 |
191 | | * pixWriteStream(...); |
192 | | * l_jpegSetQuality(prev); // resets to previous value |
193 | | * (3) On error, logs a message and does not change the variable. |
194 | | */ |
195 | | l_int32 |
196 | | l_jpegSetQuality(l_int32 new_quality) |
197 | 0 | { |
198 | 0 | l_int32 prevq, newq; |
199 | |
|
200 | 0 | prevq = var_JPEG_QUALITY; |
201 | 0 | newq = (new_quality == 0) ? 75 : new_quality; |
202 | 0 | if (newq < 1 || newq > 100) |
203 | 0 | L_ERROR("invalid jpeg quality; unchanged\n", __func__); |
204 | 0 | else |
205 | 0 | var_JPEG_QUALITY = newq; |
206 | 0 | return prevq; |
207 | 0 | } |
208 | | |
209 | | |
210 | | /*----------------------------------------------------------------------* |
211 | | * Set global variable LeptDebugOK for writing to named temp files * |
212 | | *----------------------------------------------------------------------*/ |
213 | | LEPT_DLL l_int32 LeptDebugOK = 0; /* default value */ |
214 | | /*! |
215 | | * \brief setLeptDebugOK() |
216 | | * |
217 | | * \param[in] allow TRUE (1) or FALSE (0) |
218 | | * \return void |
219 | | * |
220 | | * <pre> |
221 | | * Notes: |
222 | | * (1) This sets or clears the global variable LeptDebugOK, to |
223 | | * control writing files in a temp directory with names that |
224 | | * are compiled in. |
225 | | * (2) The default in the library distribution is 0. Call with |
226 | | * %allow = 1 for development and debugging. |
227 | | */ |
228 | | void |
229 | | setLeptDebugOK(l_int32 allow) |
230 | 0 | { |
231 | 0 | if (allow != 0) allow = 1; |
232 | 0 | LeptDebugOK = allow; |
233 | 0 | } |
234 | | |
235 | | |
236 | | /*---------------------------------------------------------------------* |
237 | | * Top-level procedures for writing images to file * |
238 | | *---------------------------------------------------------------------*/ |
239 | | /*! |
240 | | * \brief pixaWriteFiles() |
241 | | * |
242 | | * \param[in] rootname |
243 | | * \param[in] pixa |
244 | | * \param[in] format defined in imageio.h; see notes for default |
245 | | * \return 0 if OK; 1 on error |
246 | | * |
247 | | * <pre> |
248 | | * Notes: |
249 | | * (1) Use %format = IFF_DEFAULT to decide the output format |
250 | | * individually for each pix. |
251 | | * </pre> |
252 | | */ |
253 | | l_ok |
254 | | pixaWriteFiles(const char *rootname, |
255 | | PIXA *pixa, |
256 | | l_int32 format) |
257 | 0 | { |
258 | 0 | char bigbuf[Bufsize]; |
259 | 0 | l_int32 i, n, pixformat; |
260 | 0 | PIX *pix; |
261 | |
|
262 | 0 | if (!rootname) |
263 | 0 | return ERROR_INT("rootname not defined", __func__, 1); |
264 | 0 | if (!pixa) |
265 | 0 | return ERROR_INT("pixa not defined", __func__, 1); |
266 | 0 | if (format < 0 || format == IFF_UNKNOWN || |
267 | 0 | format >= NumImageFileFormatExtensions) |
268 | 0 | return ERROR_INT("invalid format", __func__, 1); |
269 | | |
270 | 0 | n = pixaGetCount(pixa); |
271 | 0 | for (i = 0; i < n; i++) { |
272 | 0 | pix = pixaGetPix(pixa, i, L_CLONE); |
273 | 0 | if (format == IFF_DEFAULT) |
274 | 0 | pixformat = pixChooseOutputFormat(pix); |
275 | 0 | else |
276 | 0 | pixformat = format; |
277 | 0 | snprintf(bigbuf, Bufsize, "%s%03d.%s", rootname, i, |
278 | 0 | ImageFileFormatExtensions[pixformat]); |
279 | 0 | pixWrite(bigbuf, pix, pixformat); |
280 | 0 | pixDestroy(&pix); |
281 | 0 | } |
282 | |
|
283 | 0 | return 0; |
284 | 0 | } |
285 | | |
286 | | |
287 | | /*! |
288 | | * \brief pixWriteDebug() |
289 | | * |
290 | | * \param[in] fname |
291 | | * \param[in] pix |
292 | | * \param[in] format defined in imageio.h |
293 | | * \return 0 if OK; 1 on error |
294 | | * |
295 | | * <pre> |
296 | | * Notes: |
297 | | * (1) Debug version, intended for use in the library when writing |
298 | | * to files in a temp directory with names that are compiled in. |
299 | | * This is used instead of pixWrite() for all such library calls. |
300 | | * (2) The global variable LeptDebugOK defaults to 0, and can be set |
301 | | * or cleared by the function setLeptDebugOK(). |
302 | | * </pre> |
303 | | */ |
304 | | l_ok |
305 | | pixWriteDebug(const char *fname, |
306 | | PIX *pix, |
307 | | l_int32 format) |
308 | 0 | { |
309 | 0 | if (LeptDebugOK) { |
310 | 0 | return pixWrite(fname, pix, format); |
311 | 0 | } else { |
312 | 0 | L_INFO("write to named temp file %s is disabled\n", __func__, fname); |
313 | 0 | return 0; |
314 | 0 | } |
315 | 0 | } |
316 | | |
317 | | |
318 | | /*! |
319 | | * \brief pixWrite() |
320 | | * |
321 | | * \param[in] fname |
322 | | * \param[in] pix |
323 | | * \param[in] format defined in imageio.h |
324 | | * \return 0 if OK; 1 on error |
325 | | * |
326 | | * <pre> |
327 | | * Notes: |
328 | | * (1) Open for write using binary mode (with the "b" flag) |
329 | | * to avoid having Windows automatically translate the NL |
330 | | * into CRLF, which corrupts image files. On non-Windows |
331 | | * systems this flag should be ignored, per ISO C90. |
332 | | * Thanks to Dave Bryan for pointing this out. |
333 | | * (2) If the default image format IFF_DEFAULT is requested: |
334 | | * use the input format if known; otherwise, use a lossless format. |
335 | | * (3) The default jpeg quality is 75. For some other value, |
336 | | * Use l_jpegSetQuality(). |
337 | | * </pre> |
338 | | */ |
339 | | l_ok |
340 | | pixWrite(const char *fname, |
341 | | PIX *pix, |
342 | | l_int32 format) |
343 | 0 | { |
344 | 0 | l_int32 ret; |
345 | 0 | FILE *fp; |
346 | |
|
347 | 0 | if (!pix) |
348 | 0 | return ERROR_INT("pix not defined", __func__, 1); |
349 | 0 | if (!fname) |
350 | 0 | return ERROR_INT("fname not defined", __func__, 1); |
351 | | |
352 | 0 | if ((fp = fopenWriteStream(fname, "wb+")) == NULL) |
353 | 0 | return ERROR_INT_1("stream not opened", fname, __func__, 1); |
354 | | |
355 | 0 | ret = pixWriteStream(fp, pix, format); |
356 | 0 | fclose(fp); |
357 | 0 | if (ret) |
358 | 0 | return ERROR_INT_1("pix not written to stream", fname, __func__, 1); |
359 | 0 | return 0; |
360 | 0 | } |
361 | | |
362 | | |
363 | | /*! |
364 | | * \brief pixWriteAutoFormat() |
365 | | * |
366 | | * \param[in] filename |
367 | | * \param[in] pix |
368 | | * \return 0 if OK; 1 on error |
369 | | */ |
370 | | l_ok |
371 | | pixWriteAutoFormat(const char *filename, |
372 | | PIX *pix) |
373 | 0 | { |
374 | 0 | l_int32 format; |
375 | |
|
376 | 0 | if (!pix) |
377 | 0 | return ERROR_INT("pix not defined", __func__, 1); |
378 | 0 | if (!filename) |
379 | 0 | return ERROR_INT("filename not defined", __func__, 1); |
380 | | |
381 | 0 | if (pixGetAutoFormat(pix, &format)) |
382 | 0 | return ERROR_INT("auto format not returned", __func__, 1); |
383 | 0 | return pixWrite(filename, pix, format); |
384 | 0 | } |
385 | | |
386 | | |
387 | | /*! |
388 | | * \brief pixWriteStream() |
389 | | * |
390 | | * \param[in] fp file stream |
391 | | * \param[in] pix |
392 | | * \param[in] format |
393 | | * \return 0 if OK; 1 on error. |
394 | | */ |
395 | | l_ok |
396 | | pixWriteStream(FILE *fp, |
397 | | PIX *pix, |
398 | | l_int32 format) |
399 | 0 | { |
400 | 0 | if (!fp) |
401 | 0 | return ERROR_INT("stream not defined", __func__, 1); |
402 | 0 | if (!pix) |
403 | 0 | return ERROR_INT("pix not defined", __func__, 1); |
404 | | |
405 | 0 | if (format == IFF_DEFAULT) |
406 | 0 | format = pixChooseOutputFormat(pix); |
407 | | |
408 | | /* Use bmp format for testing if library for requested |
409 | | * format for jpeg, png or tiff is not available */ |
410 | 0 | changeFormatForMissingLib(&format); |
411 | |
|
412 | 0 | switch(format) |
413 | 0 | { |
414 | 0 | case IFF_BMP: |
415 | 0 | pixWriteStreamBmp(fp, pix); |
416 | 0 | break; |
417 | | |
418 | 0 | case IFF_JFIF_JPEG: /* default quality; baseline sequential */ |
419 | 0 | return pixWriteStreamJpeg(fp, pix, var_JPEG_QUALITY, 0); |
420 | | |
421 | 0 | case IFF_PNG: /* no gamma value stored */ |
422 | 0 | return pixWriteStreamPng(fp, pix, 0.0); |
423 | | |
424 | 0 | case IFF_TIFF: /* uncompressed */ |
425 | 0 | case IFF_TIFF_PACKBITS: /* compressed, binary only */ |
426 | 0 | case IFF_TIFF_RLE: /* compressed, binary only */ |
427 | 0 | case IFF_TIFF_G3: /* compressed, binary only */ |
428 | 0 | case IFF_TIFF_G4: /* compressed, binary only */ |
429 | 0 | case IFF_TIFF_LZW: /* compressed, all depths */ |
430 | 0 | case IFF_TIFF_ZIP: /* compressed, all depths */ |
431 | 0 | case IFF_TIFF_JPEG: /* compressed, 8 bpp gray and 32 bpp rgb */ |
432 | 0 | return pixWriteStreamTiff(fp, pix, format); |
433 | | |
434 | 0 | case IFF_PNM: |
435 | 0 | return pixWriteStreamPnm(fp, pix); |
436 | | |
437 | 0 | case IFF_PS: |
438 | 0 | return pixWriteStreamPS(fp, pix, NULL, 0, DefaultScaling); |
439 | | |
440 | 0 | case IFF_GIF: |
441 | 0 | return pixWriteStreamGif(fp, pix); |
442 | | |
443 | 0 | case IFF_JP2: |
444 | 0 | return pixWriteStreamJp2k(fp, pix, 34, 0, L_JP2_CODEC, 0, 0); |
445 | | |
446 | 0 | case IFF_WEBP: |
447 | 0 | return pixWriteStreamWebP(fp, pix, 80, 0); |
448 | | |
449 | 0 | case IFF_LPDF: |
450 | 0 | return pixWriteStreamPdf(fp, pix, 0, NULL); |
451 | | |
452 | 0 | case IFF_SPIX: |
453 | 0 | return pixWriteStreamSpix(fp, pix); |
454 | | |
455 | 0 | default: |
456 | 0 | return ERROR_INT("unknown format", __func__, 1); |
457 | 0 | } |
458 | | |
459 | 0 | return 0; |
460 | 0 | } |
461 | | |
462 | | |
463 | | /*! |
464 | | * \brief pixWriteImpliedFormat() |
465 | | * |
466 | | * \param[in] filename |
467 | | * \param[in] pix |
468 | | * \param[in] quality iff JPEG; 1 - 100, 0 for default |
469 | | * \param[in] progressive iff JPEG; 0 for baseline seq., 1 for progressive |
470 | | * \return 0 if OK; 1 on error |
471 | | * |
472 | | * <pre> |
473 | | * Notes: |
474 | | * (1) This determines the output format from the filename extension. |
475 | | * (2) The last two args are ignored except for requests for jpeg files. |
476 | | * (3) The jpeg default quality is 75. |
477 | | * </pre> |
478 | | */ |
479 | | l_ok |
480 | | pixWriteImpliedFormat(const char *filename, |
481 | | PIX *pix, |
482 | | l_int32 quality, |
483 | | l_int32 progressive) |
484 | 0 | { |
485 | 0 | l_int32 format; |
486 | |
|
487 | 0 | if (!filename) |
488 | 0 | return ERROR_INT("filename not defined", __func__, 1); |
489 | 0 | if (!pix) |
490 | 0 | return ERROR_INT("pix not defined", __func__, 1); |
491 | | |
492 | | /* Determine output format */ |
493 | 0 | format = getImpliedFileFormat(filename); |
494 | 0 | if (format == IFF_UNKNOWN) { |
495 | 0 | format = IFF_PNG; |
496 | 0 | } else if (format == IFF_TIFF) { |
497 | 0 | if (pixGetDepth(pix) == 1) |
498 | 0 | format = IFF_TIFF_G4; |
499 | 0 | else |
500 | | #ifdef _WIN32 |
501 | | format = IFF_TIFF_LZW; /* poor compression */ |
502 | | #else |
503 | 0 | format = IFF_TIFF_ZIP; /* native Windows tools can't handle this */ |
504 | 0 | #endif /* _WIN32 */ |
505 | 0 | } |
506 | |
|
507 | 0 | if (format == IFF_JFIF_JPEG) { |
508 | 0 | quality = L_MIN(quality, 100); |
509 | 0 | quality = L_MAX(quality, 0); |
510 | 0 | if (progressive != 0 && progressive != 1) { |
511 | 0 | progressive = 0; |
512 | 0 | L_WARNING("invalid progressive; setting to baseline\n", __func__); |
513 | 0 | } |
514 | 0 | if (quality == 0) |
515 | 0 | quality = 75; |
516 | 0 | pixWriteJpeg (filename, pix, quality, progressive); |
517 | 0 | } else { |
518 | 0 | pixWrite(filename, pix, format); |
519 | 0 | } |
520 | |
|
521 | 0 | return 0; |
522 | 0 | } |
523 | | |
524 | | |
525 | | /*---------------------------------------------------------------------* |
526 | | * Selection of output format if default is requested * |
527 | | *---------------------------------------------------------------------*/ |
528 | | /*! |
529 | | * \brief pixChooseOutputFormat() |
530 | | * |
531 | | * \param[in] pix |
532 | | * \return output format, or 0 on error |
533 | | * |
534 | | * <pre> |
535 | | * Notes: |
536 | | * (1) This should only be called if the requested format is IFF_DEFAULT. |
537 | | * (2) If the pix wasn't read from a file, its input format value |
538 | | * will be IFF_UNKNOWN, and in that case it is written out |
539 | | * in a compressed but lossless format. |
540 | | * </pre> |
541 | | */ |
542 | | l_int32 |
543 | | pixChooseOutputFormat(PIX *pix) |
544 | 0 | { |
545 | 0 | l_int32 d, format; |
546 | |
|
547 | 0 | if (!pix) |
548 | 0 | return ERROR_INT("pix not defined", __func__, 0); |
549 | | |
550 | 0 | d = pixGetDepth(pix); |
551 | 0 | format = pixGetInputFormat(pix); |
552 | 0 | if (format == IFF_UNKNOWN) { /* output lossless */ |
553 | 0 | if (d == 1) |
554 | 0 | format = IFF_TIFF_G4; |
555 | 0 | else |
556 | 0 | format = IFF_PNG; |
557 | 0 | } |
558 | |
|
559 | 0 | return format; |
560 | 0 | } |
561 | | |
562 | | |
563 | | /*! |
564 | | * \brief getImpliedFileFormat() |
565 | | * |
566 | | * \param[in] filename |
567 | | * \return output format, or IFF_UNKNOWN on error or invalid extension. |
568 | | * |
569 | | * <pre> |
570 | | * Notes: |
571 | | * (1) This determines the output file format from the extension |
572 | | * of the input filename. |
573 | | * </pre> |
574 | | */ |
575 | | l_int32 |
576 | | getImpliedFileFormat(const char *filename) |
577 | 0 | { |
578 | 0 | char *extension; |
579 | 0 | l_int32 format = IFF_UNKNOWN; |
580 | |
|
581 | 0 | if (!filename) |
582 | 0 | return ERROR_INT("extension not defined", __func__, IFF_UNKNOWN); |
583 | | |
584 | 0 | if (splitPathAtExtension (filename, NULL, &extension)) |
585 | 0 | return IFF_UNKNOWN; |
586 | | |
587 | 0 | format = getFormatFromExtension(extension); |
588 | 0 | LEPT_FREE(extension); |
589 | 0 | return format; |
590 | 0 | } |
591 | | |
592 | | |
593 | | /*! |
594 | | * \brief getFormatFromExtension() |
595 | | * |
596 | | * \param[in] extension |
597 | | * \return output format, or IFF_UNKNOWN on error or invalid extension. |
598 | | * |
599 | | * <pre> |
600 | | * Notes: |
601 | | * (1) This determines the integer for writing in a format that |
602 | | * corresponds to the image file type extension. For example, |
603 | | * the integer code corresponding to the extension "jpg" is 2; |
604 | | * it is used to write with jpeg encoding. |
605 | | * </pre> |
606 | | */ |
607 | | l_int32 |
608 | | getFormatFromExtension(const char *extension) |
609 | 0 | { |
610 | 0 | int i, numext; |
611 | 0 | l_int32 format = IFF_UNKNOWN; |
612 | |
|
613 | 0 | if (!extension) |
614 | 0 | return ERROR_INT("extension not defined", __func__, IFF_UNKNOWN); |
615 | | |
616 | 0 | numext = sizeof(extension_map) / sizeof(extension_map[0]); |
617 | 0 | for (i = 0; i < numext; i++) { |
618 | 0 | if (!strcmp(extension, extension_map[i].extension)) { |
619 | 0 | format = extension_map[i].format; |
620 | 0 | break; |
621 | 0 | } |
622 | 0 | } |
623 | 0 | return format; |
624 | 0 | } |
625 | | |
626 | | |
627 | | /*! |
628 | | * \brief pixGetAutoFormat() |
629 | | * |
630 | | * \param[in] pix |
631 | | * \param[in] &format |
632 | | * \return 0 if OK, 1 on error |
633 | | * |
634 | | * <pre> |
635 | | * Notes: |
636 | | * (1) The output formats are restricted to tiff, jpeg and png |
637 | | * because these are the most commonly used image formats and |
638 | | * the ones that are typically installed with leptonica. |
639 | | * (2) This decides what compression to use based on the pix. |
640 | | * It chooses tiff-g4 if 1 bpp without a colormap, jpeg with |
641 | | * quality 75 if grayscale, rgb or rgba (where it loses |
642 | | * the alpha layer), and lossless png for all other situations. |
643 | | * </pre> |
644 | | */ |
645 | | l_ok |
646 | | pixGetAutoFormat(PIX *pix, |
647 | | l_int32 *pformat) |
648 | 0 | { |
649 | 0 | l_int32 d; |
650 | 0 | PIXCMAP *cmap; |
651 | |
|
652 | 0 | if (!pformat) |
653 | 0 | return ERROR_INT("&format not defined", __func__, 0); |
654 | 0 | *pformat = IFF_UNKNOWN; |
655 | 0 | if (!pix) |
656 | 0 | return ERROR_INT("pix not defined", __func__, 0); |
657 | | |
658 | 0 | d = pixGetDepth(pix); |
659 | 0 | cmap = pixGetColormap(pix); |
660 | 0 | if (d == 1 && !cmap) { |
661 | 0 | *pformat = IFF_TIFF_G4; |
662 | 0 | } else if ((d == 8 && !cmap) || d == 24 || d == 32) { |
663 | 0 | *pformat = IFF_JFIF_JPEG; |
664 | 0 | } else { |
665 | 0 | *pformat = IFF_PNG; |
666 | 0 | } |
667 | |
|
668 | 0 | return 0; |
669 | 0 | } |
670 | | |
671 | | |
672 | | /*! |
673 | | * \brief getFormatExtension() |
674 | | * |
675 | | * \param[in] format integer |
676 | | * \return extension string, or NULL if format is out of range |
677 | | * |
678 | | * <pre> |
679 | | * Notes: |
680 | | * (1) This string is NOT owned by the caller; it is just a pointer |
681 | | * to a global string. Do not free it. |
682 | | * </pre> |
683 | | */ |
684 | | const char * |
685 | | getFormatExtension(l_int32 format) |
686 | 0 | { |
687 | 0 | if (format < 0 || format >= NumImageFileFormatExtensions) |
688 | 0 | return (const char *)ERROR_PTR("invalid format", __func__, NULL); |
689 | | |
690 | 0 | return ImageFileFormatExtensions[format]; |
691 | 0 | } |
692 | | |
693 | | |
694 | | /*---------------------------------------------------------------------* |
695 | | * Write to memory * |
696 | | *---------------------------------------------------------------------*/ |
697 | | /*! |
698 | | * \brief pixWriteMem() |
699 | | * |
700 | | * \param[out] pdata data of tiff compressed image |
701 | | * \param[out] psize size of returned data |
702 | | * \param[in] pix |
703 | | * \param[in] format defined in imageio.h |
704 | | * \return 0 if OK, 1 on error |
705 | | * |
706 | | * <pre> |
707 | | * Notes: |
708 | | * (1) On Windows, this will only write tiff and PostScript to memory. |
709 | | * For other formats, it requires open_memstream(3). |
710 | | * (2) PostScript output is uncompressed, in hex ascii. |
711 | | * Most printers support level 2 compression (tiff_g4 for 1 bpp, |
712 | | * jpeg for 8 and 32 bpp). |
713 | | * (3) The default jpeg quality is 75. For some other value, |
714 | | * Use l_jpegSetQuality(). |
715 | | * </pre> |
716 | | */ |
717 | | l_ok |
718 | | pixWriteMem(l_uint8 **pdata, |
719 | | size_t *psize, |
720 | | PIX *pix, |
721 | | l_int32 format) |
722 | 0 | { |
723 | 0 | l_int32 ret; |
724 | |
|
725 | 0 | if (!pdata) |
726 | 0 | return ERROR_INT("&data not defined", __func__, 1 ); |
727 | 0 | if (!psize) |
728 | 0 | return ERROR_INT("&size not defined", __func__, 1 ); |
729 | 0 | if (!pix) |
730 | 0 | return ERROR_INT("&pix not defined", __func__, 1 ); |
731 | | |
732 | 0 | if (format == IFF_DEFAULT) |
733 | 0 | format = pixChooseOutputFormat(pix); |
734 | | |
735 | | /* Use bmp format for testing if library for requested |
736 | | * format for jpeg, png or tiff is not available */ |
737 | 0 | changeFormatForMissingLib(&format); |
738 | |
|
739 | 0 | switch(format) |
740 | 0 | { |
741 | 0 | case IFF_BMP: |
742 | 0 | ret = pixWriteMemBmp(pdata, psize, pix); |
743 | 0 | break; |
744 | | |
745 | 0 | case IFF_JFIF_JPEG: /* default quality; baseline sequential */ |
746 | 0 | ret = pixWriteMemJpeg(pdata, psize, pix, var_JPEG_QUALITY, 0); |
747 | 0 | break; |
748 | | |
749 | 0 | case IFF_PNG: /* no gamma value stored */ |
750 | 0 | ret = pixWriteMemPng(pdata, psize, pix, 0.0); |
751 | 0 | break; |
752 | | |
753 | 0 | case IFF_TIFF: /* uncompressed */ |
754 | 0 | case IFF_TIFF_PACKBITS: /* compressed, binary only */ |
755 | 0 | case IFF_TIFF_RLE: /* compressed, binary only */ |
756 | 0 | case IFF_TIFF_G3: /* compressed, binary only */ |
757 | 0 | case IFF_TIFF_G4: /* compressed, binary only */ |
758 | 0 | case IFF_TIFF_LZW: /* compressed, all depths */ |
759 | 0 | case IFF_TIFF_ZIP: /* compressed, all depths */ |
760 | 0 | case IFF_TIFF_JPEG: /* compressed, 8 bpp gray or 32 bpp rgb */ |
761 | 0 | ret = pixWriteMemTiff(pdata, psize, pix, format); |
762 | 0 | break; |
763 | | |
764 | 0 | case IFF_PNM: |
765 | 0 | ret = pixWriteMemPnm(pdata, psize, pix); |
766 | 0 | break; |
767 | | |
768 | 0 | case IFF_PS: |
769 | 0 | ret = pixWriteMemPS(pdata, psize, pix, NULL, 0, DefaultScaling); |
770 | 0 | break; |
771 | | |
772 | 0 | case IFF_GIF: |
773 | 0 | ret = pixWriteMemGif(pdata, psize, pix); |
774 | 0 | break; |
775 | | |
776 | 0 | case IFF_JP2: |
777 | 0 | ret = pixWriteMemJp2k(pdata, psize, pix, 34, 0, 0, 0); |
778 | 0 | break; |
779 | | |
780 | 0 | case IFF_WEBP: |
781 | 0 | ret = pixWriteMemWebP(pdata, psize, pix, 80, 0); |
782 | 0 | break; |
783 | | |
784 | 0 | case IFF_LPDF: |
785 | 0 | ret = pixWriteMemPdf(pdata, psize, pix, 0, NULL); |
786 | 0 | break; |
787 | | |
788 | 0 | case IFF_SPIX: |
789 | 0 | ret = pixWriteMemSpix(pdata, psize, pix); |
790 | 0 | break; |
791 | | |
792 | 0 | default: |
793 | 0 | return ERROR_INT("unknown format", __func__, 1); |
794 | 0 | } |
795 | | |
796 | 0 | return ret; |
797 | 0 | } |
798 | | |
799 | | |
800 | | /*---------------------------------------------------------------------* |
801 | | * Image display for debugging * |
802 | | *---------------------------------------------------------------------*/ |
803 | | /*! |
804 | | * \brief l_fileDisplay() |
805 | | * |
806 | | * \param[in] fname |
807 | | * \param[in] x, y location of display frame on the screen |
808 | | * \param[in] scale scale factor (use 0 to skip display) |
809 | | * \return 0 if OK; 1 on error |
810 | | * |
811 | | * <pre> |
812 | | * Notes: |
813 | | * (1) This is a convenient wrapper for displaying image files. |
814 | | * (2) It does nothing unless LeptDebugOK == TRUE. |
815 | | * (2) Set %scale = 0 to disable display. |
816 | | * (3) This downscales 1 bpp to gray. |
817 | | * </pre> |
818 | | */ |
819 | | l_ok |
820 | | l_fileDisplay(const char *fname, |
821 | | l_int32 x, |
822 | | l_int32 y, |
823 | | l_float32 scale) |
824 | 0 | { |
825 | 0 | PIX *pixs, *pixd; |
826 | |
|
827 | 0 | if (!LeptDebugOK) { |
828 | 0 | L_INFO("displaying files is disabled; " |
829 | 0 | "use setLeptDebugOK(1) to enable\n", __func__); |
830 | 0 | return 0; |
831 | 0 | } |
832 | 0 | if (scale == 0.0) |
833 | 0 | return 0; |
834 | 0 | if (scale < 0.0) |
835 | 0 | return ERROR_INT("invalid scale factor", __func__, 1); |
836 | 0 | if ((pixs = pixRead(fname)) == NULL) |
837 | 0 | return ERROR_INT("pixs not read", __func__, 1); |
838 | | |
839 | 0 | if (scale == 1.0) { |
840 | 0 | pixd = pixClone(pixs); |
841 | 0 | } else { |
842 | 0 | if (scale < 1.0 && pixGetDepth(pixs) == 1) |
843 | 0 | pixd = pixScaleToGray(pixs, scale); |
844 | 0 | else |
845 | 0 | pixd = pixScale(pixs, scale, scale); |
846 | 0 | } |
847 | 0 | pixDisplay(pixd, x, y); |
848 | 0 | pixDestroy(&pixs); |
849 | 0 | pixDestroy(&pixd); |
850 | 0 | return 0; |
851 | 0 | } |
852 | | |
853 | | |
854 | | /*! |
855 | | * \brief pixDisplay() |
856 | | * |
857 | | * \param[in] pix 1, 2, 4, 8, 16, 32 bpp |
858 | | * \param[in] x, y location of display frame on the screen |
859 | | * \return 0 if OK; 1 on error |
860 | | * |
861 | | * <pre> |
862 | | * Notes: |
863 | | * (1) This is debugging code that displays an image on the screen. |
864 | | * It uses a static internal variable to number the output files |
865 | | * written by a single process. Behavior with a shared library |
866 | | * may be unpredictable. |
867 | | * (2) It does nothing unless LeptDebugOK == TRUE. |
868 | | * (3) It uses these programs to display the image: |
869 | | * On Unix: xzgv, xli, xv or (for apple) open |
870 | | * On Windows: i_view or the application currently registered |
871 | | * as the default viewer (the browser 'open' action |
872 | | * based on the extension of the image file). |
873 | | * The display program must be on your $PATH variable. It is |
874 | | * chosen by setting the global var_DISPLAY_PROG, using |
875 | | * l_chooseDisplayProg(). Default on Unix is xzgv. |
876 | | * (4) Images with dimensions larger than MaxDisplayWidth or |
877 | | * MaxDisplayHeight are downscaled to fit those constraints. |
878 | | * This is particularly important for displaying 1 bpp images |
879 | | * with xv, because xv automatically downscales large images |
880 | | * by subsampling, which looks poor. For 1 bpp, we use |
881 | | * scale-to-gray to get decent-looking anti-aliased images. |
882 | | * In all cases, we write a temporary file to /tmp/lept/disp, |
883 | | * that is read by the display program. |
884 | | * (5) The temporary file is written as png if, after initial |
885 | | * processing for special cases, any of these obtain: |
886 | | * * pix dimensions are smaller than some thresholds |
887 | | * * pix depth is less than 8 bpp |
888 | | * * pix is colormapped |
889 | | * (6) For spp == 4, we call pixDisplayLayersRGBA() to show 3 |
890 | | * versions of the image: the image with a fully opaque |
891 | | * alpha, the alpha, and the image as it would appear with |
892 | | * a white background. |
893 | | * (7) pixDisplay() can be inactivated at runtime by calling: |
894 | | * l_chooseDisplayProg(L_DISPLAY_WITH_NONE); |
895 | | * </pre> |
896 | | */ |
897 | | l_ok |
898 | | pixDisplay(PIX *pixs, |
899 | | l_int32 x, |
900 | | l_int32 y) |
901 | 0 | { |
902 | 0 | return pixDisplayWithTitle(pixs, x, y, NULL, 1); |
903 | 0 | } |
904 | | |
905 | | |
906 | | /*! |
907 | | * \brief pixDisplayWithTitle() |
908 | | * |
909 | | * \param[in] pix 1, 2, 4, 8, 16, 32 bpp |
910 | | * \param[in] x, y location of display frame |
911 | | * \param[in] title [optional] on frame; can be NULL; |
912 | | * \param[in] dispflag 1 to write, else disabled |
913 | | * \return 0 if OK; 1 on error |
914 | | * |
915 | | * <pre> |
916 | | * Notes: |
917 | | * (1) See notes for pixDisplay(). |
918 | | * (2) This displays the image if dispflag == 1 and the global |
919 | | * var_DISPLAY_PROG != L_DISPLAY_WITH_NONE; otherwise it punts. |
920 | | * </pre> |
921 | | */ |
922 | | l_ok |
923 | | pixDisplayWithTitle(PIX *pixs, |
924 | | l_int32 x, |
925 | | l_int32 y, |
926 | | const char *title, |
927 | | l_int32 dispflag) |
928 | 0 | { |
929 | 0 | char *tempname; |
930 | 0 | char buffer[Bufsize]; |
931 | 0 | static l_atomic index = 0; /* caution: not .so safe */ |
932 | 0 | l_int32 w, h, d, spp, maxheight, opaque, threeviews; |
933 | 0 | l_float32 ratw, rath, ratmin; |
934 | 0 | PIX *pix0, *pix1, *pix2; |
935 | 0 | PIXCMAP *cmap; |
936 | 0 | #ifndef _WIN32 |
937 | 0 | l_int32 wt, ht; |
938 | | #else |
939 | | char *pathname; |
940 | | char fullpath[_MAX_PATH]; |
941 | | #endif /* _WIN32 */ |
942 | |
|
943 | 0 | if (!LeptDebugOK) { |
944 | 0 | L_INFO("displaying images is disabled;\n " |
945 | 0 | "use setLeptDebugOK(1) to enable\n", __func__); |
946 | 0 | return 0; |
947 | 0 | } |
948 | | |
949 | | #ifdef OS_IOS /* iOS 11 does not support system() */ |
950 | | return ERROR_INT("iOS 11 does not support system()", __func__, 1); |
951 | | #endif /* OS_IOS */ |
952 | | |
953 | 0 | if (dispflag != 1 || var_DISPLAY_PROG == L_DISPLAY_WITH_NONE) |
954 | 0 | return 0; |
955 | 0 | if (!pixs) |
956 | 0 | return ERROR_INT("pixs not defined", __func__, 1); |
957 | | |
958 | 0 | #ifndef _WIN32 /* unix */ |
959 | 0 | if (var_DISPLAY_PROG != L_DISPLAY_WITH_XZGV && |
960 | 0 | var_DISPLAY_PROG != L_DISPLAY_WITH_XLI && |
961 | 0 | var_DISPLAY_PROG != L_DISPLAY_WITH_XV && |
962 | 0 | var_DISPLAY_PROG != L_DISPLAY_WITH_OPEN) |
963 | 0 | return ERROR_INT("invalid unix program chosen for display", |
964 | 0 | __func__, 1); |
965 | | #else /* _WIN32 */ |
966 | | if (var_DISPLAY_PROG != L_DISPLAY_WITH_IV && |
967 | | var_DISPLAY_PROG != L_DISPLAY_WITH_OPEN) |
968 | | return ERROR_INT("invalid windows program chosen for display", |
969 | | __func__, 1); |
970 | | #endif /* _WIN32 */ |
971 | | |
972 | | /* Display with three views if either spp = 4 or if colormapped |
973 | | * and the alpha component is not fully opaque */ |
974 | 0 | opaque = TRUE; |
975 | 0 | if ((cmap = pixGetColormap(pixs)) != NULL) |
976 | 0 | pixcmapIsOpaque(cmap, &opaque); |
977 | 0 | spp = pixGetSpp(pixs); |
978 | 0 | threeviews = (spp == 4 || !opaque) ? TRUE : FALSE; |
979 | | |
980 | | /* If colormapped and not opaque, remove the colormap to RGBA */ |
981 | 0 | if (!opaque) |
982 | 0 | pix0 = pixRemoveColormap(pixs, REMOVE_CMAP_WITH_ALPHA); |
983 | 0 | else |
984 | 0 | pix0 = pixClone(pixs); |
985 | | |
986 | | /* Scale if necessary; this will also remove a colormap */ |
987 | 0 | pixGetDimensions(pix0, &w, &h, &d); |
988 | 0 | maxheight = (threeviews) ? MaxDisplayHeight / 3 : MaxDisplayHeight; |
989 | 0 | if (w <= MaxDisplayWidth && h <= maxheight) { |
990 | 0 | if (d == 16) /* take MSB */ |
991 | 0 | pix1 = pixConvert16To8(pix0, L_MS_BYTE); |
992 | 0 | else |
993 | 0 | pix1 = pixClone(pix0); |
994 | 0 | } else { |
995 | 0 | ratw = (l_float32)MaxDisplayWidth / (l_float32)w; |
996 | 0 | rath = (l_float32)maxheight / (l_float32)h; |
997 | 0 | ratmin = L_MIN(ratw, rath); |
998 | 0 | if (ratmin < 0.125 && d == 1) |
999 | 0 | pix1 = pixScaleToGray8(pix0); |
1000 | 0 | else if (ratmin < 0.25 && d == 1) |
1001 | 0 | pix1 = pixScaleToGray4(pix0); |
1002 | 0 | else if (ratmin < 0.33 && d == 1) |
1003 | 0 | pix1 = pixScaleToGray3(pix0); |
1004 | 0 | else if (ratmin < 0.5 && d == 1) |
1005 | 0 | pix1 = pixScaleToGray2(pix0); |
1006 | 0 | else |
1007 | 0 | pix1 = pixScale(pix0, ratmin, ratmin); |
1008 | 0 | } |
1009 | 0 | pixDestroy(&pix0); |
1010 | 0 | if (!pix1) |
1011 | 0 | return ERROR_INT("pix1 not made", __func__, 1); |
1012 | | |
1013 | | /* Generate the three views if required */ |
1014 | 0 | if (threeviews) |
1015 | 0 | pix2 = pixDisplayLayersRGBA(pix1, 0xffffff00, 0); |
1016 | 0 | else |
1017 | 0 | pix2 = pixClone(pix1); |
1018 | |
|
1019 | 0 | if (index == 0) { /* erase any existing images */ |
1020 | 0 | lept_rmdir("lept/disp"); |
1021 | 0 | lept_mkdir("lept/disp"); |
1022 | 0 | } |
1023 | |
|
1024 | 0 | index++; |
1025 | 0 | if (pixGetDepth(pix2) < 8 || pixGetColormap(pix2) || |
1026 | 0 | (w < MaxSizeForPng && h < MaxSizeForPng)) { |
1027 | 0 | snprintf(buffer, Bufsize, "/tmp/lept/disp/write.%03d.png", index); |
1028 | 0 | pixWrite(buffer, pix2, IFF_PNG); |
1029 | 0 | } else { |
1030 | 0 | snprintf(buffer, Bufsize, "/tmp/lept/disp/write.%03d.jpg", index); |
1031 | 0 | pixWrite(buffer, pix2, IFF_JFIF_JPEG); |
1032 | 0 | } |
1033 | 0 | tempname = genPathname(buffer, NULL); |
1034 | |
|
1035 | 0 | #ifndef _WIN32 |
1036 | | |
1037 | | /* Unix */ |
1038 | 0 | if (var_DISPLAY_PROG == L_DISPLAY_WITH_XZGV) { |
1039 | | /* no way to display title */ |
1040 | 0 | pixGetDimensions(pix2, &wt, &ht, NULL); |
1041 | 0 | snprintf(buffer, Bufsize, |
1042 | 0 | "xzgv --geometry %dx%d+%d+%d %s &", wt + 10, ht + 10, |
1043 | 0 | x, y, tempname); |
1044 | 0 | } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_XLI) { |
1045 | 0 | if (title) { |
1046 | 0 | snprintf(buffer, Bufsize, |
1047 | 0 | "xli -dispgamma 1.0 -quiet -geometry +%d+%d -title \"%s\" %s &", |
1048 | 0 | x, y, title, tempname); |
1049 | 0 | } else { |
1050 | 0 | snprintf(buffer, Bufsize, |
1051 | 0 | "xli -dispgamma 1.0 -quiet -geometry +%d+%d %s &", |
1052 | 0 | x, y, tempname); |
1053 | 0 | } |
1054 | 0 | } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_XV) { |
1055 | 0 | if (title) { |
1056 | 0 | snprintf(buffer, Bufsize, |
1057 | 0 | "xv -quit -geometry +%d+%d -name \"%s\" %s &", |
1058 | 0 | x, y, title, tempname); |
1059 | 0 | } else { |
1060 | 0 | snprintf(buffer, Bufsize, |
1061 | 0 | "xv -quit -geometry +%d+%d %s &", x, y, tempname); |
1062 | 0 | } |
1063 | 0 | } else { /* L_DISPLAY_WITH_OPEN */ |
1064 | 0 | snprintf(buffer, Bufsize, "open %s &", tempname); |
1065 | 0 | } |
1066 | 0 | callSystemDebug(buffer); |
1067 | |
|
1068 | | #else /* _WIN32 */ |
1069 | | |
1070 | | /* Windows: L_DISPLAY_WITH_IV || L_DISPLAY_WITH_OPEN */ |
1071 | | pathname = genPathname(tempname, NULL); |
1072 | | _fullpath(fullpath, pathname, sizeof(fullpath)); |
1073 | | if (var_DISPLAY_PROG == L_DISPLAY_WITH_IV) { |
1074 | | if (title) { |
1075 | | snprintf(buffer, Bufsize, |
1076 | | "i_view32.exe \"%s\" /pos=(%d,%d) /title=\"%s\"", |
1077 | | fullpath, x, y, title); |
1078 | | } else { |
1079 | | snprintf(buffer, Bufsize, "i_view32.exe \"%s\" /pos=(%d,%d)", |
1080 | | fullpath, x, y); |
1081 | | } |
1082 | | } else { /* L_DISPLAY_WITH_OPEN */ |
1083 | | snprintf(buffer, Bufsize, "explorer.exe /open,\"%s\"", fullpath); |
1084 | | } |
1085 | | callSystemDebug(buffer); |
1086 | | LEPT_FREE(pathname); |
1087 | | |
1088 | | #endif /* _WIN32 */ |
1089 | |
|
1090 | 0 | pixDestroy(&pix1); |
1091 | 0 | pixDestroy(&pix2); |
1092 | 0 | LEPT_FREE(tempname); |
1093 | 0 | return 0; |
1094 | 0 | } |
1095 | | |
1096 | | |
1097 | | /*! |
1098 | | * \brief pixMakeColorSquare() |
1099 | | * |
1100 | | * \param[in] color in 0xrrggbb00 format |
1101 | | * \param[in] size in pixels; >= 100; use 0 for default (min size) |
1102 | | * \param[in] addlabel use 1 to display the color component values |
1103 | | * \param[in] location of text: L_ADD_ABOVE, etc; ignored if %addlabel == 0 |
1104 | | * \param[in] textcolor of text label; in 0xrrggbb00 format |
1105 | | * \return 32 bpp rgb pixd if OK; NULL on error |
1106 | | * |
1107 | | * <pre> |
1108 | | * Notes: |
1109 | | * (1) If %addlabel == 0, %location and %textcolor are ignored. |
1110 | | * (2) To make an array of color squares, use pixDisplayColorArray(). |
1111 | | * </pre> |
1112 | | */ |
1113 | | PIX * |
1114 | | pixMakeColorSquare(l_uint32 color, |
1115 | | l_int32 size, |
1116 | | l_int32 addlabel, |
1117 | | l_int32 location, |
1118 | | l_uint32 textcolor) |
1119 | 0 | { |
1120 | 0 | char buf[32]; |
1121 | 0 | l_int32 w, rval, gval, bval; |
1122 | 0 | L_BMF *bmf; |
1123 | 0 | PIX *pix1, *pix2; |
1124 | |
|
1125 | 0 | w = (size <= 0) ? 100 : size; |
1126 | 0 | if (addlabel && w < 100) { |
1127 | 0 | L_WARNING("size too small for label; omitting label\n", __func__); |
1128 | 0 | addlabel = 0; |
1129 | 0 | } |
1130 | |
|
1131 | 0 | if ((pix1 = pixCreate(w, w, 32)) == NULL) |
1132 | 0 | return (PIX *)ERROR_PTR("pix1 not madel", __func__, NULL); |
1133 | 0 | pixSetAllArbitrary(pix1, color); |
1134 | 0 | if (!addlabel) |
1135 | 0 | return pix1; |
1136 | | |
1137 | | /* Adding text of color component values */ |
1138 | 0 | if (location != L_ADD_ABOVE && location != L_ADD_AT_TOP && |
1139 | 0 | location != L_ADD_AT_BOT && location != L_ADD_BELOW) { |
1140 | 0 | L_ERROR("invalid location: adding below\n", __func__); |
1141 | 0 | location = L_ADD_BELOW; |
1142 | 0 | } |
1143 | 0 | bmf = bmfCreate(NULL, 4); |
1144 | 0 | extractRGBValues(color, &rval, &gval, &bval); |
1145 | 0 | snprintf(buf, sizeof(buf), "%d,%d,%d", rval, gval, bval); |
1146 | 0 | pix2 = pixAddSingleTextblock(pix1, bmf, buf, textcolor, location, NULL); |
1147 | 0 | pixDestroy(&pix1); |
1148 | 0 | bmfDestroy(&bmf); |
1149 | 0 | return pix2; |
1150 | 0 | } |
1151 | | |
1152 | | |
1153 | | void |
1154 | | l_chooseDisplayProg(l_int32 selection) |
1155 | 0 | { |
1156 | 0 | if (selection == L_DISPLAY_WITH_XLI || |
1157 | 0 | selection == L_DISPLAY_WITH_XZGV || |
1158 | 0 | selection == L_DISPLAY_WITH_XV || |
1159 | 0 | selection == L_DISPLAY_WITH_IV || |
1160 | 0 | selection == L_DISPLAY_WITH_OPEN) { |
1161 | 0 | var_DISPLAY_PROG = selection; |
1162 | 0 | } else { |
1163 | 0 | L_ERROR("invalid display program\n", "l_chooseDisplayProg"); |
1164 | 0 | } |
1165 | 0 | } |
1166 | | |
1167 | | |
1168 | | /*---------------------------------------------------------------------* |
1169 | | * Change format for missing lib * |
1170 | | *---------------------------------------------------------------------*/ |
1171 | | /*! |
1172 | | * \brief changeFormatForMissingLib() |
1173 | | * |
1174 | | * \param[in,out] pformat addr of requested output image format |
1175 | | * \return void |
1176 | | * |
1177 | | * <pre> |
1178 | | * Notes: |
1179 | | * (1) This is useful for testing functionality when the library for |
1180 | | * the requested output format (jpeg, png or tiff) is not linked. |
1181 | | * In that case, the output format is changed to bmp. |
1182 | | * </pre> |
1183 | | */ |
1184 | | void |
1185 | | changeFormatForMissingLib(l_int32 *pformat) |
1186 | 0 | { |
1187 | | #if !defined(HAVE_LIBJPEG) |
1188 | | if (*pformat == IFF_JFIF_JPEG) { |
1189 | | L_WARNING("jpeg library missing; output bmp format\n", __func__); |
1190 | | *pformat = IFF_BMP; |
1191 | | } |
1192 | | #endif /* !defined(HAVE_LIBJPEG) */ |
1193 | | #if !defined(HAVE_LIBPNG) |
1194 | | if (*pformat == IFF_PNG) { |
1195 | | L_WARNING("png library missing; output bmp format\n", __func__); |
1196 | | *pformat = IFF_BMP; |
1197 | | } |
1198 | | #endif /* !defined(HAVE_LIBPNG) */ |
1199 | | #if !defined(HAVE_LIBTIFF) |
1200 | | if (L_FORMAT_IS_TIFF(*pformat)) { |
1201 | | L_WARNING("tiff library missing; output bmp format\n", __func__); |
1202 | | *pformat = IFF_BMP; |
1203 | | } |
1204 | | #endif /* !defined(HAVE_LIBTIFF) */ |
1205 | 0 | } |
1206 | | |
1207 | | |
1208 | | /*---------------------------------------------------------------------* |
1209 | | * Deprecated pix output for debugging * |
1210 | | *---------------------------------------------------------------------*/ |
1211 | | /*! |
1212 | | * \brief pixDisplayWrite() |
1213 | | * |
1214 | | * \param[in] pix |
1215 | | * \param[in] reduction |
1216 | | * \return 1 (error) |
1217 | | * |
1218 | | * <pre> |
1219 | | * Notes: |
1220 | | * As of 1.80, this is a non-functional stub. |
1221 | | * </pre> |
1222 | | */ |
1223 | | l_ok |
1224 | | pixDisplayWrite(PIX *pixs, |
1225 | | l_int32 reduction) |
1226 | 0 | { |
1227 | 0 | lept_stderr("\n########################################################\n" |
1228 | 0 | " pixDisplayWrite() was last used in tesseract 3.04," |
1229 | 0 | " in Feb 2016. As of 1.80, it is a non-functional stub\n" |
1230 | 0 | "########################################################" |
1231 | 0 | "\n\n\n"); |
1232 | 0 | return 1; |
1233 | 0 | } |