Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/leptonica/src/readfile.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 readfile.c: reads image on file into memory | |
| 29 * <pre> | |
| 30 * | |
| 31 * Top-level functions for reading images from file | |
| 32 * PIXA *pixaReadFiles() | |
| 33 * PIXA *pixaReadFilesSA() | |
| 34 * PIX *pixRead() | |
| 35 * PIX *pixReadWithHint() | |
| 36 * PIX *pixReadIndexed() | |
| 37 * PIX *pixReadStream() | |
| 38 * | |
| 39 * Read header information from file | |
| 40 * l_int32 pixReadHeader() | |
| 41 * | |
| 42 * Format finders | |
| 43 * l_int32 findFileFormat() | |
| 44 * l_int32 findFileFormatStream() | |
| 45 * l_int32 findFileFormatBuffer() | |
| 46 * l_int32 fileFormatIsTiff() | |
| 47 * | |
| 48 * Read from memory | |
| 49 * PIX *pixReadMem() | |
| 50 * l_int32 pixReadHeaderMem() | |
| 51 * | |
| 52 * Output image file information | |
| 53 * void writeImageFileInfo() | |
| 54 * | |
| 55 * Test function for I/O with different formats | |
| 56 * l_int32 ioFormatTest() | |
| 57 * | |
| 58 * Supported file formats: | |
| 59 * (1) Reading is supported without any external libraries: | |
| 60 * bmp | |
| 61 * pnm (including pbm, pgm, etc) | |
| 62 * spix (raw serialized) | |
| 63 * (2) Reading is supported with installation of external libraries: | |
| 64 * png | |
| 65 * jpg (standard jfif version) | |
| 66 * tiff (including most varieties of compression) | |
| 67 * gif | |
| 68 * webp | |
| 69 * jp2 (jpeg 2000) | |
| 70 * (3) Other file types will get an "unknown format" error. | |
| 71 * </pre> | |
| 72 */ | |
| 73 | |
| 74 #ifdef HAVE_CONFIG_H | |
| 75 #include <config_auto.h> | |
| 76 #endif /* HAVE_CONFIG_H */ | |
| 77 | |
| 78 #include <string.h> | |
| 79 #include "allheaders.h" | |
| 80 | |
| 81 /* Output files for ioFormatTest(). */ | |
| 82 static const char *FILE_BMP = "/tmp/lept/format/file.bmp"; | |
| 83 static const char *FILE_PNG = "/tmp/lept/format/file.png"; | |
| 84 static const char *FILE_PNM = "/tmp/lept/format/file.pnm"; | |
| 85 static const char *FILE_G3 = "/tmp/lept/format/file_g3.tif"; | |
| 86 static const char *FILE_G4 = "/tmp/lept/format/file_g4.tif"; | |
| 87 static const char *FILE_RLE = "/tmp/lept/format/file_rle.tif"; | |
| 88 static const char *FILE_PB = "/tmp/lept/format/file_packbits.tif"; | |
| 89 static const char *FILE_LZW = "/tmp/lept/format/file_lzw.tif"; | |
| 90 static const char *FILE_ZIP = "/tmp/lept/format/file_zip.tif"; | |
| 91 static const char *FILE_TIFF_JPEG = "/tmp/lept/format/file_jpeg.tif"; | |
| 92 static const char *FILE_TIFF = "/tmp/lept/format/file.tif"; | |
| 93 static const char *FILE_JPG = "/tmp/lept/format/file.jpg"; | |
| 94 static const char *FILE_GIF = "/tmp/lept/format/file.gif"; | |
| 95 static const char *FILE_WEBP = "/tmp/lept/format/file.webp"; | |
| 96 static const char *FILE_JP2K = "/tmp/lept/format/file.jp2"; | |
| 97 | |
| 98 /* There are two jp2 formats, and two codecs associated with them: | |
| 99 * OPJ_CODEC_J2K (L_J2K_CODEC) is associated with JP2K_CODESTREAM | |
| 100 * OPJ_CODEC_JP2 (L_JP2_CODEC) is associated with JP2K_IMAGE_DATA */ | |
| 101 static const unsigned char JP2K_CODESTREAM[4] = { 0xff, 0x4f, 0xff, 0x51 }; | |
| 102 static const unsigned char JP2K_IMAGE_DATA[12] = { 0x00, 0x00, 0x00, 0x0c, | |
| 103 0x6a, 0x50, 0x20, 0x20, | |
| 104 0x0d, 0x0a, 0x87, 0x0a }; | |
| 105 | |
| 106 | |
| 107 /*---------------------------------------------------------------------* | |
| 108 * Top-level functions for reading images from file * | |
| 109 *---------------------------------------------------------------------*/ | |
| 110 /*! | |
| 111 * \brief pixaReadFiles() | |
| 112 * | |
| 113 * \param[in] dirname | |
| 114 * \param[in] substr [optional] substring filter on filenames; can be null | |
| 115 * \return pixa, or NULL on error | |
| 116 * | |
| 117 * <pre> | |
| 118 * Notes: | |
| 119 * (1) %dirname is the full path for the directory. | |
| 120 * (2) %substr is the part of the file name (excluding | |
| 121 * the directory) that is to be matched. All matching | |
| 122 * filenames are read into the Pixa. If substr is NULL, | |
| 123 * all filenames are read into the Pixa. | |
| 124 * </pre> | |
| 125 */ | |
| 126 PIXA * | |
| 127 pixaReadFiles(const char *dirname, | |
| 128 const char *substr) | |
| 129 { | |
| 130 PIXA *pixa; | |
| 131 SARRAY *sa; | |
| 132 | |
| 133 if (!dirname) | |
| 134 return (PIXA *)ERROR_PTR("dirname not defined", __func__, NULL); | |
| 135 | |
| 136 if ((sa = getSortedPathnamesInDirectory(dirname, substr, 0, 0)) == NULL) | |
| 137 return (PIXA *)ERROR_PTR("sa not made", __func__, NULL); | |
| 138 | |
| 139 pixa = pixaReadFilesSA(sa); | |
| 140 sarrayDestroy(&sa); | |
| 141 return pixa; | |
| 142 } | |
| 143 | |
| 144 | |
| 145 /*! | |
| 146 * \brief pixaReadFilesSA() | |
| 147 * | |
| 148 * \param[in] sa full pathnames for all files | |
| 149 * \return pixa, or NULL on error | |
| 150 */ | |
| 151 PIXA * | |
| 152 pixaReadFilesSA(SARRAY *sa) | |
| 153 { | |
| 154 char *str; | |
| 155 l_int32 i, n; | |
| 156 PIX *pix; | |
| 157 PIXA *pixa; | |
| 158 | |
| 159 if (!sa) | |
| 160 return (PIXA *)ERROR_PTR("sa not defined", __func__, NULL); | |
| 161 | |
| 162 n = sarrayGetCount(sa); | |
| 163 pixa = pixaCreate(n); | |
| 164 for (i = 0; i < n; i++) { | |
| 165 str = sarrayGetString(sa, i, L_NOCOPY); | |
| 166 if ((pix = pixRead(str)) == NULL) { | |
| 167 L_WARNING("pix not read from file %s\n", __func__, str); | |
| 168 continue; | |
| 169 } | |
| 170 pixaAddPix(pixa, pix, L_INSERT); | |
| 171 } | |
| 172 | |
| 173 return pixa; | |
| 174 } | |
| 175 | |
| 176 | |
| 177 /*! | |
| 178 * \brief pixRead() | |
| 179 * | |
| 180 * \param[in] filename with full pathname or in local directory | |
| 181 * \return pix if OK; NULL on error | |
| 182 * | |
| 183 * <pre> | |
| 184 * Notes: | |
| 185 * (1) See at top of file for supported formats. | |
| 186 * </pre> | |
| 187 */ | |
| 188 PIX * | |
| 189 pixRead(const char *filename) | |
| 190 { | |
| 191 FILE *fp; | |
| 192 PIX *pix; | |
| 193 | |
| 194 if (!filename) | |
| 195 return (PIX *)ERROR_PTR("filename not defined", __func__, NULL); | |
| 196 | |
| 197 if ((fp = fopenReadStream(filename)) == NULL) | |
| 198 return (PIX*)ERROR_PTR_1("image file not found", | |
| 199 filename, __func__, NULL); | |
| 200 pix = pixReadStream(fp, 0); | |
| 201 fclose(fp); | |
| 202 if (!pix) | |
| 203 return (PIX *)ERROR_PTR_1("pix not read", filename, __func__, NULL); | |
| 204 return pix; | |
| 205 } | |
| 206 | |
| 207 | |
| 208 /*! | |
| 209 * \brief pixReadWithHint() | |
| 210 * | |
| 211 * \param[in] filename with full pathname or in local directory | |
| 212 * \param[in] hint bitwise OR of L_HINT_* values for jpeg; | |
| 213 * use 0 for no hint | |
| 214 * \return pix if OK; NULL on error | |
| 215 * | |
| 216 * <pre> | |
| 217 * Notes: | |
| 218 * (1) The hint is not binding, but may be used to optimize jpeg decoding. | |
| 219 * Use 0 for no hinting. | |
| 220 * </pre> | |
| 221 */ | |
| 222 PIX * | |
| 223 pixReadWithHint(const char *filename, | |
| 224 l_int32 hint) | |
| 225 { | |
| 226 FILE *fp; | |
| 227 PIX *pix; | |
| 228 | |
| 229 if (!filename) | |
| 230 return (PIX *)ERROR_PTR("filename not defined", __func__, NULL); | |
| 231 | |
| 232 if ((fp = fopenReadStream(filename)) == NULL) | |
| 233 return (PIX *)ERROR_PTR_1("image file not found", | |
| 234 filename, __func__, NULL); | |
| 235 pix = pixReadStream(fp, hint); | |
| 236 fclose(fp); | |
| 237 | |
| 238 if (!pix) | |
| 239 return (PIX *)ERROR_PTR_1("image not returned", | |
| 240 filename, __func__, NULL); | |
| 241 return pix; | |
| 242 } | |
| 243 | |
| 244 | |
| 245 /*! | |
| 246 * \brief pixReadIndexed() | |
| 247 * | |
| 248 * \param[in] sa string array of full pathnames | |
| 249 * \param[in] index into pathname array | |
| 250 * \return pix if OK; null if not found | |
| 251 * | |
| 252 * <pre> | |
| 253 * Notes: | |
| 254 * (1) This function is useful for selecting image files from a | |
| 255 * directory, where the integer %index is embedded into | |
| 256 * the file name. | |
| 257 * (2) This is typically done by generating the sarray using | |
| 258 * getNumberedPathnamesInDirectory(), so that the %index | |
| 259 * pathname would have the number %index in it. The size | |
| 260 * of the sarray should be the largest number (plus 1) appearing | |
| 261 * in the file names, respecting the constraints in the | |
| 262 * call to getNumberedPathnamesInDirectory(). | |
| 263 * (3) Consequently, for some indices into the sarray, there may | |
| 264 * be no pathnames in the directory containing that number. | |
| 265 * By convention, we place empty C strings ("") in those | |
| 266 * locations in the sarray, and it is not an error if such | |
| 267 * a string is encountered and no pix is returned. | |
| 268 * Therefore, the caller must verify that a pix is returned. | |
| 269 * (4) See convertSegmentedPagesToPS() in src/psio1.c for an | |
| 270 * example of usage. | |
| 271 * </pre> | |
| 272 */ | |
| 273 PIX * | |
| 274 pixReadIndexed(SARRAY *sa, | |
| 275 l_int32 index) | |
| 276 { | |
| 277 char *fname; | |
| 278 l_int32 n; | |
| 279 PIX *pix; | |
| 280 | |
| 281 if (!sa) | |
| 282 return (PIX *)ERROR_PTR("sa not defined", __func__, NULL); | |
| 283 n = sarrayGetCount(sa); | |
| 284 if (index < 0 || index >= n) | |
| 285 return (PIX *)ERROR_PTR("index out of bounds", __func__, NULL); | |
| 286 | |
| 287 fname = sarrayGetString(sa, index, L_NOCOPY); | |
| 288 if (fname[0] == '\0') | |
| 289 return NULL; | |
| 290 | |
| 291 if ((pix = pixRead(fname)) == NULL) { | |
| 292 L_ERROR("pix not read from file %s\n", __func__, fname); | |
| 293 return NULL; | |
| 294 } | |
| 295 | |
| 296 return pix; | |
| 297 } | |
| 298 | |
| 299 | |
| 300 /*! | |
| 301 * \brief pixReadStream() | |
| 302 * | |
| 303 * \param[in] fp file stream | |
| 304 * \param[in] hint bitwise OR of L_HINT_* values for jpeg; 0 for no hint | |
| 305 * \return pix if OK; NULL on error | |
| 306 * | |
| 307 * <pre> | |
| 308 * Notes: | |
| 309 * (1) The hint only applies to jpeg. | |
| 310 * </pre> | |
| 311 */ | |
| 312 PIX * | |
| 313 pixReadStream(FILE *fp, | |
| 314 l_int32 hint) | |
| 315 { | |
| 316 l_int32 format, ret, valid; | |
| 317 l_uint8 *comment; | |
| 318 PIX *pix; | |
| 319 PIXCMAP *cmap; | |
| 320 | |
| 321 if (!fp) | |
| 322 return (PIX *)ERROR_PTR("stream not defined", __func__, NULL); | |
| 323 pix = NULL; | |
| 324 | |
| 325 findFileFormatStream(fp, &format); | |
| 326 switch (format) | |
| 327 { | |
| 328 case IFF_BMP: | |
| 329 if ((pix = pixReadStreamBmp(fp)) == NULL ) | |
| 330 return (PIX *)ERROR_PTR( "bmp: no pix returned", __func__, NULL); | |
| 331 break; | |
| 332 | |
| 333 case IFF_JFIF_JPEG: | |
| 334 if ((pix = pixReadStreamJpeg(fp, 0, 1, NULL, hint)) == NULL) | |
| 335 return (PIX *)ERROR_PTR( "jpeg: no pix returned", __func__, NULL); | |
| 336 ret = fgetJpegComment(fp, &comment); | |
| 337 if (!ret && comment) | |
| 338 pixSetText(pix, (char *)comment); | |
| 339 LEPT_FREE(comment); | |
| 340 break; | |
| 341 | |
| 342 case IFF_PNG: | |
| 343 if ((pix = pixReadStreamPng(fp)) == NULL) | |
| 344 return (PIX *)ERROR_PTR("png: no pix returned", __func__, NULL); | |
| 345 break; | |
| 346 | |
| 347 case IFF_TIFF: | |
| 348 case IFF_TIFF_PACKBITS: | |
| 349 case IFF_TIFF_RLE: | |
| 350 case IFF_TIFF_G3: | |
| 351 case IFF_TIFF_G4: | |
| 352 case IFF_TIFF_LZW: | |
| 353 case IFF_TIFF_ZIP: | |
| 354 case IFF_TIFF_JPEG: | |
| 355 if ((pix = pixReadStreamTiff(fp, 0)) == NULL) /* page 0 by default */ | |
| 356 return (PIX *)ERROR_PTR("tiff: no pix returned", __func__, NULL); | |
| 357 break; | |
| 358 | |
| 359 case IFF_PNM: | |
| 360 if ((pix = pixReadStreamPnm(fp)) == NULL) | |
| 361 return (PIX *)ERROR_PTR("pnm: no pix returned", __func__, NULL); | |
| 362 break; | |
| 363 | |
| 364 case IFF_GIF: | |
| 365 if ((pix = pixReadStreamGif(fp)) == NULL) | |
| 366 return (PIX *)ERROR_PTR("gif: no pix returned", __func__, NULL); | |
| 367 break; | |
| 368 | |
| 369 case IFF_JP2: | |
| 370 if ((pix = pixReadStreamJp2k(fp, 1, NULL, 0, 0)) == NULL) | |
| 371 return (PIX *)ERROR_PTR("jp2: no pix returned", __func__, NULL); | |
| 372 break; | |
| 373 | |
| 374 case IFF_WEBP: | |
| 375 if ((pix = pixReadStreamWebP(fp)) == NULL) | |
| 376 return (PIX *)ERROR_PTR("webp: no pix returned", __func__, NULL); | |
| 377 break; | |
| 378 | |
| 379 case IFF_PS: | |
| 380 L_ERROR("PostScript reading is not supported\n", __func__); | |
| 381 return NULL; | |
| 382 | |
| 383 case IFF_LPDF: | |
| 384 L_ERROR("Pdf reading is not supported\n", __func__); | |
| 385 return NULL; | |
| 386 | |
| 387 case IFF_SPIX: | |
| 388 if ((pix = pixReadStreamSpix(fp)) == NULL) | |
| 389 return (PIX *)ERROR_PTR("spix: no pix returned", __func__, NULL); | |
| 390 break; | |
| 391 | |
| 392 case IFF_UNKNOWN: | |
| 393 return (PIX *)ERROR_PTR( "Unknown format: no pix returned", | |
| 394 __func__, NULL); | |
| 395 break; | |
| 396 } | |
| 397 | |
| 398 if (pix) { | |
| 399 pixSetInputFormat(pix, format); | |
| 400 if ((cmap = pixGetColormap(pix))) { | |
| 401 pixcmapIsValid(cmap, pix, &valid); | |
| 402 if (!valid) { | |
| 403 pixDestroy(&pix); | |
| 404 return (PIX *)ERROR_PTR("invalid colormap", __func__, NULL); | |
| 405 } | |
| 406 } | |
| 407 } | |
| 408 return pix; | |
| 409 } | |
| 410 | |
| 411 | |
| 412 | |
| 413 /*---------------------------------------------------------------------* | |
| 414 * Read header information from file * | |
| 415 *---------------------------------------------------------------------*/ | |
| 416 /*! | |
| 417 * \brief pixReadHeader() | |
| 418 * | |
| 419 * \param[in] filename with full pathname or in local directory | |
| 420 * \param[out] pformat [optional] file format | |
| 421 * \param[out] pw, ph [optional] width and height | |
| 422 * \param[out] pbps [optional] bits/sample | |
| 423 * \param[out] pspp [optional] samples/pixel 1, 3 or 4 | |
| 424 * \param[out] piscmap [optional] 1 if cmap exists; 0 otherwise | |
| 425 * \return 0 if OK, 1 on error | |
| 426 * | |
| 427 * <pre> | |
| 428 * Notes: | |
| 429 * (1) This reads the actual headers for jpeg, png, tiff and pnm. | |
| 430 * For bmp and gif, we cheat and read the entire file into a pix, | |
| 431 * from which we extract the "header" information. | |
| 432 * </pre> | |
| 433 */ | |
| 434 l_ok | |
| 435 pixReadHeader(const char *filename, | |
| 436 l_int32 *pformat, | |
| 437 l_int32 *pw, | |
| 438 l_int32 *ph, | |
| 439 l_int32 *pbps, | |
| 440 l_int32 *pspp, | |
| 441 l_int32 *piscmap) | |
| 442 { | |
| 443 l_int32 format, ret, w, h, d, bps, spp, iscmap; | |
| 444 l_int32 type; /* ignored */ | |
| 445 FILE *fp; | |
| 446 PIX *pix; | |
| 447 | |
| 448 if (pw) *pw = 0; | |
| 449 if (ph) *ph = 0; | |
| 450 if (pbps) *pbps = 0; | |
| 451 if (pspp) *pspp = 0; | |
| 452 if (piscmap) *piscmap = 0; | |
| 453 if (pformat) *pformat = 0; | |
| 454 iscmap = 0; /* init to false */ | |
| 455 if (!filename) | |
| 456 return ERROR_INT("filename not defined", __func__, 1); | |
| 457 | |
| 458 if ((fp = fopenReadStream(filename)) == NULL) | |
| 459 return ERROR_INT_1("image file not found", filename, __func__, 1); | |
| 460 findFileFormatStream(fp, &format); | |
| 461 fclose(fp); | |
| 462 | |
| 463 switch (format) | |
| 464 { | |
| 465 case IFF_BMP: /* cheating: reading the entire file */ | |
| 466 if ((pix = pixRead(filename)) == NULL) | |
| 467 return ERROR_INT_1( "bmp: pix not read", filename, __func__, 1); | |
| 468 pixGetDimensions(pix, &w, &h, &d); | |
| 469 bps = (d == 32) ? 8 : d; | |
| 470 spp = pixGetSpp(pix); | |
| 471 iscmap = (pixGetColormap(pix)) ? 1 : 0; | |
| 472 pixDestroy(&pix); | |
| 473 break; | |
| 474 | |
| 475 case IFF_JFIF_JPEG: | |
| 476 ret = readHeaderJpeg(filename, &w, &h, &spp, NULL, NULL); | |
| 477 bps = 8; | |
| 478 if (ret) | |
| 479 return ERROR_INT_1("jpeg: no header info returned", | |
| 480 filename, __func__, 1); | |
| 481 break; | |
| 482 | |
| 483 case IFF_PNG: | |
| 484 ret = readHeaderPng(filename, &w, &h, &bps, &spp, &iscmap); | |
| 485 if (ret) | |
| 486 return ERROR_INT_1("png: no header info returned", | |
| 487 filename, __func__, 1); | |
| 488 break; | |
| 489 | |
| 490 case IFF_TIFF: | |
| 491 case IFF_TIFF_PACKBITS: | |
| 492 case IFF_TIFF_RLE: | |
| 493 case IFF_TIFF_G3: | |
| 494 case IFF_TIFF_G4: | |
| 495 case IFF_TIFF_LZW: | |
| 496 case IFF_TIFF_ZIP: | |
| 497 case IFF_TIFF_JPEG: | |
| 498 /* Reading page 0 by default; possibly redefine format */ | |
| 499 ret = readHeaderTiff(filename, 0, &w, &h, &bps, &spp, NULL, &iscmap, | |
| 500 &format); | |
| 501 if (ret) | |
| 502 return ERROR_INT_1("tiff: no header info returned", | |
| 503 filename, __func__, 1); | |
| 504 break; | |
| 505 | |
| 506 case IFF_PNM: | |
| 507 ret = readHeaderPnm(filename, &w, &h, &d, &type, &bps, &spp); | |
| 508 if (ret) | |
| 509 return ERROR_INT_1("pnm: no header info returned", | |
| 510 filename, __func__, 1); | |
| 511 break; | |
| 512 | |
| 513 case IFF_GIF: /* cheating: reading the entire file */ | |
| 514 if ((pix = pixRead(filename)) == NULL) | |
| 515 return ERROR_INT_1( "gif: pix not read", filename, __func__, 1); | |
| 516 pixGetDimensions(pix, &w, &h, &d); | |
| 517 pixDestroy(&pix); | |
| 518 iscmap = 1; /* always colormapped; max 256 colors */ | |
| 519 spp = 1; | |
| 520 bps = d; | |
| 521 break; | |
| 522 | |
| 523 case IFF_JP2: | |
| 524 ret = readHeaderJp2k(filename, &w, &h, &bps, &spp, NULL); | |
| 525 break; | |
| 526 | |
| 527 case IFF_WEBP: | |
| 528 if (readHeaderWebP(filename, &w, &h, &spp)) | |
| 529 return ERROR_INT_1("webp: no header info returned", | |
| 530 filename, __func__, 1); | |
| 531 bps = 8; | |
| 532 break; | |
| 533 | |
| 534 case IFF_PS: | |
| 535 if (pformat) *pformat = format; | |
| 536 return ERROR_INT("PostScript reading is not supported\n", __func__, 1); | |
| 537 | |
| 538 case IFF_LPDF: | |
| 539 if (pformat) *pformat = format; | |
| 540 return ERROR_INT("Pdf reading is not supported\n", __func__, 1); | |
| 541 | |
| 542 case IFF_SPIX: | |
| 543 ret = readHeaderSpix(filename, &w, &h, &bps, &spp, &iscmap); | |
| 544 if (ret) | |
| 545 return ERROR_INT_1("spix: no header info returned", | |
| 546 filename, __func__, 1); | |
| 547 break; | |
| 548 | |
| 549 case IFF_UNKNOWN: | |
| 550 return ERROR_INT_1("unknown format in file", filename, __func__, 1); | |
| 551 } | |
| 552 | |
| 553 if (pw) *pw = w; | |
| 554 if (ph) *ph = h; | |
| 555 if (pbps) *pbps = bps; | |
| 556 if (pspp) *pspp = spp; | |
| 557 if (piscmap) *piscmap = iscmap; | |
| 558 if (pformat) *pformat = format; | |
| 559 return 0; | |
| 560 } | |
| 561 | |
| 562 | |
| 563 /*---------------------------------------------------------------------* | |
| 564 * Format finders * | |
| 565 *---------------------------------------------------------------------*/ | |
| 566 /*! | |
| 567 * \brief findFileFormat() | |
| 568 * | |
| 569 * \param[in] filename | |
| 570 * \param[out] pformat found format | |
| 571 * \return 0 if OK, 1 on error or if format is not recognized | |
| 572 */ | |
| 573 l_ok | |
| 574 findFileFormat(const char *filename, | |
| 575 l_int32 *pformat) | |
| 576 { | |
| 577 l_int32 ret; | |
| 578 FILE *fp; | |
| 579 | |
| 580 if (!pformat) | |
| 581 return ERROR_INT("&format not defined", __func__, 1); | |
| 582 *pformat = IFF_UNKNOWN; | |
| 583 if (!filename) | |
| 584 return ERROR_INT("filename not defined", __func__, 1); | |
| 585 | |
| 586 if ((fp = fopenReadStream(filename)) == NULL) | |
| 587 return ERROR_INT_1("image file not found", filename, __func__, 1); | |
| 588 ret = findFileFormatStream(fp, pformat); | |
| 589 fclose(fp); | |
| 590 return ret; | |
| 591 } | |
| 592 | |
| 593 | |
| 594 /*! | |
| 595 * \brief findFileFormatStream() | |
| 596 * | |
| 597 * \param[in] fp file stream | |
| 598 * \param[out] pformat found format | |
| 599 * \return 0 if OK, 1 on error or if format is not recognized | |
| 600 * | |
| 601 * <pre> | |
| 602 * Notes: | |
| 603 * (1) Important: Side effect -- this resets fp to BOF. | |
| 604 * </pre> | |
| 605 */ | |
| 606 l_ok | |
| 607 findFileFormatStream(FILE *fp, | |
| 608 l_int32 *pformat) | |
| 609 { | |
| 610 l_uint8 firstbytes[13]; | |
| 611 l_int32 format; | |
| 612 | |
| 613 if (!pformat) | |
| 614 return ERROR_INT("&format not defined", __func__, 1); | |
| 615 *pformat = IFF_UNKNOWN; | |
| 616 if (!fp) | |
| 617 return ERROR_INT("stream not defined", __func__, 1); | |
| 618 | |
| 619 rewind(fp); | |
| 620 if (fnbytesInFile(fp) < 12) | |
| 621 return ERROR_INT("truncated file", __func__, 1); | |
| 622 | |
| 623 if (fread(&firstbytes, 1, 12, fp) != 12) | |
| 624 return ERROR_INT("failed to read first 12 bytes of file", __func__, 1); | |
| 625 firstbytes[12] = 0; | |
| 626 rewind(fp); | |
| 627 | |
| 628 findFileFormatBuffer(firstbytes, &format); | |
| 629 if (format == IFF_TIFF) { | |
| 630 findTiffCompression(fp, &format); | |
| 631 rewind(fp); | |
| 632 } | |
| 633 *pformat = format; | |
| 634 if (format == IFF_UNKNOWN) | |
| 635 return 1; | |
| 636 else | |
| 637 return 0; | |
| 638 } | |
| 639 | |
| 640 | |
| 641 /*! | |
| 642 * \brief findFileFormatBuffer() | |
| 643 * | |
| 644 * \param[in] buf byte buffer at least 12 bytes in size; we can't check | |
| 645 * \param[out] pformat found format | |
| 646 * \return 0 if OK, 1 on error or if format is not recognized | |
| 647 * | |
| 648 * <pre> | |
| 649 * Notes: | |
| 650 * (1) This determines the file format from the first 12 bytes in | |
| 651 * the compressed data stream, which are stored in memory. | |
| 652 * (2) For tiff files, this returns IFF_TIFF. The specific tiff | |
| 653 * compression is then determined using findTiffCompression(). | |
| 654 * </pre> | |
| 655 */ | |
| 656 l_ok | |
| 657 findFileFormatBuffer(const l_uint8 *buf, | |
| 658 l_int32 *pformat) | |
| 659 { | |
| 660 l_uint16 twobytepw; | |
| 661 | |
| 662 if (!pformat) | |
| 663 return ERROR_INT("&format not defined", __func__, 1); | |
| 664 *pformat = IFF_UNKNOWN; | |
| 665 if (!buf) | |
| 666 return ERROR_INT("byte buffer not defined", __func__, 0); | |
| 667 | |
| 668 /* Check the bmp and tiff 2-byte header ids */ | |
| 669 ((char *)(&twobytepw))[0] = buf[0]; | |
| 670 ((char *)(&twobytepw))[1] = buf[1]; | |
| 671 | |
| 672 if (convertOnBigEnd16(twobytepw) == BMP_ID) { | |
| 673 *pformat = IFF_BMP; | |
| 674 return 0; | |
| 675 } | |
| 676 | |
| 677 if (twobytepw == TIFF_BIGEND_ID || twobytepw == TIFF_LITTLEEND_ID) { | |
| 678 *pformat = IFF_TIFF; | |
| 679 return 0; | |
| 680 } | |
| 681 | |
| 682 /* Check for the p*m 2-byte header ids */ | |
| 683 if ((buf[0] == 'P' && buf[1] == '4') || /* newer packed */ | |
| 684 (buf[0] == 'P' && buf[1] == '1')) { /* old ASCII format */ | |
| 685 *pformat = IFF_PNM; | |
| 686 return 0; | |
| 687 } | |
| 688 | |
| 689 if ((buf[0] == 'P' && buf[1] == '5') || /* newer */ | |
| 690 (buf[0] == 'P' && buf[1] == '2')) { /* old */ | |
| 691 *pformat = IFF_PNM; | |
| 692 return 0; | |
| 693 } | |
| 694 | |
| 695 if ((buf[0] == 'P' && buf[1] == '6') || /* newer */ | |
| 696 (buf[0] == 'P' && buf[1] == '3')) { /* old */ | |
| 697 *pformat = IFF_PNM; | |
| 698 return 0; | |
| 699 } | |
| 700 | |
| 701 if (buf[0] == 'P' && buf[1] == '7') { /* new arbitrary (PAM) */ | |
| 702 *pformat = IFF_PNM; | |
| 703 return 0; | |
| 704 } | |
| 705 | |
| 706 /* Consider the first 11 bytes of the standard JFIF JPEG header: | |
| 707 * - The first two bytes are the most important: 0xffd8. | |
| 708 * - The next two bytes are the jfif marker: 0xffe0. | |
| 709 * Not all jpeg files have this marker. | |
| 710 * - The next two bytes are the header length. | |
| 711 * - The next 5 bytes are a null-terminated string. | |
| 712 * For JFIF, the string is "JFIF", naturally. For others it | |
| 713 * can be "Exif" or just about anything else. | |
| 714 * - Because of all this variability, we only check the first | |
| 715 * two byte marker. All jpeg files are identified as | |
| 716 * IFF_JFIF_JPEG. */ | |
| 717 if (buf[0] == 0xff && buf[1] == 0xd8) { | |
| 718 *pformat = IFF_JFIF_JPEG; | |
| 719 return 0; | |
| 720 } | |
| 721 | |
| 722 /* Check for the 8 byte PNG signature (png_signature in png.c): | |
| 723 * {137, 80, 78, 71, 13, 10, 26, 10} */ | |
| 724 if (buf[0] == 137 && buf[1] == 80 && buf[2] == 78 && buf[3] == 71 && | |
| 725 buf[4] == 13 && buf[5] == 10 && buf[6] == 26 && buf[7] == 10) { | |
| 726 *pformat = IFF_PNG; | |
| 727 return 0; | |
| 728 } | |
| 729 | |
| 730 /* Look for "GIF87a" or "GIF89a" */ | |
| 731 if (buf[0] == 'G' && buf[1] == 'I' && buf[2] == 'F' && buf[3] == '8' && | |
| 732 (buf[4] == '7' || buf[4] == '9') && buf[5] == 'a') { | |
| 733 *pformat = IFF_GIF; | |
| 734 return 0; | |
| 735 } | |
| 736 | |
| 737 /* Check for both types of jp2k file */ | |
| 738 if (memcmp(buf, JP2K_CODESTREAM, 4) == 0 || | |
| 739 memcmp(buf, JP2K_IMAGE_DATA, 12) == 0) { | |
| 740 *pformat = IFF_JP2; | |
| 741 return 0; | |
| 742 } | |
| 743 | |
| 744 /* Check for webp */ | |
| 745 if (buf[0] == 'R' && buf[1] == 'I' && buf[2] == 'F' && buf[3] == 'F' && | |
| 746 buf[8] == 'W' && buf[9] == 'E' && buf[10] == 'B' && buf[11] == 'P') { | |
| 747 *pformat = IFF_WEBP; | |
| 748 return 0; | |
| 749 } | |
| 750 | |
| 751 /* Check for ps */ | |
| 752 if (buf[0] == '%' && buf[1] == '!' && buf[2] == 'P' && buf[3] == 'S' && | |
| 753 buf[4] == '-' && buf[5] == 'A' && buf[6] == 'd' && buf[7] == 'o' && | |
| 754 buf[8] == 'b' && buf[9] == 'e') { | |
| 755 *pformat = IFF_PS; | |
| 756 return 0; | |
| 757 } | |
| 758 | |
| 759 /* Check for pdf */ | |
| 760 if (buf[0] == '%' && buf[1] == 'P' && buf[2] == 'D' && buf[3] == 'F' && | |
| 761 buf[4] == '-' && buf[5] == '1') { | |
| 762 *pformat = IFF_LPDF; | |
| 763 return 0; | |
| 764 } | |
| 765 | |
| 766 /* Check for "spix" serialized pix */ | |
| 767 if (buf[0] == 's' && buf[1] == 'p' && buf[2] == 'i' && buf[3] == 'x') { | |
| 768 *pformat = IFF_SPIX; | |
| 769 return 0; | |
| 770 } | |
| 771 | |
| 772 /* File format identifier not found; unknown */ | |
| 773 return 1; | |
| 774 } | |
| 775 | |
| 776 | |
| 777 /*! | |
| 778 * \brief fileFormatIsTiff() | |
| 779 * | |
| 780 * \param[in] fp file stream | |
| 781 * \return 1 if file is tiff; 0 otherwise or on error | |
| 782 */ | |
| 783 l_int32 | |
| 784 fileFormatIsTiff(FILE *fp) | |
| 785 { | |
| 786 l_int32 format; | |
| 787 | |
| 788 if (!fp) | |
| 789 return ERROR_INT("stream not defined", __func__, 0); | |
| 790 | |
| 791 findFileFormatStream(fp, &format); | |
| 792 if (format == IFF_TIFF || format == IFF_TIFF_PACKBITS || | |
| 793 format == IFF_TIFF_RLE || format == IFF_TIFF_G3 || | |
| 794 format == IFF_TIFF_G4 || format == IFF_TIFF_LZW || | |
| 795 format == IFF_TIFF_ZIP || format == IFF_TIFF_JPEG) | |
| 796 return 1; | |
| 797 else | |
| 798 return 0; | |
| 799 } | |
| 800 | |
| 801 | |
| 802 /*---------------------------------------------------------------------* | |
| 803 * Read from memory * | |
| 804 *---------------------------------------------------------------------*/ | |
| 805 /*! | |
| 806 * \brief pixReadMem() | |
| 807 * | |
| 808 * \param[in] data const; encoded | |
| 809 * \param[in] size size of data | |
| 810 * \return pix, or NULL on error | |
| 811 * | |
| 812 * <pre> | |
| 813 * Notes: | |
| 814 * (1) This is a variation of pixReadStream(), where the data is read | |
| 815 * from a memory buffer rather than a file. | |
| 816 * (2) On Windows, this only reads tiff formatted files directly from | |
| 817 * memory. For other formats, it writes to a temp file and | |
| 818 * decompresses from file. | |
| 819 * (3) findFileFormatBuffer() requires up to 12 bytes to decide on | |
| 820 * the format. That determines the constraint here. But in | |
| 821 * fact the data must contain the entire compressed string for | |
| 822 * the image. | |
| 823 * </pre> | |
| 824 */ | |
| 825 PIX * | |
| 826 pixReadMem(const l_uint8 *data, | |
| 827 size_t size) | |
| 828 { | |
| 829 l_int32 format, valid; | |
| 830 PIX *pix; | |
| 831 PIXCMAP *cmap; | |
| 832 | |
| 833 if (!data) | |
| 834 return (PIX *)ERROR_PTR("data not defined", __func__, NULL); | |
| 835 if (size < 12) | |
| 836 return (PIX *)ERROR_PTR("size < 12", __func__, NULL); | |
| 837 pix = NULL; | |
| 838 | |
| 839 findFileFormatBuffer(data, &format); | |
| 840 switch (format) | |
| 841 { | |
| 842 case IFF_BMP: | |
| 843 if ((pix = pixReadMemBmp(data, size)) == NULL ) | |
| 844 return (PIX *)ERROR_PTR( "bmp: no pix returned", __func__, NULL); | |
| 845 break; | |
| 846 | |
| 847 case IFF_JFIF_JPEG: | |
| 848 if ((pix = pixReadMemJpeg(data, size, 0, 1, NULL, 0)) == NULL) | |
| 849 return (PIX *)ERROR_PTR( "jpeg: no pix returned", __func__, NULL); | |
| 850 break; | |
| 851 | |
| 852 case IFF_PNG: | |
| 853 if ((pix = pixReadMemPng(data, size)) == NULL) | |
| 854 return (PIX *)ERROR_PTR("png: no pix returned", __func__, NULL); | |
| 855 break; | |
| 856 | |
| 857 case IFF_TIFF: | |
| 858 case IFF_TIFF_PACKBITS: | |
| 859 case IFF_TIFF_RLE: | |
| 860 case IFF_TIFF_G3: | |
| 861 case IFF_TIFF_G4: | |
| 862 case IFF_TIFF_LZW: | |
| 863 case IFF_TIFF_ZIP: | |
| 864 /* Reading page 0 by default */ | |
| 865 if ((pix = pixReadMemTiff(data, size, 0)) == NULL) | |
| 866 return (PIX *)ERROR_PTR("tiff: no pix returned", __func__, NULL); | |
| 867 break; | |
| 868 | |
| 869 case IFF_PNM: | |
| 870 if ((pix = pixReadMemPnm(data, size)) == NULL) | |
| 871 return (PIX *)ERROR_PTR("pnm: no pix returned", __func__, NULL); | |
| 872 break; | |
| 873 | |
| 874 case IFF_GIF: | |
| 875 if ((pix = pixReadMemGif(data, size)) == NULL) | |
| 876 return (PIX *)ERROR_PTR("gif: no pix returned", __func__, NULL); | |
| 877 break; | |
| 878 | |
| 879 case IFF_JP2: | |
| 880 if ((pix = pixReadMemJp2k(data, size, 1, NULL, 0, 0)) == NULL) | |
| 881 return (PIX *)ERROR_PTR("jp2k: no pix returned", __func__, NULL); | |
| 882 break; | |
| 883 | |
| 884 case IFF_WEBP: | |
| 885 if ((pix = pixReadMemWebP(data, size)) == NULL) | |
| 886 return (PIX *)ERROR_PTR("webp: no pix returned", __func__, NULL); | |
| 887 break; | |
| 888 | |
| 889 case IFF_PS: | |
| 890 L_ERROR("PostScript reading is not supported\n", __func__); | |
| 891 return NULL; | |
| 892 | |
| 893 case IFF_LPDF: | |
| 894 L_ERROR("Pdf reading is not supported\n", __func__); | |
| 895 return NULL; | |
| 896 | |
| 897 case IFF_SPIX: | |
| 898 if ((pix = pixReadMemSpix(data, size)) == NULL) | |
| 899 return (PIX *)ERROR_PTR("spix: no pix returned", __func__, NULL); | |
| 900 break; | |
| 901 | |
| 902 case IFF_UNKNOWN: | |
| 903 return (PIX *)ERROR_PTR("Unknown format: no pix returned", | |
| 904 __func__, NULL); | |
| 905 break; | |
| 906 } | |
| 907 | |
| 908 /* Set the input format. For tiff reading from memory we lose | |
| 909 * the actual input format; for 1 bpp, default to G4. Also | |
| 910 * verify that the colormap is valid. */ | |
| 911 if (pix) { | |
| 912 if (format == IFF_TIFF && pixGetDepth(pix) == 1) | |
| 913 format = IFF_TIFF_G4; | |
| 914 pixSetInputFormat(pix, format); | |
| 915 if ((cmap = pixGetColormap(pix))) { | |
| 916 pixcmapIsValid(cmap, pix, &valid); | |
| 917 if (!valid) { | |
| 918 pixDestroy(&pix); | |
| 919 return (PIX *)ERROR_PTR("invalid colormap", __func__, NULL); | |
| 920 } | |
| 921 } | |
| 922 pixSetPadBits(pix, 0); | |
| 923 } | |
| 924 return pix; | |
| 925 } | |
| 926 | |
| 927 | |
| 928 /*! | |
| 929 * \brief pixReadHeaderMem() | |
| 930 * | |
| 931 * \param[in] data const; encoded | |
| 932 * \param[in] size size of data | |
| 933 * \param[out] pformat [optional] image format | |
| 934 * \param[out] pw, ph [optional] width and height | |
| 935 * \param[out] pbps [optional] bits/sample | |
| 936 * \param[out] pspp [optional] samples/pixel 1, 3 or 4 | |
| 937 * \param[out] piscmap [optional] 1 if cmap exists; 0 otherwise | |
| 938 * \return 0 if OK, 1 on error | |
| 939 * | |
| 940 * <pre> | |
| 941 * Notes: | |
| 942 * (1) This reads the actual headers for jpeg, png, tiff, jp2k and pnm. | |
| 943 * For bmp and gif, we cheat and read all the data into a pix, | |
| 944 * from which we extract the "header" information. | |
| 945 * (2) The amount of data required depends on the format. For | |
| 946 * png, it requires less than 30 bytes, but for jpeg it can | |
| 947 * require most of the compressed file. In practice, the data | |
| 948 * is typically the entire compressed file in memory. | |
| 949 * (3) findFileFormatBuffer() requires up to 12 bytes to decide on | |
| 950 * the format, which we require. | |
| 951 * </pre> | |
| 952 */ | |
| 953 l_ok | |
| 954 pixReadHeaderMem(const l_uint8 *data, | |
| 955 size_t size, | |
| 956 l_int32 *pformat, | |
| 957 l_int32 *pw, | |
| 958 l_int32 *ph, | |
| 959 l_int32 *pbps, | |
| 960 l_int32 *pspp, | |
| 961 l_int32 *piscmap) | |
| 962 { | |
| 963 l_int32 format, ret, w, h, d, bps, spp, iscmap; | |
| 964 l_int32 type; /* not used */ | |
| 965 PIX *pix; | |
| 966 | |
| 967 if (pw) *pw = 0; | |
| 968 if (ph) *ph = 0; | |
| 969 if (pbps) *pbps = 0; | |
| 970 if (pspp) *pspp = 0; | |
| 971 if (piscmap) *piscmap = 0; | |
| 972 if (pformat) *pformat = 0; | |
| 973 iscmap = 0; /* init to false */ | |
| 974 if (!data) | |
| 975 return ERROR_INT("data not defined", __func__, 1); | |
| 976 if (size < 12) | |
| 977 return ERROR_INT("size < 12", __func__, 1); | |
| 978 | |
| 979 findFileFormatBuffer(data, &format); | |
| 980 | |
| 981 switch (format) | |
| 982 { | |
| 983 case IFF_BMP: /* cheating: read the pix */ | |
| 984 if ((pix = pixReadMemBmp(data, size)) == NULL) | |
| 985 return ERROR_INT( "bmp: pix not read", __func__, 1); | |
| 986 pixGetDimensions(pix, &w, &h, &d); | |
| 987 pixDestroy(&pix); | |
| 988 bps = (d == 32) ? 8 : d; | |
| 989 spp = (d == 32) ? 3 : 1; | |
| 990 break; | |
| 991 | |
| 992 case IFF_JFIF_JPEG: | |
| 993 ret = readHeaderMemJpeg(data, size, &w, &h, &spp, NULL, NULL); | |
| 994 bps = 8; | |
| 995 if (ret) | |
| 996 return ERROR_INT( "jpeg: no header info returned", __func__, 1); | |
| 997 break; | |
| 998 | |
| 999 case IFF_PNG: | |
| 1000 ret = readHeaderMemPng(data, size, &w, &h, &bps, &spp, &iscmap); | |
| 1001 if (ret) | |
| 1002 return ERROR_INT( "png: no header info returned", __func__, 1); | |
| 1003 break; | |
| 1004 | |
| 1005 case IFF_TIFF: | |
| 1006 case IFF_TIFF_PACKBITS: | |
| 1007 case IFF_TIFF_RLE: | |
| 1008 case IFF_TIFF_G3: | |
| 1009 case IFF_TIFF_G4: | |
| 1010 case IFF_TIFF_LZW: | |
| 1011 case IFF_TIFF_ZIP: | |
| 1012 case IFF_TIFF_JPEG: | |
| 1013 /* Reading page 0 by default; possibly redefine format */ | |
| 1014 ret = readHeaderMemTiff(data, size, 0, &w, &h, &bps, &spp, | |
| 1015 NULL, &iscmap, &format); | |
| 1016 if (ret) | |
| 1017 return ERROR_INT( "tiff: no header info returned", __func__, 1); | |
| 1018 break; | |
| 1019 | |
| 1020 case IFF_PNM: | |
| 1021 ret = readHeaderMemPnm(data, size, &w, &h, &d, &type, &bps, &spp); | |
| 1022 if (ret) | |
| 1023 return ERROR_INT( "pnm: no header info returned", __func__, 1); | |
| 1024 break; | |
| 1025 | |
| 1026 case IFF_GIF: /* cheating: read the pix */ | |
| 1027 if ((pix = pixReadMemGif(data, size)) == NULL) | |
| 1028 return ERROR_INT( "gif: pix not read", __func__, 1); | |
| 1029 pixGetDimensions(pix, &w, &h, &d); | |
| 1030 pixDestroy(&pix); | |
| 1031 iscmap = 1; /* always colormapped; max 256 colors */ | |
| 1032 spp = 1; | |
| 1033 bps = d; | |
| 1034 break; | |
| 1035 | |
| 1036 case IFF_JP2: | |
| 1037 ret = readHeaderMemJp2k(data, size, &w, &h, &bps, &spp, NULL); | |
| 1038 break; | |
| 1039 | |
| 1040 case IFF_WEBP: | |
| 1041 bps = 8; | |
| 1042 ret = readHeaderMemWebP(data, size, &w, &h, &spp); | |
| 1043 break; | |
| 1044 | |
| 1045 case IFF_PS: | |
| 1046 if (pformat) *pformat = format; | |
| 1047 return ERROR_INT("PostScript reading is not supported\n", __func__, 1); | |
| 1048 | |
| 1049 case IFF_LPDF: | |
| 1050 if (pformat) *pformat = format; | |
| 1051 return ERROR_INT("Pdf reading is not supported\n", __func__, 1); | |
| 1052 | |
| 1053 case IFF_SPIX: | |
| 1054 ret = sreadHeaderSpix((l_uint32 *)data, size, &w, &h, &bps, | |
| 1055 &spp, &iscmap); | |
| 1056 if (ret) | |
| 1057 return ERROR_INT( "pnm: no header info returned", __func__, 1); | |
| 1058 break; | |
| 1059 | |
| 1060 case IFF_UNKNOWN: | |
| 1061 return ERROR_INT("unknown format; no data returned", __func__, 1); | |
| 1062 break; | |
| 1063 } | |
| 1064 | |
| 1065 if (pw) *pw = w; | |
| 1066 if (ph) *ph = h; | |
| 1067 if (pbps) *pbps = bps; | |
| 1068 if (pspp) *pspp = spp; | |
| 1069 if (piscmap) *piscmap = iscmap; | |
| 1070 if (pformat) *pformat = format; | |
| 1071 return 0; | |
| 1072 } | |
| 1073 | |
| 1074 | |
| 1075 /*---------------------------------------------------------------------* | |
| 1076 * Output image file information * | |
| 1077 *---------------------------------------------------------------------*/ | |
| 1078 extern const char *ImageFileFormatExtensions[]; | |
| 1079 | |
| 1080 /*! | |
| 1081 * \brief writeImageFileInfo() | |
| 1082 * | |
| 1083 * \param[in] filename input file | |
| 1084 * \param[in] fpout output file stream | |
| 1085 * \param[in] headeronly 1 to read only the header; 0 to read both | |
| 1086 * the header and the input file | |
| 1087 * \return 0 if OK; 1 on error | |
| 1088 * | |
| 1089 * <pre> | |
| 1090 * Notes: | |
| 1091 * (1) If headeronly == 0 and the image has spp == 4,this will | |
| 1092 * also call pixDisplayLayersRGBA() to display the image | |
| 1093 * in three views. | |
| 1094 * (2) This is a debug function that changes the value of | |
| 1095 * var_PNG_STRIP_16_TO_8 to 1 (the default). | |
| 1096 * </pre> | |
| 1097 */ | |
| 1098 l_ok | |
| 1099 writeImageFileInfo(const char *filename, | |
| 1100 FILE *fpout, | |
| 1101 l_int32 headeronly) | |
| 1102 { | |
| 1103 char *text; | |
| 1104 l_int32 w, h, d, wpl, count, npages, color; | |
| 1105 l_int32 format, bps, spp, iscmap, xres, yres, transparency; | |
| 1106 FILE *fpin; | |
| 1107 PIX *pix, *pixt; | |
| 1108 PIXCMAP *cmap; | |
| 1109 | |
| 1110 if (!filename) | |
| 1111 return ERROR_INT("filename not defined", __func__, 1); | |
| 1112 if (!fpout) | |
| 1113 return ERROR_INT("stream not defined", __func__, 1); | |
| 1114 | |
| 1115 /* Read the header */ | |
| 1116 if (pixReadHeader(filename, &format, &w, &h, &bps, &spp, &iscmap)) { | |
| 1117 L_ERROR("failure to read header of %s\n", __func__, filename); | |
| 1118 return 1; | |
| 1119 } | |
| 1120 fprintf(fpout, "===============================================\n" | |
| 1121 "Reading the header:\n"); | |
| 1122 fprintf(fpout, " input image format type: %s\n", | |
| 1123 ImageFileFormatExtensions[format]); | |
| 1124 fprintf(fpout, " w = %d, h = %d, bps = %d, spp = %d, iscmap = %d\n", | |
| 1125 w, h, bps, spp, iscmap); | |
| 1126 | |
| 1127 findFileFormat(filename, &format); | |
| 1128 if (format == IFF_JP2) { | |
| 1129 fpin = fopenReadStream(filename); | |
| 1130 fgetJp2kResolution(fpin, &xres, &yres); | |
| 1131 if (fpin) fclose(fpin); | |
| 1132 fprintf(fpout, " xres = %d, yres = %d\n", xres, yres); | |
| 1133 } else if (format == IFF_PNG) { | |
| 1134 fpin = fopenReadStream(filename); | |
| 1135 fgetPngResolution(fpin, &xres, &yres); | |
| 1136 if (fpin) fclose(fpin); | |
| 1137 fprintf(fpout, " xres = %d, yres = %d\n", xres, yres); | |
| 1138 if (iscmap) { | |
| 1139 fpin = fopenReadStream(filename); | |
| 1140 fgetPngColormapInfo(fpin, &cmap, &transparency); | |
| 1141 if (fpin) fclose(fpin); | |
| 1142 if (transparency) | |
| 1143 fprintf(fpout, " colormap has transparency\n"); | |
| 1144 else | |
| 1145 fprintf(fpout, " colormap does not have transparency\n"); | |
| 1146 pixcmapWriteStream(fpout, cmap); | |
| 1147 pixcmapDestroy(&cmap); | |
| 1148 } | |
| 1149 } else if (format == IFF_JFIF_JPEG) { | |
| 1150 fpin = fopenReadStream(filename); | |
| 1151 fgetJpegResolution(fpin, &xres, &yres); | |
| 1152 if (fpin) fclose(fpin); | |
| 1153 fprintf(fpout, " xres = %d, yres = %d\n", xres, yres); | |
| 1154 } | |
| 1155 | |
| 1156 if (headeronly) | |
| 1157 return 0; | |
| 1158 | |
| 1159 /* Read the full image. Note that when we read an image that | |
| 1160 * has transparency in a colormap, we convert it to RGBA. */ | |
| 1161 fprintf(fpout, "===============================================\n" | |
| 1162 "Reading the full image:\n"); | |
| 1163 | |
| 1164 /* Preserve 16 bpp if the format is png */ | |
| 1165 if (format == IFF_PNG && bps == 16) | |
| 1166 l_pngSetReadStrip16To8(0); | |
| 1167 | |
| 1168 if ((pix = pixRead(filename)) == NULL) { | |
| 1169 L_ERROR("failure to read full image of %s\n", __func__, filename); | |
| 1170 return 1; | |
| 1171 } | |
| 1172 | |
| 1173 format = pixGetInputFormat(pix); | |
| 1174 pixGetDimensions(pix, &w, &h, &d); | |
| 1175 wpl = pixGetWpl(pix); | |
| 1176 spp = pixGetSpp(pix); | |
| 1177 fprintf(fpout, " input image format type: %s\n", | |
| 1178 ImageFileFormatExtensions[format]); | |
| 1179 fprintf(fpout, " w = %d, h = %d, d = %d, spp = %d, wpl = %d\n", | |
| 1180 w, h, d, spp, wpl); | |
| 1181 fprintf(fpout, " xres = %d, yres = %d\n", | |
| 1182 pixGetXRes(pix), pixGetYRes(pix)); | |
| 1183 | |
| 1184 text = pixGetText(pix); | |
| 1185 if (text) /* not null */ | |
| 1186 fprintf(fpout, " text: %s\n", text); | |
| 1187 | |
| 1188 cmap = pixGetColormap(pix); | |
| 1189 if (cmap) { | |
| 1190 pixcmapHasColor(cmap, &color); | |
| 1191 if (color) | |
| 1192 fprintf(fpout, " colormap exists and has color values:"); | |
| 1193 else | |
| 1194 fprintf(fpout, " colormap exists and has only gray values:"); | |
| 1195 pixcmapWriteStream(fpout, pixGetColormap(pix)); | |
| 1196 } | |
| 1197 else | |
| 1198 fprintf(fpout, " colormap does not exist\n"); | |
| 1199 | |
| 1200 if (format == IFF_TIFF || format == IFF_TIFF_G4 || | |
| 1201 format == IFF_TIFF_G3 || format == IFF_TIFF_PACKBITS) { | |
| 1202 fprintf(fpout, " Tiff header information:\n"); | |
| 1203 fpin = fopenReadStream(filename); | |
| 1204 tiffGetCount(fpin, &npages); | |
| 1205 if (fpin) fclose(fpin); | |
| 1206 if (npages == 1) | |
| 1207 fprintf(fpout, " One page in file\n"); | |
| 1208 else | |
| 1209 fprintf(fpout, " %d pages in file\n", npages); | |
| 1210 fprintTiffInfo(fpout, filename); | |
| 1211 } | |
| 1212 | |
| 1213 if (d == 1) { | |
| 1214 pixCountPixels(pix, &count, NULL); | |
| 1215 pixGetDimensions(pix, &w, &h, NULL); | |
| 1216 fprintf(fpout, " 1 bpp: foreground pixel fraction ON/Total = %g\n", | |
| 1217 (l_float32)count / (l_float32)(w * h)); | |
| 1218 } | |
| 1219 fprintf(fpout, "===============================================\n"); | |
| 1220 | |
| 1221 /* If there is an alpha component, visualize it. Note that when | |
| 1222 * alpha == 0, the rgb layer is transparent. We visualize the | |
| 1223 * result when a white background is visible through the | |
| 1224 * transparency layer. */ | |
| 1225 if (pixGetSpp(pix) == 4) { | |
| 1226 pixt = pixDisplayLayersRGBA(pix, 0xffffff00, 600); | |
| 1227 pixDisplay(pixt, 100, 100); | |
| 1228 pixDestroy(&pixt); | |
| 1229 } | |
| 1230 | |
| 1231 if (format == IFF_PNG && bps == 16) | |
| 1232 l_pngSetReadStrip16To8(1); /* return to default if format is png */ | |
| 1233 | |
| 1234 pixDestroy(&pix); | |
| 1235 return 0; | |
| 1236 } | |
| 1237 | |
| 1238 | |
| 1239 /*---------------------------------------------------------------------* | |
| 1240 * Test function for I/O with different formats * | |
| 1241 *---------------------------------------------------------------------*/ | |
| 1242 /*! | |
| 1243 * \brief ioFormatTest() | |
| 1244 * | |
| 1245 * \param[in] filename input image file | |
| 1246 * \return 0 if OK; 1 on error or if the test fails | |
| 1247 * | |
| 1248 * <pre> | |
| 1249 * Notes: | |
| 1250 * (1) This writes and reads a set of output files losslessly | |
| 1251 * in different formats to /tmp/format/, and tests that the | |
| 1252 * result before and after is unchanged. | |
| 1253 * (2) This should work properly on input images of any depth, | |
| 1254 * with and without colormaps. | |
| 1255 * (3) All supported formats are tested for bmp, png, tiff and | |
| 1256 * non-ascii pnm. Ascii pnm also works (but who'd ever want | |
| 1257 * to use it?) We allow 2 bpp bmp, although it's not | |
| 1258 * supported elsewhere. And we don't support reading | |
| 1259 * 16 bpp png, although this can be turned on in pngio.c. | |
| 1260 * (4) This silently skips png or tiff testing if HAVE_LIBPNG | |
| 1261 * or HAVE_LIBTIFF are 0, respectively. | |
| 1262 * </pre> | |
| 1263 */ | |
| 1264 l_ok | |
| 1265 ioFormatTest(const char *filename) | |
| 1266 { | |
| 1267 l_int32 w, h, d, equal, problems; | |
| 1268 #if HAVE_LIBJPEG || HAVE_LIBWEBP || HAVE_LIBJP2K | |
| 1269 l_int32 depth; | |
| 1270 #endif | |
| 1271 #if HAVE_LIBJPEG || HAVE_LIBTIFF || HAVE_LIBWEBP || HAVE_LIBJP2K | |
| 1272 l_float32 diff; | |
| 1273 #endif | |
| 1274 BOX *box; | |
| 1275 PIX *pixs, *pixc, *pix1, *pix2; | |
| 1276 PIXCMAP *cmap; | |
| 1277 | |
| 1278 if (!filename) | |
| 1279 return ERROR_INT("filename not defined", __func__, 1); | |
| 1280 | |
| 1281 /* Read the input file and limit the size */ | |
| 1282 if ((pix1 = pixRead(filename)) == NULL) | |
| 1283 return ERROR_INT("pix1 not made", __func__, 1); | |
| 1284 pixGetDimensions(pix1, &w, &h, NULL); | |
| 1285 if (w > 250 && h > 250) { /* take the central 250 x 250 region */ | |
| 1286 box = boxCreate(w / 2 - 125, h / 2 - 125, 250, 250); | |
| 1287 pixs = pixClipRectangle(pix1, box, NULL); | |
| 1288 boxDestroy(&box); | |
| 1289 } else { | |
| 1290 pixs = pixClone(pix1); | |
| 1291 } | |
| 1292 pixDestroy(&pix1); | |
| 1293 | |
| 1294 lept_mkdir("lept/format"); | |
| 1295 | |
| 1296 /* Note that the reader automatically removes colormaps | |
| 1297 * from 1 bpp BMP images, but not from 8 bpp BMP images. | |
| 1298 * Therefore, if our 8 bpp image initially doesn't have a | |
| 1299 * colormap, we are going to need to remove it from any | |
| 1300 * pix read from a BMP file. */ | |
| 1301 pixc = pixClone(pixs); /* laziness */ | |
| 1302 | |
| 1303 /* This does not test the alpha layer pixels, because most | |
| 1304 * formats don't support it. Remove any alpha. */ | |
| 1305 if (pixGetSpp(pixc) == 4) | |
| 1306 pixSetSpp(pixc, 3); | |
| 1307 cmap = pixGetColormap(pixc); /* colormap; can be NULL */ | |
| 1308 d = pixGetDepth(pixc); | |
| 1309 | |
| 1310 problems = FALSE; | |
| 1311 | |
| 1312 /* ----------------------- BMP -------------------------- */ | |
| 1313 | |
| 1314 /* BMP works for 1, 2, 4, 8 and 32 bpp images. | |
| 1315 * It always writes colormaps for 1 and 8 bpp, so we must | |
| 1316 * remove it after readback if the input image doesn't have | |
| 1317 * a colormap. Although we can write/read 2 bpp BMP, nobody | |
| 1318 * else can read them! */ | |
| 1319 if (d == 1 || d == 8) { | |
| 1320 L_INFO("write/read bmp\n", __func__); | |
| 1321 pixWrite(FILE_BMP, pixc, IFF_BMP); | |
| 1322 pix1 = pixRead(FILE_BMP); | |
| 1323 if (!cmap) | |
| 1324 pix2 = pixRemoveColormap(pix1, REMOVE_CMAP_BASED_ON_SRC); | |
| 1325 else | |
| 1326 pix2 = pixClone(pix1); | |
| 1327 pixEqual(pixc, pix2, &equal); | |
| 1328 if (!equal) { | |
| 1329 L_INFO(" **** bad bmp image: d = %d ****\n", __func__, d); | |
| 1330 problems = TRUE; | |
| 1331 } | |
| 1332 pixDestroy(&pix1); | |
| 1333 pixDestroy(&pix2); | |
| 1334 } | |
| 1335 | |
| 1336 if (d == 2 || d == 4 || d == 32) { | |
| 1337 L_INFO("write/read bmp\n", __func__); | |
| 1338 pixWrite(FILE_BMP, pixc, IFF_BMP); | |
| 1339 pix1 = pixRead(FILE_BMP); | |
| 1340 pixEqual(pixc, pix1, &equal); | |
| 1341 if (!equal) { | |
| 1342 L_INFO(" **** bad bmp image: d = %d ****\n", __func__, d); | |
| 1343 problems = TRUE; | |
| 1344 } | |
| 1345 pixDestroy(&pix1); | |
| 1346 } | |
| 1347 | |
| 1348 /* ----------------------- PNG -------------------------- */ | |
| 1349 #if HAVE_LIBPNG | |
| 1350 /* PNG works for all depths, but here, because we strip | |
| 1351 * 16 --> 8 bpp on reading, we don't test png for 16 bpp. */ | |
| 1352 if (d != 16) { | |
| 1353 L_INFO("write/read png\n", __func__); | |
| 1354 pixWrite(FILE_PNG, pixc, IFF_PNG); | |
| 1355 pix1 = pixRead(FILE_PNG); | |
| 1356 pixEqual(pixc, pix1, &equal); | |
| 1357 if (!equal) { | |
| 1358 L_INFO(" **** bad png image: d = %d ****\n", __func__, d); | |
| 1359 problems = TRUE; | |
| 1360 } | |
| 1361 pixDestroy(&pix1); | |
| 1362 } | |
| 1363 #endif /* HAVE_LIBPNG */ | |
| 1364 | |
| 1365 /* ----------------------- TIFF -------------------------- */ | |
| 1366 #if HAVE_LIBTIFF && HAVE_LIBJPEG | |
| 1367 /* TIFF works for 1, 2, 4, 8, 16 and 32 bpp images. | |
| 1368 * Because 8 bpp tiff always writes 256 entry colormaps, the | |
| 1369 * colormap sizes may be different for 8 bpp images with | |
| 1370 * colormap; we are testing if the image content is the same. | |
| 1371 * Likewise, the 2 and 4 bpp tiff images with colormaps | |
| 1372 * have colormap sizes 4 and 16, rsp. This test should | |
| 1373 * work properly on the content, regardless of the number | |
| 1374 * of color entries in pixc. */ | |
| 1375 | |
| 1376 /* tiff uncompressed works for all pixel depths */ | |
| 1377 L_INFO("write/read uncompressed tiff\n", __func__); | |
| 1378 pixWrite(FILE_TIFF, pixc, IFF_TIFF); | |
| 1379 pix1 = pixRead(FILE_TIFF); | |
| 1380 pixEqual(pixc, pix1, &equal); | |
| 1381 if (!equal) { | |
| 1382 L_INFO(" **** bad tiff uncompressed image: d = %d ****\n", | |
| 1383 __func__, d); | |
| 1384 problems = TRUE; | |
| 1385 } | |
| 1386 pixDestroy(&pix1); | |
| 1387 | |
| 1388 /* tiff lzw works for all pixel depths */ | |
| 1389 L_INFO("write/read lzw compressed tiff\n", __func__); | |
| 1390 pixWrite(FILE_LZW, pixc, IFF_TIFF_LZW); | |
| 1391 pix1 = pixRead(FILE_LZW); | |
| 1392 pixEqual(pixc, pix1, &equal); | |
| 1393 if (!equal) { | |
| 1394 L_INFO(" **** bad tiff lzw compressed image: d = %d ****\n", | |
| 1395 __func__, d); | |
| 1396 problems = TRUE; | |
| 1397 } | |
| 1398 pixDestroy(&pix1); | |
| 1399 | |
| 1400 /* tiff adobe deflate (zip) works for all pixel depths */ | |
| 1401 L_INFO("write/read zip compressed tiff\n", __func__); | |
| 1402 pixWrite(FILE_ZIP, pixc, IFF_TIFF_ZIP); | |
| 1403 pix1 = pixRead(FILE_ZIP); | |
| 1404 pixEqual(pixc, pix1, &equal); | |
| 1405 if (!equal) { | |
| 1406 L_INFO(" **** bad tiff zip compressed image: d = %d ****\n", | |
| 1407 __func__, d); | |
| 1408 problems = TRUE; | |
| 1409 } | |
| 1410 pixDestroy(&pix1); | |
| 1411 | |
| 1412 /* tiff jpeg encoding works for grayscale and rgb */ | |
| 1413 if (d == 8 || d == 32) { | |
| 1414 PIX *pixc1; | |
| 1415 L_INFO("write/read jpeg compressed tiff\n", __func__); | |
| 1416 if (d == 8 && pixGetColormap(pixc)) { | |
| 1417 pixc1 = pixRemoveColormap(pixc, REMOVE_CMAP_BASED_ON_SRC); | |
| 1418 pixWrite(FILE_TIFF_JPEG, pixc1, IFF_TIFF_JPEG); | |
| 1419 if ((pix1 = pixRead(FILE_TIFF_JPEG)) == NULL) { | |
| 1420 L_INFO(" did not read FILE_TIFF_JPEG\n", __func__); | |
| 1421 problems = TRUE; | |
| 1422 } | |
| 1423 pixDestroy(&pixc1); | |
| 1424 } else { | |
| 1425 pixWrite(FILE_TIFF_JPEG, pixc, IFF_TIFF_JPEG); | |
| 1426 pix1 = pixRead(FILE_TIFF_JPEG); | |
| 1427 if (d == 8) { | |
| 1428 pixCompareGray(pix1, pixc, L_COMPARE_ABS_DIFF, 0, NULL, &diff, | |
| 1429 NULL, NULL); | |
| 1430 } else { | |
| 1431 pixCompareRGB(pix1, pixc, L_COMPARE_ABS_DIFF, 0, NULL, &diff, | |
| 1432 NULL, NULL); | |
| 1433 } | |
| 1434 if (diff > 8.0) { | |
| 1435 L_INFO(" **** bad tiff jpeg compressed image: " | |
| 1436 "d = %d, diff = %5.2f ****\n", __func__, d, diff); | |
| 1437 problems = TRUE; | |
| 1438 } | |
| 1439 } | |
| 1440 pixDestroy(&pix1); | |
| 1441 } | |
| 1442 | |
| 1443 /* tiff g4, g3, rle and packbits work for 1 bpp */ | |
| 1444 if (d == 1) { | |
| 1445 L_INFO("write/read g4 compressed tiff\n", __func__); | |
| 1446 pixWrite(FILE_G4, pixc, IFF_TIFF_G4); | |
| 1447 pix1 = pixRead(FILE_G4); | |
| 1448 pixEqual(pixc, pix1, &equal); | |
| 1449 if (!equal) { | |
| 1450 L_INFO(" **** bad tiff g4 image ****\n", __func__); | |
| 1451 problems = TRUE; | |
| 1452 } | |
| 1453 pixDestroy(&pix1); | |
| 1454 | |
| 1455 L_INFO("write/read g3 compressed tiff\n", __func__); | |
| 1456 pixWrite(FILE_G3, pixc, IFF_TIFF_G3); | |
| 1457 pix1 = pixRead(FILE_G3); | |
| 1458 pixEqual(pixc, pix1, &equal); | |
| 1459 if (!equal) { | |
| 1460 L_INFO(" **** bad tiff g3 image ****\n", __func__); | |
| 1461 problems = TRUE; | |
| 1462 } | |
| 1463 pixDestroy(&pix1); | |
| 1464 | |
| 1465 L_INFO("write/read rle compressed tiff\n", __func__); | |
| 1466 pixWrite(FILE_RLE, pixc, IFF_TIFF_RLE); | |
| 1467 pix1 = pixRead(FILE_RLE); | |
| 1468 pixEqual(pixc, pix1, &equal); | |
| 1469 if (!equal) { | |
| 1470 L_INFO(" **** bad tiff rle image: d = %d ****\n", __func__, d); | |
| 1471 problems = TRUE; | |
| 1472 } | |
| 1473 pixDestroy(&pix1); | |
| 1474 | |
| 1475 L_INFO("write/read packbits compressed tiff\n", __func__); | |
| 1476 pixWrite(FILE_PB, pixc, IFF_TIFF_PACKBITS); | |
| 1477 pix1 = pixRead(FILE_PB); | |
| 1478 pixEqual(pixc, pix1, &equal); | |
| 1479 if (!equal) { | |
| 1480 L_INFO(" **** bad tiff packbits image: d = %d ****\n", | |
| 1481 __func__, d); | |
| 1482 problems = TRUE; | |
| 1483 } | |
| 1484 pixDestroy(&pix1); | |
| 1485 } | |
| 1486 #endif /* HAVE_LIBTIFF && HAVE_LIBJPEG */ | |
| 1487 | |
| 1488 /* ----------------------- PNM -------------------------- */ | |
| 1489 | |
| 1490 /* pnm works for 1, 2, 4, 8, 16 and 32 bpp. | |
| 1491 * pnm doesn't have colormaps, so when we write colormapped | |
| 1492 * pix out as pnm, the colormap is removed. Thus for the test, | |
| 1493 * we must remove the colormap from pixc before testing. */ | |
| 1494 L_INFO("write/read pnm\n", __func__); | |
| 1495 pixWrite(FILE_PNM, pixc, IFF_PNM); | |
| 1496 pix1 = pixRead(FILE_PNM); | |
| 1497 if (cmap) | |
| 1498 pix2 = pixRemoveColormap(pixc, REMOVE_CMAP_BASED_ON_SRC); | |
| 1499 else | |
| 1500 pix2 = pixClone(pixc); | |
| 1501 pixEqual(pix1, pix2, &equal); | |
| 1502 if (!equal) { | |
| 1503 L_INFO(" **** bad pnm image: d = %d ****\n", __func__, d); | |
| 1504 problems = TRUE; | |
| 1505 } | |
| 1506 pixDestroy(&pix1); | |
| 1507 pixDestroy(&pix2); | |
| 1508 | |
| 1509 /* ----------------------- GIF -------------------------- */ | |
| 1510 #if HAVE_LIBGIF | |
| 1511 /* GIF works for only 1 and 8 bpp, colormapped */ | |
| 1512 if (d != 8 || !cmap) | |
| 1513 pix1 = pixConvertTo8(pixc, 1); | |
| 1514 else | |
| 1515 pix1 = pixClone(pixc); | |
| 1516 L_INFO("write/read gif\n", __func__); | |
| 1517 pixWrite(FILE_GIF, pix1, IFF_GIF); | |
| 1518 pix2 = pixRead(FILE_GIF); | |
| 1519 pixEqual(pix1, pix2, &equal); | |
| 1520 if (!equal) { | |
| 1521 L_INFO(" **** bad gif image: d = %d ****\n", __func__, d); | |
| 1522 problems = TRUE; | |
| 1523 } | |
| 1524 pixDestroy(&pix1); | |
| 1525 pixDestroy(&pix2); | |
| 1526 #endif /* HAVE_LIBGIF */ | |
| 1527 | |
| 1528 /* ----------------------- JPEG ------------------------- */ | |
| 1529 #if HAVE_LIBJPEG | |
| 1530 /* JPEG works for only 8 bpp gray and rgb */ | |
| 1531 if (cmap || d > 8) | |
| 1532 pix1 = pixConvertTo32(pixc); | |
| 1533 else | |
| 1534 pix1 = pixConvertTo8(pixc, 0); | |
| 1535 depth = pixGetDepth(pix1); | |
| 1536 L_INFO("write/read jpeg\n", __func__); | |
| 1537 pixWrite(FILE_JPG, pix1, IFF_JFIF_JPEG); | |
| 1538 pix2 = pixRead(FILE_JPG); | |
| 1539 if (depth == 8) { | |
| 1540 pixCompareGray(pix1, pix2, L_COMPARE_ABS_DIFF, 0, NULL, &diff, | |
| 1541 NULL, NULL); | |
| 1542 } else { | |
| 1543 pixCompareRGB(pix1, pix2, L_COMPARE_ABS_DIFF, 0, NULL, &diff, | |
| 1544 NULL, NULL); | |
| 1545 } | |
| 1546 if (diff > 8.0) { | |
| 1547 L_INFO(" **** bad jpeg image: d = %d, diff = %5.2f ****\n", | |
| 1548 __func__, depth, diff); | |
| 1549 problems = TRUE; | |
| 1550 } | |
| 1551 pixDestroy(&pix1); | |
| 1552 pixDestroy(&pix2); | |
| 1553 #endif /* HAVE_LIBJPEG */ | |
| 1554 | |
| 1555 /* ----------------------- WEBP ------------------------- */ | |
| 1556 #if HAVE_LIBWEBP | |
| 1557 /* WEBP works for rgb and rgba */ | |
| 1558 if (cmap || d <= 16) | |
| 1559 pix1 = pixConvertTo32(pixc); | |
| 1560 else | |
| 1561 pix1 = pixClone(pixc); | |
| 1562 depth = pixGetDepth(pix1); | |
| 1563 L_INFO("write/read webp\n", __func__); | |
| 1564 pixWrite(FILE_WEBP, pix1, IFF_WEBP); | |
| 1565 pix2 = pixRead(FILE_WEBP); | |
| 1566 pixCompareRGB(pix1, pix2, L_COMPARE_ABS_DIFF, 0, NULL, &diff, NULL, NULL); | |
| 1567 if (diff > 5.0) { | |
| 1568 L_INFO(" **** bad webp image: d = %d, diff = %5.2f ****\n", | |
| 1569 __func__, depth, diff); | |
| 1570 problems = TRUE; | |
| 1571 } | |
| 1572 pixDestroy(&pix1); | |
| 1573 pixDestroy(&pix2); | |
| 1574 #endif /* HAVE_LIBWEBP */ | |
| 1575 | |
| 1576 /* ----------------------- JP2K ------------------------- */ | |
| 1577 #if HAVE_LIBJP2K | |
| 1578 /* JP2K works for only 8 bpp gray, rgb and rgba */ | |
| 1579 if (cmap || d > 8) | |
| 1580 pix1 = pixConvertTo32(pixc); | |
| 1581 else | |
| 1582 pix1 = pixConvertTo8(pixc, 0); | |
| 1583 depth = pixGetDepth(pix1); | |
| 1584 L_INFO("write/read jp2k\n", __func__); | |
| 1585 pixWrite(FILE_JP2K, pix1, IFF_JP2); | |
| 1586 pix2 = pixRead(FILE_JP2K); | |
| 1587 if (depth == 8) { | |
| 1588 pixCompareGray(pix1, pix2, L_COMPARE_ABS_DIFF, 0, NULL, &diff, | |
| 1589 NULL, NULL); | |
| 1590 } else { | |
| 1591 pixCompareRGB(pix1, pix2, L_COMPARE_ABS_DIFF, 0, NULL, &diff, | |
| 1592 NULL, NULL); | |
| 1593 } | |
| 1594 lept_stderr("diff = %7.3f\n", diff); | |
| 1595 if (diff > 7.0) { | |
| 1596 L_INFO(" **** bad jp2k image: d = %d, diff = %5.2f ****\n", | |
| 1597 __func__, depth, diff); | |
| 1598 problems = TRUE; | |
| 1599 } | |
| 1600 pixDestroy(&pix1); | |
| 1601 pixDestroy(&pix2); | |
| 1602 #endif /* HAVE_LIBJP2K */ | |
| 1603 | |
| 1604 if (problems == FALSE) | |
| 1605 L_INFO("All formats read and written OK!\n", __func__); | |
| 1606 | |
| 1607 pixDestroy(&pixc); | |
| 1608 pixDestroy(&pixs); | |
| 1609 return problems; | |
| 1610 } |
