Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/leptonica/src/fpix1.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 fpix1.c | |
| 29 * <pre> | |
| 30 * | |
| 31 * --------------------------------------------------- | |
| 32 * This file has these FPix, FPixa and DPix utilities: | |
| 33 * - creation and destruction | |
| 34 * - accessors | |
| 35 * - serialization and deserialization | |
| 36 * --------------------------------------------------- | |
| 37 * | |
| 38 * FPix Create/copy/destroy | |
| 39 * FPIX *fpixCreate() | |
| 40 * FPIX *fpixCreateTemplate() | |
| 41 * FPIX *fpixClone() | |
| 42 * FPIX *fpixCopy() | |
| 43 * void fpixDestroy() | |
| 44 * | |
| 45 * FPix accessors | |
| 46 * l_int32 fpixGetDimensions() | |
| 47 * l_int32 fpixSetDimensions() | |
| 48 * l_int32 fpixGetWpl() | |
| 49 * l_int32 fpixSetWpl() | |
| 50 * l_int32 fpixGetResolution() | |
| 51 * l_int32 fpixSetResolution() | |
| 52 * l_int32 fpixCopyResolution() | |
| 53 * l_float32 *fpixGetData() | |
| 54 * l_int32 fpixSetData() | |
| 55 * l_int32 fpixGetPixel() | |
| 56 * l_int32 fpixSetPixel() | |
| 57 * | |
| 58 * FPixa Create/copy/destroy | |
| 59 * FPIXA *fpixaCreate() | |
| 60 * FPIXA *fpixaCopy() | |
| 61 * void fpixaDestroy() | |
| 62 * | |
| 63 * FPixa addition | |
| 64 * l_int32 fpixaAddFPix() | |
| 65 * static l_int32 fpixaExtendArray() | |
| 66 * static l_int32 fpixaExtendArrayToSize() | |
| 67 * | |
| 68 * FPixa accessors | |
| 69 * l_int32 fpixaGetCount() | |
| 70 * FPIX *fpixaGetFPix() | |
| 71 * l_int32 fpixaGetFPixDimensions() | |
| 72 * l_float32 *fpixaGetData() | |
| 73 * l_int32 fpixaGetPixel() | |
| 74 * l_int32 fpixaSetPixel() | |
| 75 * | |
| 76 * DPix Create/copy/destroy | |
| 77 * DPIX *dpixCreate() | |
| 78 * DPIX *dpixCreateTemplate() | |
| 79 * DPIX *dpixClone() | |
| 80 * DPIX *dpixCopy() | |
| 81 * void dpixDestroy() | |
| 82 * | |
| 83 * DPix accessors | |
| 84 * l_int32 dpixGetDimensions() | |
| 85 * l_int32 dpixSetDimensions() | |
| 86 * l_int32 dpixGetWpl() | |
| 87 * l_int32 dpixSetWpl() | |
| 88 * l_int32 dpixGetResolution() | |
| 89 * l_int32 dpixSetResolution() | |
| 90 * l_int32 dpixCopyResolution() | |
| 91 * l_float64 *dpixGetData() | |
| 92 * l_int32 dpixSetData() | |
| 93 * l_int32 dpixGetPixel() | |
| 94 * l_int32 dpixSetPixel() | |
| 95 * | |
| 96 * FPix serialized I/O | |
| 97 * FPIX *fpixRead() | |
| 98 * FPIX *fpixReadStream() | |
| 99 * FPIX *fpixReadMem() | |
| 100 * l_int32 fpixWrite() | |
| 101 * l_int32 fpixWriteStream() | |
| 102 * l_int32 fpixWriteMem() | |
| 103 * FPIX *fpixEndianByteSwap() | |
| 104 * | |
| 105 * DPix serialized I/O | |
| 106 * DPIX *dpixRead() | |
| 107 * DPIX *dpixReadStream() | |
| 108 * DPIX *dpixReadMem() | |
| 109 * l_int32 dpixWrite() | |
| 110 * l_int32 dpixWriteStream() | |
| 111 * l_int32 dpixWriteMem() | |
| 112 * DPIX *dpixEndianByteSwap() | |
| 113 * | |
| 114 * Print FPix (subsampled, for debugging) | |
| 115 * l_int32 fpixPrintStream() | |
| 116 * </pre> | |
| 117 */ | |
| 118 | |
| 119 #ifdef HAVE_CONFIG_H | |
| 120 #include <config_auto.h> | |
| 121 #endif /* HAVE_CONFIG_H */ | |
| 122 | |
| 123 #include <string.h> | |
| 124 #include "allheaders.h" | |
| 125 #include "pix_internal.h" | |
| 126 | |
| 127 /* Bounds on array sizes */ | |
| 128 static const size_t MaxPtrArraySize = 100000; | |
| 129 static const size_t InitialPtrArraySize = 20; /*!< n'importe quoi */ | |
| 130 | |
| 131 /* Static functions */ | |
| 132 static l_int32 fpixaExtendArray(FPIXA *fpixa); | |
| 133 static l_int32 fpixaExtendArrayToSize(FPIXA *fpixa, l_int32 size); | |
| 134 | |
| 135 /*--------------------------------------------------------------------* | |
| 136 * FPix Create/copy/destroy * | |
| 137 *--------------------------------------------------------------------*/ | |
| 138 /*! | |
| 139 * \brief fpixCreate() | |
| 140 * | |
| 141 * \param[in] width, height | |
| 142 * \return fpixd with data allocated and initialized to 0, or NULL on error | |
| 143 * | |
| 144 * <pre> | |
| 145 * Notes: | |
| 146 * (1) Makes a FPix of specified size, with the data array | |
| 147 * allocated and initialized to 0. | |
| 148 * (2) The number of pixels must be less than 2^29. | |
| 149 * </pre> | |
| 150 */ | |
| 151 FPIX * | |
| 152 fpixCreate(l_int32 width, | |
| 153 l_int32 height) | |
| 154 { | |
| 155 l_float32 *data; | |
| 156 l_uint64 npix64; | |
| 157 FPIX *fpixd; | |
| 158 | |
| 159 if (width <= 0) | |
| 160 return (FPIX *)ERROR_PTR("width must be > 0", __func__, NULL); | |
| 161 if (height <= 0) | |
| 162 return (FPIX *)ERROR_PTR("height must be > 0", __func__, NULL); | |
| 163 | |
| 164 /* Avoid overflow in malloc arg, malicious or otherwise */ | |
| 165 npix64 = (l_uint64)width * (l_uint64)height; /* # of 4-byte pixels */ | |
| 166 if (npix64 >= (1LL << 29)) { | |
| 167 L_ERROR("requested w = %d, h = %d\n", __func__, width, height); | |
| 168 return (FPIX *)ERROR_PTR("requested bytes >= 2^31", __func__, NULL); | |
| 169 } | |
| 170 | |
| 171 fpixd = (FPIX *)LEPT_CALLOC(1, sizeof(FPIX)); | |
| 172 fpixSetDimensions(fpixd, width, height); | |
| 173 fpixSetWpl(fpixd, width); /* 4-byte words */ | |
| 174 fpixd->refcount = 1; | |
| 175 | |
| 176 data = (l_float32 *)LEPT_CALLOC((size_t)width * height, sizeof(l_float32)); | |
| 177 if (!data) { | |
| 178 fpixDestroy(&fpixd); | |
| 179 return (FPIX *)ERROR_PTR("calloc fail for data", __func__, NULL); | |
| 180 } | |
| 181 fpixSetData(fpixd, data); | |
| 182 return fpixd; | |
| 183 } | |
| 184 | |
| 185 | |
| 186 /*! | |
| 187 * \brief fpixCreateTemplate() | |
| 188 * | |
| 189 * \param[in] fpixs | |
| 190 * \return fpixd, or NULL on error | |
| 191 * | |
| 192 * <pre> | |
| 193 * Notes: | |
| 194 * (1) Makes a FPix of the same size as the input FPix, with the | |
| 195 * data array allocated and initialized to 0. | |
| 196 * (2) Copies the resolution. | |
| 197 * </pre> | |
| 198 */ | |
| 199 FPIX * | |
| 200 fpixCreateTemplate(FPIX *fpixs) | |
| 201 { | |
| 202 l_int32 w, h; | |
| 203 FPIX *fpixd; | |
| 204 | |
| 205 if (!fpixs) | |
| 206 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 207 | |
| 208 fpixGetDimensions(fpixs, &w, &h); | |
| 209 if ((fpixd = fpixCreate(w, h)) == NULL) | |
| 210 return (FPIX *)ERROR_PTR("fpixd not made", __func__, NULL); | |
| 211 fpixCopyResolution(fpixd, fpixs); | |
| 212 return fpixd; | |
| 213 } | |
| 214 | |
| 215 | |
| 216 /*! | |
| 217 * \brief fpixClone() | |
| 218 * | |
| 219 * \param[in] fpix | |
| 220 * \return same fpix ptr, or NULL on error | |
| 221 * | |
| 222 * <pre> | |
| 223 * Notes: | |
| 224 * (1) See pixClone() for definition and usage. | |
| 225 * </pre> | |
| 226 */ | |
| 227 FPIX * | |
| 228 fpixClone(FPIX *fpix) | |
| 229 { | |
| 230 if (!fpix) | |
| 231 return (FPIX *)ERROR_PTR("fpix not defined", __func__, NULL); | |
| 232 ++fpix->refcount; | |
| 233 | |
| 234 return fpix; | |
| 235 } | |
| 236 | |
| 237 | |
| 238 /*! | |
| 239 * \brief fpixCopy() | |
| 240 * | |
| 241 * \param[in] fpixs | |
| 242 * \return fpixd, or NULL on error | |
| 243 */ | |
| 244 FPIX * | |
| 245 fpixCopy(FPIX *fpixs) | |
| 246 { | |
| 247 l_int32 w, h, bytes; | |
| 248 l_float32 *datas, *datad; | |
| 249 FPIX *fpixd; | |
| 250 | |
| 251 if (!fpixs) | |
| 252 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, NULL); | |
| 253 | |
| 254 /* Total bytes in image data */ | |
| 255 fpixGetDimensions(fpixs, &w, &h); | |
| 256 bytes = 4 * w * h; | |
| 257 | |
| 258 if ((fpixd = fpixCreateTemplate(fpixs)) == NULL) | |
| 259 return (FPIX *)ERROR_PTR("fpixd not made", __func__, NULL); | |
| 260 datas = fpixGetData(fpixs); | |
| 261 datad = fpixGetData(fpixd); | |
| 262 memcpy(datad, datas, bytes); | |
| 263 return fpixd; | |
| 264 } | |
| 265 | |
| 266 | |
| 267 /*! | |
| 268 * \brief fpixDestroy() | |
| 269 * | |
| 270 * \param[in,out] pfpix will be set to null before returning | |
| 271 * \return void | |
| 272 * | |
| 273 * <pre> | |
| 274 * Notes: | |
| 275 * (1) Decrements the ref count and, if 0, destroys the fpix. | |
| 276 * (2) Always nulls the input ptr. | |
| 277 * </pre> | |
| 278 */ | |
| 279 void | |
| 280 fpixDestroy(FPIX **pfpix) | |
| 281 { | |
| 282 l_float32 *data; | |
| 283 FPIX *fpix; | |
| 284 | |
| 285 if (!pfpix) { | |
| 286 L_WARNING("ptr address is null!\n", __func__); | |
| 287 return; | |
| 288 } | |
| 289 | |
| 290 if ((fpix = *pfpix) == NULL) | |
| 291 return; | |
| 292 | |
| 293 /* Decrement the ref count. If it is 0, destroy the fpix. */ | |
| 294 if (--fpix->refcount == 0) { | |
| 295 if ((data = fpixGetData(fpix)) != NULL) | |
| 296 LEPT_FREE(data); | |
| 297 LEPT_FREE(fpix); | |
| 298 } | |
| 299 *pfpix = NULL; | |
| 300 } | |
| 301 | |
| 302 | |
| 303 /*--------------------------------------------------------------------* | |
| 304 * FPix Accessors * | |
| 305 *--------------------------------------------------------------------*/ | |
| 306 /*! | |
| 307 * \brief fpixGetDimensions() | |
| 308 * | |
| 309 * \param[in] fpix | |
| 310 * \param[out] pw, ph [optional] each can be null | |
| 311 * \return 0 if OK, 1 on error | |
| 312 */ | |
| 313 l_ok | |
| 314 fpixGetDimensions(FPIX *fpix, | |
| 315 l_int32 *pw, | |
| 316 l_int32 *ph) | |
| 317 { | |
| 318 if (!pw && !ph) | |
| 319 return ERROR_INT("no return val requested", __func__, 1); | |
| 320 if (pw) *pw = 0; | |
| 321 if (ph) *ph = 0; | |
| 322 if (!fpix) | |
| 323 return ERROR_INT("fpix not defined", __func__, 1); | |
| 324 if (pw) *pw = fpix->w; | |
| 325 if (ph) *ph = fpix->h; | |
| 326 return 0; | |
| 327 } | |
| 328 | |
| 329 | |
| 330 /*! | |
| 331 * \brief fpixSetDimensions() | |
| 332 * | |
| 333 * \param[in] fpix | |
| 334 * \param[in] w, h | |
| 335 * \return 0 if OK, 1 on error | |
| 336 */ | |
| 337 l_ok | |
| 338 fpixSetDimensions(FPIX *fpix, | |
| 339 l_int32 w, | |
| 340 l_int32 h) | |
| 341 { | |
| 342 if (!fpix) | |
| 343 return ERROR_INT("fpix not defined", __func__, 1); | |
| 344 fpix->w = w; | |
| 345 fpix->h = h; | |
| 346 return 0; | |
| 347 } | |
| 348 | |
| 349 | |
| 350 /*! | |
| 351 * \brief fpixGetWpl() | |
| 352 * | |
| 353 * \param[in] fpix | |
| 354 * \return wpl, or 0 on error | |
| 355 */ | |
| 356 l_int32 | |
| 357 fpixGetWpl(FPIX *fpix) | |
| 358 { | |
| 359 if (!fpix) | |
| 360 return ERROR_INT("fpix not defined", __func__, 0); | |
| 361 return fpix->wpl; | |
| 362 } | |
| 363 | |
| 364 | |
| 365 /*! | |
| 366 * \brief fpixSetWpl() | |
| 367 * | |
| 368 * \param[in] fpix | |
| 369 * \param[in] wpl | |
| 370 * \return 0 if OK, 1 on error | |
| 371 */ | |
| 372 l_ok | |
| 373 fpixSetWpl(FPIX *fpix, | |
| 374 l_int32 wpl) | |
| 375 { | |
| 376 if (!fpix) | |
| 377 return ERROR_INT("fpix not defined", __func__, 1); | |
| 378 | |
| 379 fpix->wpl = wpl; | |
| 380 return 0; | |
| 381 } | |
| 382 | |
| 383 | |
| 384 /*! | |
| 385 * \brief fpixGetResolution() | |
| 386 * | |
| 387 * \param[in] fpix | |
| 388 * \param[out] pxres, pyres [optional] x and y resolution | |
| 389 * \return 0 if OK, 1 on error | |
| 390 */ | |
| 391 l_ok | |
| 392 fpixGetResolution(FPIX *fpix, | |
| 393 l_int32 *pxres, | |
| 394 l_int32 *pyres) | |
| 395 { | |
| 396 if (!fpix) | |
| 397 return ERROR_INT("fpix not defined", __func__, 1); | |
| 398 if (pxres) *pxres = fpix->xres; | |
| 399 if (pyres) *pyres = fpix->yres; | |
| 400 return 0; | |
| 401 } | |
| 402 | |
| 403 | |
| 404 /*! | |
| 405 * \brief fpixSetResolution() | |
| 406 * | |
| 407 * \param[in] fpix | |
| 408 * \param[in] xres, yres x and y resolution | |
| 409 * \return 0 if OK, 1 on error | |
| 410 */ | |
| 411 l_ok | |
| 412 fpixSetResolution(FPIX *fpix, | |
| 413 l_int32 xres, | |
| 414 l_int32 yres) | |
| 415 { | |
| 416 if (!fpix) | |
| 417 return ERROR_INT("fpix not defined", __func__, 1); | |
| 418 | |
| 419 fpix->xres = xres; | |
| 420 fpix->yres = yres; | |
| 421 return 0; | |
| 422 } | |
| 423 | |
| 424 | |
| 425 /*! | |
| 426 * \brief fpixCopyResolution() | |
| 427 * | |
| 428 * \param[in] fpixd, fpixs | |
| 429 * \return 0 if OK, 1 on error | |
| 430 */ | |
| 431 l_ok | |
| 432 fpixCopyResolution(FPIX *fpixd, | |
| 433 FPIX *fpixs) | |
| 434 { | |
| 435 l_int32 xres, yres; | |
| 436 if (!fpixs || !fpixd) | |
| 437 return ERROR_INT("fpixs and fpixd not both defined", __func__, 1); | |
| 438 | |
| 439 fpixGetResolution(fpixs, &xres, &yres); | |
| 440 fpixSetResolution(fpixd, xres, yres); | |
| 441 return 0; | |
| 442 } | |
| 443 | |
| 444 | |
| 445 /*! | |
| 446 * \brief fpixGetData() | |
| 447 * | |
| 448 * \param[in] fpix | |
| 449 * \return ptr to fpix data, or NULL on error | |
| 450 */ | |
| 451 l_float32 * | |
| 452 fpixGetData(FPIX *fpix) | |
| 453 { | |
| 454 if (!fpix) | |
| 455 return (l_float32 *)ERROR_PTR("fpix not defined", __func__, NULL); | |
| 456 return fpix->data; | |
| 457 } | |
| 458 | |
| 459 | |
| 460 /*! | |
| 461 * \brief fpixSetData() | |
| 462 * | |
| 463 * \param[in] fpix | |
| 464 * \param[in] data | |
| 465 * \return 0 if OK, 1 on error | |
| 466 */ | |
| 467 l_ok | |
| 468 fpixSetData(FPIX *fpix, | |
| 469 l_float32 *data) | |
| 470 { | |
| 471 if (!fpix) | |
| 472 return ERROR_INT("fpix not defined", __func__, 1); | |
| 473 | |
| 474 fpix->data = data; | |
| 475 return 0; | |
| 476 } | |
| 477 | |
| 478 | |
| 479 /*! | |
| 480 * \brief fpixGetPixel() | |
| 481 * | |
| 482 * \param[in] fpix | |
| 483 * \param[in] x,y pixel coords | |
| 484 * \param[out] pval pixel value | |
| 485 * \return 0 if OK; 1 or 2 on error | |
| 486 * | |
| 487 * Notes: | |
| 488 * (1) If the point is outside the image, this returns an error (2), | |
| 489 * with 0.0 in %pval. To avoid spamming output, it fails silently. | |
| 490 */ | |
| 491 l_ok | |
| 492 fpixGetPixel(FPIX *fpix, | |
| 493 l_int32 x, | |
| 494 l_int32 y, | |
| 495 l_float32 *pval) | |
| 496 { | |
| 497 l_int32 w, h; | |
| 498 | |
| 499 if (!pval) | |
| 500 return ERROR_INT("pval not defined", __func__, 1); | |
| 501 *pval = 0.0; | |
| 502 if (!fpix) | |
| 503 return ERROR_INT("fpix not defined", __func__, 1); | |
| 504 | |
| 505 fpixGetDimensions(fpix, &w, &h); | |
| 506 if (x < 0 || x >= w || y < 0 || y >= h) | |
| 507 return 2; | |
| 508 | |
| 509 *pval = *(fpix->data + y * w + x); | |
| 510 return 0; | |
| 511 } | |
| 512 | |
| 513 | |
| 514 /*! | |
| 515 * \brief fpixSetPixel() | |
| 516 * | |
| 517 * \param[in] fpix | |
| 518 * \param[in] x,y pixel coords | |
| 519 * \param[in] val pixel value | |
| 520 * \return 0 if OK; 1 or 2 on error | |
| 521 * | |
| 522 * Notes: | |
| 523 * (1) If the point is outside the image, this returns an error (2), | |
| 524 * with 0.0 in %pval. To avoid spamming output, it fails silently. | |
| 525 */ | |
| 526 l_ok | |
| 527 fpixSetPixel(FPIX *fpix, | |
| 528 l_int32 x, | |
| 529 l_int32 y, | |
| 530 l_float32 val) | |
| 531 { | |
| 532 l_int32 w, h; | |
| 533 | |
| 534 if (!fpix) | |
| 535 return ERROR_INT("fpix not defined", __func__, 1); | |
| 536 | |
| 537 fpixGetDimensions(fpix, &w, &h); | |
| 538 if (x < 0 || x >= w || y < 0 || y >= h) | |
| 539 return 2; | |
| 540 | |
| 541 *(fpix->data + y * w + x) = val; | |
| 542 return 0; | |
| 543 } | |
| 544 | |
| 545 | |
| 546 /*--------------------------------------------------------------------* | |
| 547 * FPixa Create/copy/destroy * | |
| 548 *--------------------------------------------------------------------*/ | |
| 549 /*! | |
| 550 * \brief fpixaCreate() | |
| 551 * | |
| 552 * \param[in] n initial number of ptrs | |
| 553 * \return fpixa, or NULL on error | |
| 554 */ | |
| 555 FPIXA * | |
| 556 fpixaCreate(l_int32 n) | |
| 557 { | |
| 558 FPIXA *fpixa; | |
| 559 | |
| 560 if (n <= 0 || n > MaxPtrArraySize) | |
| 561 n = InitialPtrArraySize; | |
| 562 | |
| 563 fpixa = (FPIXA *)LEPT_CALLOC(1, sizeof(FPIXA)); | |
| 564 fpixa->n = 0; | |
| 565 fpixa->nalloc = n; | |
| 566 fpixa->refcount = 1; | |
| 567 fpixa->fpix = (FPIX **)LEPT_CALLOC(n, sizeof(FPIX *)); | |
| 568 return fpixa; | |
| 569 } | |
| 570 | |
| 571 | |
| 572 /*! | |
| 573 * \brief fpixaCopy() | |
| 574 * | |
| 575 * \param[in] fpixa | |
| 576 * \param[in] copyflag L_COPY, L_CLODE or L_COPY_CLONE | |
| 577 * \return new fpixa, or NULL on error | |
| 578 * | |
| 579 * <pre> | |
| 580 * Notes: | |
| 581 * copyflag may be one of | |
| 582 * ~ L_COPY makes a new fpixa and copies each fpix | |
| 583 * ~ L_CLONE gives a new ref-counted handle to the input fpixa | |
| 584 * ~ L_COPY_CLONE makes a new fpixa with clones of all fpix | |
| 585 * </pre> | |
| 586 */ | |
| 587 FPIXA * | |
| 588 fpixaCopy(FPIXA *fpixa, | |
| 589 l_int32 copyflag) | |
| 590 { | |
| 591 l_int32 i; | |
| 592 FPIX *fpixc; | |
| 593 FPIXA *fpixac; | |
| 594 | |
| 595 if (!fpixa) | |
| 596 return (FPIXA *)ERROR_PTR("fpixa not defined", __func__, NULL); | |
| 597 | |
| 598 if (copyflag == L_CLONE) { | |
| 599 ++fpixa->refcount; | |
| 600 return fpixa; | |
| 601 } | |
| 602 | |
| 603 if (copyflag != L_COPY && copyflag != L_COPY_CLONE) | |
| 604 return (FPIXA *)ERROR_PTR("invalid copyflag", __func__, NULL); | |
| 605 | |
| 606 if ((fpixac = fpixaCreate(fpixa->n)) == NULL) | |
| 607 return (FPIXA *)ERROR_PTR("fpixac not made", __func__, NULL); | |
| 608 for (i = 0; i < fpixa->n; i++) { | |
| 609 if (copyflag == L_COPY) | |
| 610 fpixc = fpixaGetFPix(fpixa, i, L_COPY); | |
| 611 else /* copy-clone */ | |
| 612 fpixc = fpixaGetFPix(fpixa, i, L_CLONE); | |
| 613 fpixaAddFPix(fpixac, fpixc, L_INSERT); | |
| 614 } | |
| 615 | |
| 616 return fpixac; | |
| 617 } | |
| 618 | |
| 619 | |
| 620 /*! | |
| 621 * \brief fpixaDestroy() | |
| 622 * | |
| 623 * \param[in,out] pfpixa will be set to null before returning | |
| 624 * \return void | |
| 625 * | |
| 626 * <pre> | |
| 627 * Notes: | |
| 628 * (1) Decrements the ref count and, if 0, destroys the fpixa. | |
| 629 * (2) Always nulls the input ptr. | |
| 630 * </pre> | |
| 631 */ | |
| 632 void | |
| 633 fpixaDestroy(FPIXA **pfpixa) | |
| 634 { | |
| 635 l_int32 i; | |
| 636 FPIXA *fpixa; | |
| 637 | |
| 638 if (pfpixa == NULL) { | |
| 639 L_WARNING("ptr address is NULL!\n", __func__); | |
| 640 return; | |
| 641 } | |
| 642 | |
| 643 if ((fpixa = *pfpixa) == NULL) | |
| 644 return; | |
| 645 | |
| 646 /* Decrement the refcount. If it is 0, destroy the pixa. */ | |
| 647 if (--fpixa->refcount == 0) { | |
| 648 for (i = 0; i < fpixa->n; i++) | |
| 649 fpixDestroy(&fpixa->fpix[i]); | |
| 650 LEPT_FREE(fpixa->fpix); | |
| 651 LEPT_FREE(fpixa); | |
| 652 } | |
| 653 *pfpixa = NULL; | |
| 654 } | |
| 655 | |
| 656 | |
| 657 /*--------------------------------------------------------------------* | |
| 658 * FPixa addition * | |
| 659 *--------------------------------------------------------------------*/ | |
| 660 /*! | |
| 661 * \brief fpixaAddFPix() | |
| 662 * | |
| 663 * \param[in] fpixa | |
| 664 * \param[in] fpix to be added | |
| 665 * \param[in] copyflag L_INSERT, L_COPY, L_CLONE | |
| 666 * \return 0 if OK; 1 on error | |
| 667 */ | |
| 668 l_ok | |
| 669 fpixaAddFPix(FPIXA *fpixa, | |
| 670 FPIX *fpix, | |
| 671 l_int32 copyflag) | |
| 672 { | |
| 673 l_int32 n; | |
| 674 FPIX *fpixc; | |
| 675 | |
| 676 if (!fpixa) | |
| 677 return ERROR_INT("fpixa not defined", __func__, 1); | |
| 678 if (!fpix) | |
| 679 return ERROR_INT("fpix not defined", __func__, 1); | |
| 680 | |
| 681 if (copyflag == L_INSERT) | |
| 682 fpixc = fpix; | |
| 683 else if (copyflag == L_COPY) | |
| 684 fpixc = fpixCopy(fpix); | |
| 685 else if (copyflag == L_CLONE) | |
| 686 fpixc = fpixClone(fpix); | |
| 687 else | |
| 688 return ERROR_INT("invalid copyflag", __func__, 1); | |
| 689 if (!fpixc) | |
| 690 return ERROR_INT("fpixc not made", __func__, 1); | |
| 691 | |
| 692 n = fpixaGetCount(fpixa); | |
| 693 if (n >= fpixa->nalloc) { | |
| 694 if (fpixaExtendArray(fpixa)) { | |
| 695 if (copyflag != L_INSERT) | |
| 696 fpixDestroy(&fpixc); | |
| 697 return ERROR_INT("extension failed", __func__, 1); | |
| 698 } | |
| 699 } | |
| 700 fpixa->fpix[n] = fpixc; | |
| 701 fpixa->n++; | |
| 702 return 0; | |
| 703 } | |
| 704 | |
| 705 | |
| 706 /*! | |
| 707 * \brief fpixaExtendArray() | |
| 708 * | |
| 709 * \param[in] fpixa | |
| 710 * \return 0 if OK; 1 on error | |
| 711 * | |
| 712 * <pre> | |
| 713 * Notes: | |
| 714 * (1) Doubles the size of the fpixa ptr array. | |
| 715 * (2) The max number of fpix ptrs is 100000. | |
| 716 * </pre> | |
| 717 */ | |
| 718 static l_int32 | |
| 719 fpixaExtendArray(FPIXA *fpixa) | |
| 720 { | |
| 721 if (!fpixa) | |
| 722 return ERROR_INT("fpixa not defined", __func__, 1); | |
| 723 | |
| 724 return fpixaExtendArrayToSize(fpixa, 2 * fpixa->nalloc); | |
| 725 } | |
| 726 | |
| 727 | |
| 728 /*! | |
| 729 * \brief fpixaExtendArrayToSize() | |
| 730 * | |
| 731 * \param[in] fpixa | |
| 732 * \param[in] size new ptr array size | |
| 733 * \return 0 if OK; 1 on error | |
| 734 * | |
| 735 * <pre> | |
| 736 * Notes: | |
| 737 * (1) If necessary, reallocs new fpix ptr array to %size. | |
| 738 * (2) The max number of fpix ptrs is 100K. | |
| 739 * </pre> | |
| 740 */ | |
| 741 static l_int32 | |
| 742 fpixaExtendArrayToSize(FPIXA *fpixa, | |
| 743 l_int32 size) | |
| 744 { | |
| 745 size_t oldsize, newsize; | |
| 746 | |
| 747 if (!fpixa) | |
| 748 return ERROR_INT("fpixa not defined", __func__, 1); | |
| 749 if (fpixa->nalloc > MaxPtrArraySize) /* belt & suspenders */ | |
| 750 return ERROR_INT("fpixa has too many ptrs", __func__, 1); | |
| 751 if (size > MaxPtrArraySize) | |
| 752 return ERROR_INT("size > 100K ptrs; too large", __func__, 1); | |
| 753 if (size <= fpixa->nalloc) { | |
| 754 L_INFO("size too small; no extension\n", __func__); | |
| 755 return 0; | |
| 756 } | |
| 757 | |
| 758 oldsize = fpixa->nalloc * sizeof(FPIX *); | |
| 759 newsize = size * sizeof(FPIX *); | |
| 760 if ((fpixa->fpix = (FPIX **)reallocNew((void **)&fpixa->fpix, | |
| 761 oldsize, newsize)) == NULL) | |
| 762 return ERROR_INT("new ptr array not returned", __func__, 1); | |
| 763 fpixa->nalloc = size; | |
| 764 return 0; | |
| 765 } | |
| 766 | |
| 767 | |
| 768 /*--------------------------------------------------------------------* | |
| 769 * FPixa accessors * | |
| 770 *--------------------------------------------------------------------*/ | |
| 771 /*! | |
| 772 * \brief fpixaGetCount() | |
| 773 * | |
| 774 * \param[in] fpixa | |
| 775 * \return count, or 0 if no pixa | |
| 776 */ | |
| 777 l_int32 | |
| 778 fpixaGetCount(FPIXA *fpixa) | |
| 779 { | |
| 780 if (!fpixa) | |
| 781 return ERROR_INT("fpixa not defined", __func__, 0); | |
| 782 | |
| 783 return fpixa->n; | |
| 784 } | |
| 785 | |
| 786 | |
| 787 /*! | |
| 788 * \brief fpixaGetFPix() | |
| 789 * | |
| 790 * \param[in] fpixa | |
| 791 * \param[in] index to the index-th fpix | |
| 792 * \param[in] accesstype L_COPY or L_CLONE | |
| 793 * \return fpix, or NULL on error | |
| 794 */ | |
| 795 FPIX * | |
| 796 fpixaGetFPix(FPIXA *fpixa, | |
| 797 l_int32 index, | |
| 798 l_int32 accesstype) | |
| 799 { | |
| 800 if (!fpixa) | |
| 801 return (FPIX *)ERROR_PTR("fpixa not defined", __func__, NULL); | |
| 802 if (index < 0 || index >= fpixa->n) | |
| 803 return (FPIX *)ERROR_PTR("index not valid", __func__, NULL); | |
| 804 | |
| 805 if (accesstype == L_COPY) | |
| 806 return fpixCopy(fpixa->fpix[index]); | |
| 807 else if (accesstype == L_CLONE) | |
| 808 return fpixClone(fpixa->fpix[index]); | |
| 809 else | |
| 810 return (FPIX *)ERROR_PTR("invalid accesstype", __func__, NULL); | |
| 811 } | |
| 812 | |
| 813 | |
| 814 /*! | |
| 815 * \brief fpixaGetFPixDimensions() | |
| 816 * | |
| 817 * \param[in] fpixa | |
| 818 * \param[in] index to the index-th box | |
| 819 * \param[out] pw, ph [optional] each can be null | |
| 820 * \return 0 if OK, 1 on error | |
| 821 */ | |
| 822 l_ok | |
| 823 fpixaGetFPixDimensions(FPIXA *fpixa, | |
| 824 l_int32 index, | |
| 825 l_int32 *pw, | |
| 826 l_int32 *ph) | |
| 827 { | |
| 828 FPIX *fpix; | |
| 829 | |
| 830 if (!pw && !ph) | |
| 831 return ERROR_INT("no return val requested", __func__, 1); | |
| 832 if (pw) *pw = 0; | |
| 833 if (ph) *ph = 0; | |
| 834 if (!fpixa) | |
| 835 return ERROR_INT("fpixa not defined", __func__, 1); | |
| 836 if (index < 0 || index >= fpixa->n) | |
| 837 return ERROR_INT("index not valid", __func__, 1); | |
| 838 | |
| 839 if ((fpix = fpixaGetFPix(fpixa, index, L_CLONE)) == NULL) | |
| 840 return ERROR_INT("fpix not found!", __func__, 1); | |
| 841 fpixGetDimensions(fpix, pw, ph); | |
| 842 fpixDestroy(&fpix); | |
| 843 return 0; | |
| 844 } | |
| 845 | |
| 846 | |
| 847 /*! | |
| 848 * \brief fpixaGetData() | |
| 849 * | |
| 850 * \param[in] fpixa | |
| 851 * \param[in] index into fpixa array | |
| 852 * \return data not a copy, or NULL on error | |
| 853 */ | |
| 854 l_float32 * | |
| 855 fpixaGetData(FPIXA *fpixa, | |
| 856 l_int32 index) | |
| 857 { | |
| 858 l_int32 n; | |
| 859 l_float32 *data; | |
| 860 FPIX *fpix; | |
| 861 | |
| 862 if (!fpixa) | |
| 863 return (l_float32 *)ERROR_PTR("fpixa not defined", __func__, NULL); | |
| 864 n = fpixaGetCount(fpixa); | |
| 865 if (index < 0 || index >= n) | |
| 866 return (l_float32 *)ERROR_PTR("invalid index", __func__, NULL); | |
| 867 | |
| 868 fpix = fpixaGetFPix(fpixa, index, L_CLONE); | |
| 869 data = fpixGetData(fpix); | |
| 870 fpixDestroy(&fpix); | |
| 871 return data; | |
| 872 } | |
| 873 | |
| 874 | |
| 875 /*! | |
| 876 * \brief fpixaGetPixel() | |
| 877 * | |
| 878 * \param[in] fpixa | |
| 879 * \param[in] index into fpixa array | |
| 880 * \param[in] x,y pixel coords | |
| 881 * \param[out] pval pixel value | |
| 882 * \return 0 if OK; 1 on error | |
| 883 */ | |
| 884 l_ok | |
| 885 fpixaGetPixel(FPIXA *fpixa, | |
| 886 l_int32 index, | |
| 887 l_int32 x, | |
| 888 l_int32 y, | |
| 889 l_float32 *pval) | |
| 890 { | |
| 891 l_int32 n, ret; | |
| 892 FPIX *fpix; | |
| 893 | |
| 894 if (!pval) | |
| 895 return ERROR_INT("pval not defined", __func__, 1); | |
| 896 *pval = 0.0; | |
| 897 if (!fpixa) | |
| 898 return ERROR_INT("fpixa not defined", __func__, 1); | |
| 899 n = fpixaGetCount(fpixa); | |
| 900 if (index < 0 || index >= n) | |
| 901 return ERROR_INT("invalid index into fpixa", __func__, 1); | |
| 902 | |
| 903 fpix = fpixaGetFPix(fpixa, index, L_CLONE); | |
| 904 ret = fpixGetPixel(fpix, x, y, pval); | |
| 905 fpixDestroy(&fpix); | |
| 906 return ret; | |
| 907 } | |
| 908 | |
| 909 | |
| 910 /*! | |
| 911 * \brief fpixaSetPixel() | |
| 912 * | |
| 913 * \param[in] fpixa | |
| 914 * \param[in] index into fpixa array | |
| 915 * \param[in] x,y pixel coords | |
| 916 * \param[in] val pixel value | |
| 917 * \return 0 if OK; 1 on error | |
| 918 */ | |
| 919 l_ok | |
| 920 fpixaSetPixel(FPIXA *fpixa, | |
| 921 l_int32 index, | |
| 922 l_int32 x, | |
| 923 l_int32 y, | |
| 924 l_float32 val) | |
| 925 { | |
| 926 l_int32 n, ret; | |
| 927 FPIX *fpix; | |
| 928 | |
| 929 if (!fpixa) | |
| 930 return ERROR_INT("fpixa not defined", __func__, 1); | |
| 931 n = fpixaGetCount(fpixa); | |
| 932 if (index < 0 || index >= n) | |
| 933 return ERROR_INT("invalid index into fpixa", __func__, 1); | |
| 934 | |
| 935 fpix = fpixaGetFPix(fpixa, index, L_CLONE); | |
| 936 ret = fpixSetPixel(fpix, x, y, val); | |
| 937 fpixDestroy(&fpix); | |
| 938 return ret; | |
| 939 } | |
| 940 | |
| 941 | |
| 942 /*--------------------------------------------------------------------* | |
| 943 * DPix Create/copy/destroy * | |
| 944 *--------------------------------------------------------------------*/ | |
| 945 /*! | |
| 946 * \brief dpixCreate() | |
| 947 * | |
| 948 * \param[in] width, height | |
| 949 * \return dpix with data allocated and initialized to 0, or NULL on error | |
| 950 * | |
| 951 * <pre> | |
| 952 * Notes: | |
| 953 * (1) Makes a DPix of specified size, with the data array | |
| 954 * allocated and initialized to 0. | |
| 955 * (2) The number of pixels must be less than 2^28. | |
| 956 * </pre> | |
| 957 */ | |
| 958 DPIX * | |
| 959 dpixCreate(l_int32 width, | |
| 960 l_int32 height) | |
| 961 { | |
| 962 l_float64 *data; | |
| 963 l_uint64 npix64; | |
| 964 DPIX *dpix; | |
| 965 | |
| 966 if (width <= 0) | |
| 967 return (DPIX *)ERROR_PTR("width must be > 0", __func__, NULL); | |
| 968 if (height <= 0) | |
| 969 return (DPIX *)ERROR_PTR("height must be > 0", __func__, NULL); | |
| 970 | |
| 971 /* Avoid overflow in malloc arg, malicious or otherwise */ | |
| 972 npix64 = (l_uint64)width * (l_uint64)height; /* # of 8 byte pixels */ | |
| 973 if (npix64 >= (1LL << 28)) { | |
| 974 L_ERROR("requested w = %d, h = %d\n", __func__, width, height); | |
| 975 return (DPIX *)ERROR_PTR("requested bytes >= 2^31", __func__, NULL); | |
| 976 } | |
| 977 | |
| 978 dpix = (DPIX *)LEPT_CALLOC(1, sizeof(DPIX)); | |
| 979 dpixSetDimensions(dpix, width, height); | |
| 980 dpixSetWpl(dpix, width); /* 8 byte words */ | |
| 981 dpix->refcount = 1; | |
| 982 | |
| 983 data = (l_float64 *)LEPT_CALLOC((size_t)width * height, sizeof(l_float64)); | |
| 984 if (!data) { | |
| 985 dpixDestroy(&dpix); | |
| 986 return (DPIX *)ERROR_PTR("calloc fail for data", __func__, NULL); | |
| 987 } | |
| 988 dpixSetData(dpix, data); | |
| 989 return dpix; | |
| 990 } | |
| 991 | |
| 992 | |
| 993 /*! | |
| 994 * \brief dpixCreateTemplate() | |
| 995 * | |
| 996 * \param[in] dpixs | |
| 997 * \return dpixd, or NULL on error | |
| 998 * | |
| 999 * <pre> | |
| 1000 * Notes: | |
| 1001 * (1) Makes a DPix of the same size as the input DPix, with the | |
| 1002 * data array allocated and initialized to 0. | |
| 1003 * (2) Copies the resolution. | |
| 1004 * </pre> | |
| 1005 */ | |
| 1006 DPIX * | |
| 1007 dpixCreateTemplate(DPIX *dpixs) | |
| 1008 { | |
| 1009 l_int32 w, h; | |
| 1010 DPIX *dpixd; | |
| 1011 | |
| 1012 if (!dpixs) | |
| 1013 return (DPIX *)ERROR_PTR("dpixs not defined", __func__, NULL); | |
| 1014 | |
| 1015 dpixGetDimensions(dpixs, &w, &h); | |
| 1016 dpixd = dpixCreate(w, h); | |
| 1017 dpixCopyResolution(dpixd, dpixs); | |
| 1018 return dpixd; | |
| 1019 } | |
| 1020 | |
| 1021 | |
| 1022 /*! | |
| 1023 * \brief dpixClone() | |
| 1024 * | |
| 1025 * \param[in] dpix | |
| 1026 * \return same dpix ptr, or NULL on error | |
| 1027 * | |
| 1028 * <pre> | |
| 1029 * Notes: | |
| 1030 * (1) See pixClone() for definition and usage. | |
| 1031 * </pre> | |
| 1032 */ | |
| 1033 DPIX * | |
| 1034 dpixClone(DPIX *dpix) | |
| 1035 { | |
| 1036 if (!dpix) | |
| 1037 return (DPIX *)ERROR_PTR("dpix not defined", __func__, NULL); | |
| 1038 ++dpix->refcount; | |
| 1039 return dpix; | |
| 1040 } | |
| 1041 | |
| 1042 | |
| 1043 /*! | |
| 1044 * \brief dpixCopy() | |
| 1045 * | |
| 1046 * \param[in] dpixs | |
| 1047 * \return dpixd, or NULL on error | |
| 1048 */ | |
| 1049 DPIX * | |
| 1050 dpixCopy(DPIX *dpixs) | |
| 1051 { | |
| 1052 l_int32 w, h, bytes; | |
| 1053 l_float64 *datas, *datad; | |
| 1054 DPIX *dpixd; | |
| 1055 | |
| 1056 if (!dpixs) | |
| 1057 return (DPIX *)ERROR_PTR("dpixs not defined", __func__, NULL); | |
| 1058 | |
| 1059 /* Total bytes in image data */ | |
| 1060 dpixGetDimensions(dpixs, &w, &h); | |
| 1061 bytes = 8 * w * h; | |
| 1062 | |
| 1063 if ((dpixd = dpixCreateTemplate(dpixs)) == NULL) | |
| 1064 return (DPIX *)ERROR_PTR("dpixd not made", __func__, NULL); | |
| 1065 datas = dpixGetData(dpixs); | |
| 1066 datad = dpixGetData(dpixd); | |
| 1067 memcpy(datad, datas, bytes); | |
| 1068 return dpixd; | |
| 1069 } | |
| 1070 | |
| 1071 | |
| 1072 /*! | |
| 1073 * \brief dpixDestroy() | |
| 1074 * | |
| 1075 * \param[in,out] pdpix will be set to null before returning | |
| 1076 * \return void | |
| 1077 * | |
| 1078 * <pre> | |
| 1079 * Notes: | |
| 1080 * (1) Decrements the ref count and, if 0, destroys the dpix. | |
| 1081 * (2) Always nulls the input ptr. | |
| 1082 * </pre> | |
| 1083 */ | |
| 1084 void | |
| 1085 dpixDestroy(DPIX **pdpix) | |
| 1086 { | |
| 1087 l_float64 *data; | |
| 1088 DPIX *dpix; | |
| 1089 | |
| 1090 if (!pdpix) { | |
| 1091 L_WARNING("ptr address is null!\n", __func__); | |
| 1092 return; | |
| 1093 } | |
| 1094 | |
| 1095 if ((dpix = *pdpix) == NULL) | |
| 1096 return; | |
| 1097 | |
| 1098 /* Decrement the ref count. If it is 0, destroy the dpix. */ | |
| 1099 if (--dpix->refcount == 0) { | |
| 1100 if ((data = dpixGetData(dpix)) != NULL) | |
| 1101 LEPT_FREE(data); | |
| 1102 LEPT_FREE(dpix); | |
| 1103 } | |
| 1104 *pdpix = NULL; | |
| 1105 } | |
| 1106 | |
| 1107 | |
| 1108 /*--------------------------------------------------------------------* | |
| 1109 * DPix Accessors * | |
| 1110 *--------------------------------------------------------------------*/ | |
| 1111 /*! | |
| 1112 * \brief dpixGetDimensions() | |
| 1113 * | |
| 1114 * \param[in] dpix | |
| 1115 * \param[out] pw, ph [optional] each can be null | |
| 1116 * \return 0 if OK, 1 on error | |
| 1117 */ | |
| 1118 l_ok | |
| 1119 dpixGetDimensions(DPIX *dpix, | |
| 1120 l_int32 *pw, | |
| 1121 l_int32 *ph) | |
| 1122 { | |
| 1123 if (!pw && !ph) | |
| 1124 return ERROR_INT("no return val requested", __func__, 1); | |
| 1125 if (pw) *pw = 0; | |
| 1126 if (ph) *ph = 0; | |
| 1127 if (!dpix) | |
| 1128 return ERROR_INT("dpix not defined", __func__, 1); | |
| 1129 if (pw) *pw = dpix->w; | |
| 1130 if (ph) *ph = dpix->h; | |
| 1131 return 0; | |
| 1132 } | |
| 1133 | |
| 1134 | |
| 1135 /*! | |
| 1136 * \brief dpixSetDimensions() | |
| 1137 * | |
| 1138 * \param[in] dpix | |
| 1139 * \param[in] w, h | |
| 1140 * \return 0 if OK, 1 on error | |
| 1141 */ | |
| 1142 l_ok | |
| 1143 dpixSetDimensions(DPIX *dpix, | |
| 1144 l_int32 w, | |
| 1145 l_int32 h) | |
| 1146 { | |
| 1147 if (!dpix) | |
| 1148 return ERROR_INT("dpix not defined", __func__, 1); | |
| 1149 dpix->w = w; | |
| 1150 dpix->h = h; | |
| 1151 return 0; | |
| 1152 } | |
| 1153 | |
| 1154 | |
| 1155 /*! | |
| 1156 * \brief dpixGetWpl() | |
| 1157 * | |
| 1158 * \param[in] dpix | |
| 1159 * \return wpl, or 0 on error | |
| 1160 */ | |
| 1161 l_int32 | |
| 1162 dpixGetWpl(DPIX *dpix) | |
| 1163 { | |
| 1164 if (!dpix) | |
| 1165 return ERROR_INT("dpix not defined", __func__, 0); | |
| 1166 return dpix->wpl; | |
| 1167 } | |
| 1168 | |
| 1169 | |
| 1170 /*! | |
| 1171 * \brief dpixSetWpl() | |
| 1172 * | |
| 1173 * \param[in] dpix | |
| 1174 * \param[in] wpl | |
| 1175 * \return 0 if OK, 1 on error | |
| 1176 */ | |
| 1177 l_ok | |
| 1178 dpixSetWpl(DPIX *dpix, | |
| 1179 l_int32 wpl) | |
| 1180 { | |
| 1181 if (!dpix) | |
| 1182 return ERROR_INT("dpix not defined", __func__, 1); | |
| 1183 | |
| 1184 dpix->wpl = wpl; | |
| 1185 return 0; | |
| 1186 } | |
| 1187 | |
| 1188 | |
| 1189 /*! | |
| 1190 * \brief dpixGetResolution() | |
| 1191 * | |
| 1192 * \param[in] dpix | |
| 1193 * \param[out] pxres, pyres [optional] x and y resolution | |
| 1194 * \return 0 if OK, 1 on error | |
| 1195 */ | |
| 1196 l_ok | |
| 1197 dpixGetResolution(DPIX *dpix, | |
| 1198 l_int32 *pxres, | |
| 1199 l_int32 *pyres) | |
| 1200 { | |
| 1201 if (!dpix) | |
| 1202 return ERROR_INT("dpix not defined", __func__, 1); | |
| 1203 if (pxres) *pxres = dpix->xres; | |
| 1204 if (pyres) *pyres = dpix->yres; | |
| 1205 return 0; | |
| 1206 } | |
| 1207 | |
| 1208 | |
| 1209 /*! | |
| 1210 * \brief dpixSetResolution() | |
| 1211 * | |
| 1212 * \param[in] dpix | |
| 1213 * \param[in] xres, yres x and y resolution | |
| 1214 * \return 0 if OK, 1 on error | |
| 1215 */ | |
| 1216 l_ok | |
| 1217 dpixSetResolution(DPIX *dpix, | |
| 1218 l_int32 xres, | |
| 1219 l_int32 yres) | |
| 1220 { | |
| 1221 if (!dpix) | |
| 1222 return ERROR_INT("dpix not defined", __func__, 1); | |
| 1223 | |
| 1224 dpix->xres = xres; | |
| 1225 dpix->yres = yres; | |
| 1226 return 0; | |
| 1227 } | |
| 1228 | |
| 1229 | |
| 1230 /*! | |
| 1231 * \brief dpixCopyResolution() | |
| 1232 * | |
| 1233 * \param[in] dpixd, dpixs | |
| 1234 * \return 0 if OK, 1 on error | |
| 1235 */ | |
| 1236 l_ok | |
| 1237 dpixCopyResolution(DPIX *dpixd, | |
| 1238 DPIX *dpixs) | |
| 1239 { | |
| 1240 l_int32 xres, yres; | |
| 1241 if (!dpixs || !dpixd) | |
| 1242 return ERROR_INT("dpixs and dpixd not both defined", __func__, 1); | |
| 1243 | |
| 1244 dpixGetResolution(dpixs, &xres, &yres); | |
| 1245 dpixSetResolution(dpixd, xres, yres); | |
| 1246 return 0; | |
| 1247 } | |
| 1248 | |
| 1249 | |
| 1250 /*! | |
| 1251 * \brief dpixGetData() | |
| 1252 * | |
| 1253 * \param[in] dpix | |
| 1254 * \return ptr to dpix data, or NULL on error | |
| 1255 */ | |
| 1256 l_float64 * | |
| 1257 dpixGetData(DPIX *dpix) | |
| 1258 { | |
| 1259 if (!dpix) | |
| 1260 return (l_float64 *)ERROR_PTR("dpix not defined", __func__, NULL); | |
| 1261 return dpix->data; | |
| 1262 } | |
| 1263 | |
| 1264 | |
| 1265 /*! | |
| 1266 * \brief dpixSetData() | |
| 1267 * | |
| 1268 * \param[in] dpix | |
| 1269 * \param[in] data | |
| 1270 * \return 0 if OK, 1 on error | |
| 1271 */ | |
| 1272 l_ok | |
| 1273 dpixSetData(DPIX *dpix, | |
| 1274 l_float64 *data) | |
| 1275 { | |
| 1276 if (!dpix) | |
| 1277 return ERROR_INT("dpix not defined", __func__, 1); | |
| 1278 | |
| 1279 dpix->data = data; | |
| 1280 return 0; | |
| 1281 } | |
| 1282 | |
| 1283 | |
| 1284 /*! | |
| 1285 * \brief dpixGetPixel() | |
| 1286 * | |
| 1287 * \param[in] dpix | |
| 1288 * \param[in] x,y pixel coords | |
| 1289 * \param[out] pval pixel value | |
| 1290 * \return 0 if OK; 1 or 2 on error | |
| 1291 * | |
| 1292 * Notes: | |
| 1293 * (1) If the point is outside the image, this returns an error (2), | |
| 1294 * with 0.0 in %pval. To avoid spamming output, it fails silently. | |
| 1295 */ | |
| 1296 l_ok | |
| 1297 dpixGetPixel(DPIX *dpix, | |
| 1298 l_int32 x, | |
| 1299 l_int32 y, | |
| 1300 l_float64 *pval) | |
| 1301 { | |
| 1302 l_int32 w, h; | |
| 1303 | |
| 1304 if (!pval) | |
| 1305 return ERROR_INT("pval not defined", __func__, 1); | |
| 1306 *pval = 0.0; | |
| 1307 if (!dpix) | |
| 1308 return ERROR_INT("dpix not defined", __func__, 1); | |
| 1309 | |
| 1310 dpixGetDimensions(dpix, &w, &h); | |
| 1311 if (x < 0 || x >= w || y < 0 || y >= h) | |
| 1312 return 2; | |
| 1313 | |
| 1314 *pval = *(dpix->data + y * w + x); | |
| 1315 return 0; | |
| 1316 } | |
| 1317 | |
| 1318 | |
| 1319 /*! | |
| 1320 * \brief dpixSetPixel() | |
| 1321 * | |
| 1322 * \param[in] dpix | |
| 1323 * \param[in] x,y pixel coords | |
| 1324 * \param[in] val pixel value | |
| 1325 * \return 0 if OK; 1 or 2 on error | |
| 1326 * | |
| 1327 * Notes: | |
| 1328 * (1) If the point is outside the image, this returns an error (2), | |
| 1329 * with 0.0 in %pval. To avoid spamming output, it fails silently. | |
| 1330 */ | |
| 1331 l_ok | |
| 1332 dpixSetPixel(DPIX *dpix, | |
| 1333 l_int32 x, | |
| 1334 l_int32 y, | |
| 1335 l_float64 val) | |
| 1336 { | |
| 1337 l_int32 w, h; | |
| 1338 | |
| 1339 if (!dpix) | |
| 1340 return ERROR_INT("dpix not defined", __func__, 1); | |
| 1341 | |
| 1342 dpixGetDimensions(dpix, &w, &h); | |
| 1343 if (x < 0 || x >= w || y < 0 || y >= h) | |
| 1344 return 2; | |
| 1345 | |
| 1346 *(dpix->data + y * w + x) = val; | |
| 1347 return 0; | |
| 1348 } | |
| 1349 | |
| 1350 | |
| 1351 /*--------------------------------------------------------------------* | |
| 1352 * FPix serialized I/O * | |
| 1353 *--------------------------------------------------------------------*/ | |
| 1354 /*! | |
| 1355 * \brief fpixRead() | |
| 1356 * | |
| 1357 * \param[in] filename | |
| 1358 * \return fpix, or NULL on error | |
| 1359 */ | |
| 1360 FPIX * | |
| 1361 fpixRead(const char *filename) | |
| 1362 { | |
| 1363 FILE *fp; | |
| 1364 FPIX *fpix; | |
| 1365 | |
| 1366 if (!filename) | |
| 1367 return (FPIX *)ERROR_PTR("filename not defined", __func__, NULL); | |
| 1368 | |
| 1369 if ((fp = fopenReadStream(filename)) == NULL) | |
| 1370 return (FPIX *)ERROR_PTR_1("stream not opened", | |
| 1371 filename, __func__, NULL); | |
| 1372 fpix = fpixReadStream(fp); | |
| 1373 fclose(fp); | |
| 1374 if (!fpix) | |
| 1375 return (FPIX *)ERROR_PTR_1("fpix not read", filename, __func__, NULL); | |
| 1376 return fpix; | |
| 1377 } | |
| 1378 | |
| 1379 | |
| 1380 /*! | |
| 1381 * \brief fpixReadStream() | |
| 1382 * | |
| 1383 * \param[in] fp file stream | |
| 1384 * \return fpix, or NULL on error | |
| 1385 */ | |
| 1386 FPIX * | |
| 1387 fpixReadStream(FILE *fp) | |
| 1388 { | |
| 1389 char buf[256]; | |
| 1390 l_int32 w, h, nbytes, xres, yres, version; | |
| 1391 l_float32 *data; | |
| 1392 FPIX *fpix; | |
| 1393 | |
| 1394 if (!fp) | |
| 1395 return (FPIX *)ERROR_PTR("stream not defined", __func__, NULL); | |
| 1396 | |
| 1397 if (fscanf(fp, "\nFPix Version %d\n", &version) != 1) | |
| 1398 return (FPIX *)ERROR_PTR("not a fpix file", __func__, NULL); | |
| 1399 if (version != FPIX_VERSION_NUMBER) | |
| 1400 return (FPIX *)ERROR_PTR("invalid fpix version", __func__, NULL); | |
| 1401 if (fscanf(fp, "w = %d, h = %d, nbytes = %d\n", &w, &h, &nbytes) != 3) | |
| 1402 return (FPIX *)ERROR_PTR("read fail for data size", __func__, NULL); | |
| 1403 | |
| 1404 /* Use fgets() and sscanf(); not fscanf(), for the last | |
| 1405 * bit of header data before the float data. The reason is | |
| 1406 * that fscanf throws away white space, and if the float data | |
| 1407 * happens to begin with ascii character(s) that are white | |
| 1408 * space, it will swallow them and all will be lost! */ | |
| 1409 if (fgets(buf, sizeof(buf), fp) == NULL) | |
| 1410 return (FPIX *)ERROR_PTR("fgets read fail", __func__, NULL); | |
| 1411 if (sscanf(buf, "xres = %d, yres = %d\n", &xres, &yres) != 2) | |
| 1412 return (FPIX *)ERROR_PTR("read fail for xres, yres", __func__, NULL); | |
| 1413 | |
| 1414 if ((fpix = fpixCreate(w, h)) == NULL) | |
| 1415 return (FPIX *)ERROR_PTR("fpix not made", __func__, NULL); | |
| 1416 fpixSetResolution(fpix, xres, yres); | |
| 1417 data = fpixGetData(fpix); | |
| 1418 if (fread(data, 1, nbytes, fp) != nbytes) { | |
| 1419 fpixDestroy(&fpix); | |
| 1420 return (FPIX *)ERROR_PTR("read error for nbytes", __func__, NULL); | |
| 1421 } | |
| 1422 fgetc(fp); /* ending nl */ | |
| 1423 | |
| 1424 /* Convert to little-endian if necessary */ | |
| 1425 fpixEndianByteSwap(fpix, fpix); | |
| 1426 return fpix; | |
| 1427 } | |
| 1428 | |
| 1429 | |
| 1430 /*! | |
| 1431 * \brief fpixReadMem() | |
| 1432 * | |
| 1433 * \param[in] data of serialized fpix | |
| 1434 * \param[in] size of data in bytes | |
| 1435 * \return fpix, or NULL on error | |
| 1436 */ | |
| 1437 FPIX * | |
| 1438 fpixReadMem(const l_uint8 *data, | |
| 1439 size_t size) | |
| 1440 { | |
| 1441 FILE *fp; | |
| 1442 FPIX *fpix; | |
| 1443 | |
| 1444 if (!data) | |
| 1445 return (FPIX *)ERROR_PTR("data not defined", __func__, NULL); | |
| 1446 if ((fp = fopenReadFromMemory(data, size)) == NULL) | |
| 1447 return (FPIX *)ERROR_PTR("stream not opened", __func__, NULL); | |
| 1448 | |
| 1449 fpix = fpixReadStream(fp); | |
| 1450 fclose(fp); | |
| 1451 if (!fpix) L_ERROR("fpix not read\n", __func__); | |
| 1452 return fpix; | |
| 1453 } | |
| 1454 | |
| 1455 | |
| 1456 /*! | |
| 1457 * \brief fpixWrite() | |
| 1458 * | |
| 1459 * \param[in] filename | |
| 1460 * \param[in] fpix | |
| 1461 * \return 0 if OK, 1 on error | |
| 1462 */ | |
| 1463 l_ok | |
| 1464 fpixWrite(const char *filename, | |
| 1465 FPIX *fpix) | |
| 1466 { | |
| 1467 l_int32 ret; | |
| 1468 FILE *fp; | |
| 1469 | |
| 1470 if (!filename) | |
| 1471 return ERROR_INT("filename not defined", __func__, 1); | |
| 1472 if (!fpix) | |
| 1473 return ERROR_INT("fpix not defined", __func__, 1); | |
| 1474 | |
| 1475 if ((fp = fopenWriteStream(filename, "wb")) == NULL) | |
| 1476 return ERROR_INT_1("stream not opened", filename, __func__, 1); | |
| 1477 ret = fpixWriteStream(fp, fpix); | |
| 1478 fclose(fp); | |
| 1479 if (ret) | |
| 1480 return ERROR_INT_1("fpix not written to stream", filename, __func__, 1); | |
| 1481 return 0; | |
| 1482 } | |
| 1483 | |
| 1484 | |
| 1485 /*! | |
| 1486 * \brief fpixWriteStream() | |
| 1487 * | |
| 1488 * \param[in] fp file stream opened for "wb" | |
| 1489 * \param[in] fpix | |
| 1490 * \return 0 if OK, 1 on error | |
| 1491 */ | |
| 1492 l_ok | |
| 1493 fpixWriteStream(FILE *fp, | |
| 1494 FPIX *fpix) | |
| 1495 { | |
| 1496 l_int32 w, h, xres, yres; | |
| 1497 l_uint32 nbytes; | |
| 1498 l_float32 *data; | |
| 1499 FPIX *fpixt; | |
| 1500 | |
| 1501 if (!fp) | |
| 1502 return ERROR_INT("stream not defined", __func__, 1); | |
| 1503 if (!fpix) | |
| 1504 return ERROR_INT("fpix not defined", __func__, 1); | |
| 1505 | |
| 1506 /* Convert to little-endian if necessary */ | |
| 1507 fpixt = fpixEndianByteSwap(NULL, fpix); | |
| 1508 | |
| 1509 fpixGetDimensions(fpixt, &w, &h); | |
| 1510 data = fpixGetData(fpixt); | |
| 1511 nbytes = sizeof(l_float32) * w * h; | |
| 1512 fpixGetResolution(fpixt, &xres, &yres); | |
| 1513 fprintf(fp, "\nFPix Version %d\n", FPIX_VERSION_NUMBER); | |
| 1514 fprintf(fp, "w = %d, h = %d, nbytes = %u\n", w, h, nbytes); | |
| 1515 fprintf(fp, "xres = %d, yres = %d\n", xres, yres); | |
| 1516 fwrite(data, 1, nbytes, fp); | |
| 1517 fprintf(fp, "\n"); | |
| 1518 | |
| 1519 fpixDestroy(&fpixt); | |
| 1520 return 0; | |
| 1521 } | |
| 1522 | |
| 1523 | |
| 1524 /*! | |
| 1525 * \brief fpixWriteMem() | |
| 1526 * | |
| 1527 * \param[out] pdata data of serialized fpix | |
| 1528 * \param[out] psize size of returned data | |
| 1529 * \param[in] fpix | |
| 1530 * \return 0 if OK, 1 on error | |
| 1531 * | |
| 1532 * <pre> | |
| 1533 * Notes: | |
| 1534 * (1) Serializes a fpix in memory and puts the result in a buffer. | |
| 1535 * </pre> | |
| 1536 */ | |
| 1537 l_ok | |
| 1538 fpixWriteMem(l_uint8 **pdata, | |
| 1539 size_t *psize, | |
| 1540 FPIX *fpix) | |
| 1541 { | |
| 1542 l_int32 ret; | |
| 1543 FILE *fp; | |
| 1544 | |
| 1545 if (pdata) *pdata = NULL; | |
| 1546 if (psize) *psize = 0; | |
| 1547 if (!pdata) | |
| 1548 return ERROR_INT("&data not defined", __func__, 1); | |
| 1549 if (!psize) | |
| 1550 return ERROR_INT("&size not defined", __func__, 1); | |
| 1551 if (!fpix) | |
| 1552 return ERROR_INT("fpix not defined", __func__, 1); | |
| 1553 | |
| 1554 #if HAVE_FMEMOPEN | |
| 1555 if ((fp = open_memstream((char **)pdata, psize)) == NULL) | |
| 1556 return ERROR_INT("stream not opened", __func__, 1); | |
| 1557 ret = fpixWriteStream(fp, fpix); | |
| 1558 fputc('\0', fp); | |
| 1559 fclose(fp); | |
| 1560 if (*psize > 0) *psize = *psize - 1; | |
| 1561 #else | |
| 1562 L_INFO("no fmemopen API --> work-around: write to temp file\n", __func__); | |
| 1563 #ifdef _WIN32 | |
| 1564 if ((fp = fopenWriteWinTempfile()) == NULL) | |
| 1565 return ERROR_INT("tmpfile stream not opened", __func__, 1); | |
| 1566 #else | |
| 1567 if ((fp = tmpfile()) == NULL) | |
| 1568 return ERROR_INT("tmpfile stream not opened", __func__, 1); | |
| 1569 #endif /* _WIN32 */ | |
| 1570 ret = fpixWriteStream(fp, fpix); | |
| 1571 rewind(fp); | |
| 1572 *pdata = l_binaryReadStream(fp, psize); | |
| 1573 fclose(fp); | |
| 1574 #endif /* HAVE_FMEMOPEN */ | |
| 1575 return ret; | |
| 1576 } | |
| 1577 | |
| 1578 | |
| 1579 /*! | |
| 1580 * \brief fpixEndianByteSwap() | |
| 1581 * | |
| 1582 * \param[in] fpixd [optional] can be either NULL, or equal to fpixs | |
| 1583 * \param[in] fpixs | |
| 1584 * \return fpixd always | |
| 1585 * | |
| 1586 * <pre> | |
| 1587 * Notes: | |
| 1588 * (1) On big-endian hardware, this does byte-swapping on each of | |
| 1589 * the 4-byte floats in the fpix data. On little-endians, | |
| 1590 * the data is unchanged. This is used for serialization | |
| 1591 * of fpix; the data is serialized in little-endian byte | |
| 1592 * order because most hardware is little-endian. | |
| 1593 * (2) The operation can be either in-place or, if fpixd == NULL, | |
| 1594 * a new fpix is made. If not in-place, caller must catch | |
| 1595 * the returned pointer. | |
| 1596 * </pre> | |
| 1597 */ | |
| 1598 FPIX * | |
| 1599 fpixEndianByteSwap(FPIX *fpixd, | |
| 1600 FPIX *fpixs) | |
| 1601 { | |
| 1602 if (!fpixs) | |
| 1603 return (FPIX *)ERROR_PTR("fpixs not defined", __func__, fpixd); | |
| 1604 if (fpixd && (fpixs != fpixd)) | |
| 1605 return (FPIX *)ERROR_PTR("fpixd != fpixs", __func__, fpixd); | |
| 1606 | |
| 1607 #ifdef L_BIG_ENDIAN | |
| 1608 { | |
| 1609 l_uint32 *data; | |
| 1610 l_int32 i, j, w, h; | |
| 1611 l_uint32 word; | |
| 1612 | |
| 1613 fpixGetDimensions(fpixs, &w, &h); | |
| 1614 if (!fpixd) | |
| 1615 fpixd = fpixCopy(fpixs); | |
| 1616 | |
| 1617 data = (l_uint32 *)fpixGetData(fpixd); | |
| 1618 for (i = 0; i < h; i++) { | |
| 1619 for (j = 0; j < w; j++, data++) { | |
| 1620 word = *data; | |
| 1621 *data = (word >> 24) | | |
| 1622 ((word >> 8) & 0x0000ff00) | | |
| 1623 ((word << 8) & 0x00ff0000) | | |
| 1624 (word << 24); | |
| 1625 } | |
| 1626 } | |
| 1627 return fpixd; | |
| 1628 } | |
| 1629 #else /* L_LITTLE_ENDIAN */ | |
| 1630 | |
| 1631 if (fpixd) | |
| 1632 return fpixd; /* no-op */ | |
| 1633 else | |
| 1634 return fpixClone(fpixs); | |
| 1635 | |
| 1636 #endif /* L_BIG_ENDIAN */ | |
| 1637 } | |
| 1638 | |
| 1639 | |
| 1640 /*--------------------------------------------------------------------* | |
| 1641 * DPix serialized I/O * | |
| 1642 *--------------------------------------------------------------------*/ | |
| 1643 /*! | |
| 1644 * \brief dpixRead() | |
| 1645 * | |
| 1646 * \param[in] filename | |
| 1647 * \return dpix, or NULL on error | |
| 1648 */ | |
| 1649 DPIX * | |
| 1650 dpixRead(const char *filename) | |
| 1651 { | |
| 1652 FILE *fp; | |
| 1653 DPIX *dpix; | |
| 1654 | |
| 1655 if (!filename) | |
| 1656 return (DPIX *)ERROR_PTR("filename not defined", __func__, NULL); | |
| 1657 | |
| 1658 if ((fp = fopenReadStream(filename)) == NULL) | |
| 1659 return (DPIX *)ERROR_PTR_1("stream not opened", | |
| 1660 filename, __func__, NULL); | |
| 1661 dpix = dpixReadStream(fp); | |
| 1662 fclose(fp); | |
| 1663 if (!dpix) | |
| 1664 return (DPIX *)ERROR_PTR_1("dpix not read", filename, __func__, NULL); | |
| 1665 return dpix; | |
| 1666 } | |
| 1667 | |
| 1668 | |
| 1669 /*! | |
| 1670 * \brief dpixReadStream() | |
| 1671 * | |
| 1672 * \param[in] fp file stream | |
| 1673 * \return dpix, or NULL on error | |
| 1674 */ | |
| 1675 DPIX * | |
| 1676 dpixReadStream(FILE *fp) | |
| 1677 { | |
| 1678 char buf[256]; | |
| 1679 l_int32 w, h, nbytes, version, xres, yres; | |
| 1680 l_float64 *data; | |
| 1681 DPIX *dpix; | |
| 1682 | |
| 1683 if (!fp) | |
| 1684 return (DPIX *)ERROR_PTR("stream not defined", __func__, NULL); | |
| 1685 | |
| 1686 if (fscanf(fp, "\nDPix Version %d\n", &version) != 1) | |
| 1687 return (DPIX *)ERROR_PTR("not a dpix file", __func__, NULL); | |
| 1688 if (version != DPIX_VERSION_NUMBER) | |
| 1689 return (DPIX *)ERROR_PTR("invalid dpix version", __func__, NULL); | |
| 1690 if (fscanf(fp, "w = %d, h = %d, nbytes = %d\n", &w, &h, &nbytes) != 3) | |
| 1691 return (DPIX *)ERROR_PTR("read fail for data size", __func__, NULL); | |
| 1692 | |
| 1693 /* Use fgets() and sscanf(); not fscanf(), for the last | |
| 1694 * bit of header data before the float data. The reason is | |
| 1695 * that fscanf throws away white space, and if the float data | |
| 1696 * happens to begin with ascii character(s) that are white | |
| 1697 * space, it will swallow them and all will be lost! */ | |
| 1698 if (fgets(buf, sizeof(buf), fp) == NULL) | |
| 1699 return (DPIX *)ERROR_PTR("fgets read fail", __func__, NULL); | |
| 1700 if (sscanf(buf, "xres = %d, yres = %d\n", &xres, &yres) != 2) | |
| 1701 return (DPIX *)ERROR_PTR("read fail for xres, yres", __func__, NULL); | |
| 1702 | |
| 1703 if ((dpix = dpixCreate(w, h)) == NULL) | |
| 1704 return (DPIX *)ERROR_PTR("dpix not made", __func__, NULL); | |
| 1705 dpixSetResolution(dpix, xres, yres); | |
| 1706 data = dpixGetData(dpix); | |
| 1707 if (fread(data, 1, nbytes, fp) != nbytes) { | |
| 1708 dpixDestroy(&dpix); | |
| 1709 return (DPIX *)ERROR_PTR("read error for nbytes", __func__, NULL); | |
| 1710 } | |
| 1711 fgetc(fp); /* ending nl */ | |
| 1712 | |
| 1713 /* Convert to little-endian if necessary */ | |
| 1714 dpixEndianByteSwap(dpix, dpix); | |
| 1715 return dpix; | |
| 1716 } | |
| 1717 | |
| 1718 | |
| 1719 /*! | |
| 1720 * \brief dpixReadMem() | |
| 1721 * | |
| 1722 * \param[in] data of serialized dpix | |
| 1723 * \param[in] size of data in bytes | |
| 1724 * \return dpix, or NULL on error | |
| 1725 */ | |
| 1726 DPIX * | |
| 1727 dpixReadMem(const l_uint8 *data, | |
| 1728 size_t size) | |
| 1729 { | |
| 1730 FILE *fp; | |
| 1731 DPIX *dpix; | |
| 1732 | |
| 1733 if (!data) | |
| 1734 return (DPIX *)ERROR_PTR("data not defined", __func__, NULL); | |
| 1735 if ((fp = fopenReadFromMemory(data, size)) == NULL) | |
| 1736 return (DPIX *)ERROR_PTR("stream not opened", __func__, NULL); | |
| 1737 | |
| 1738 dpix = dpixReadStream(fp); | |
| 1739 fclose(fp); | |
| 1740 if (!dpix) L_ERROR("dpix not read\n", __func__); | |
| 1741 return dpix; | |
| 1742 } | |
| 1743 | |
| 1744 | |
| 1745 /*! | |
| 1746 * \brief dpixWrite() | |
| 1747 * | |
| 1748 * \param[in] filename | |
| 1749 * \param[in] dpix | |
| 1750 * \return 0 if OK, 1 on error | |
| 1751 */ | |
| 1752 l_ok | |
| 1753 dpixWrite(const char *filename, | |
| 1754 DPIX *dpix) | |
| 1755 { | |
| 1756 l_int32 ret; | |
| 1757 FILE *fp; | |
| 1758 | |
| 1759 if (!filename) | |
| 1760 return ERROR_INT("filename not defined", __func__, 1); | |
| 1761 if (!dpix) | |
| 1762 return ERROR_INT("dpix not defined", __func__, 1); | |
| 1763 | |
| 1764 if ((fp = fopenWriteStream(filename, "wb")) == NULL) | |
| 1765 return ERROR_INT_1("stream not opened", filename, __func__, 1); | |
| 1766 ret = dpixWriteStream(fp, dpix); | |
| 1767 fclose(fp); | |
| 1768 if (ret) | |
| 1769 return ERROR_INT_1("dpix not written to stream", filename, __func__, 1); | |
| 1770 return 0; | |
| 1771 } | |
| 1772 | |
| 1773 | |
| 1774 /*! | |
| 1775 * \brief dpixWriteStream() | |
| 1776 * | |
| 1777 * \param[in] fp file stream opened for "wb" | |
| 1778 * \param[in] dpix | |
| 1779 * \return 0 if OK, 1 on error | |
| 1780 */ | |
| 1781 l_ok | |
| 1782 dpixWriteStream(FILE *fp, | |
| 1783 DPIX *dpix) | |
| 1784 { | |
| 1785 l_int32 w, h, xres, yres; | |
| 1786 l_uint32 nbytes; | |
| 1787 l_float64 *data; | |
| 1788 DPIX *dpixt; | |
| 1789 | |
| 1790 if (!fp) | |
| 1791 return ERROR_INT("stream not defined", __func__, 1); | |
| 1792 if (!dpix) | |
| 1793 return ERROR_INT("dpix not defined", __func__, 1); | |
| 1794 | |
| 1795 /* Convert to little-endian if necessary */ | |
| 1796 dpixt = dpixEndianByteSwap(NULL, dpix); | |
| 1797 | |
| 1798 dpixGetDimensions(dpixt, &w, &h); | |
| 1799 dpixGetResolution(dpixt, &xres, &yres); | |
| 1800 data = dpixGetData(dpixt); | |
| 1801 nbytes = sizeof(l_float64) * w * h; | |
| 1802 fprintf(fp, "\nDPix Version %d\n", DPIX_VERSION_NUMBER); | |
| 1803 fprintf(fp, "w = %d, h = %d, nbytes = %u\n", w, h, nbytes); | |
| 1804 fprintf(fp, "xres = %d, yres = %d\n", xres, yres); | |
| 1805 fwrite(data, 1, nbytes, fp); | |
| 1806 fprintf(fp, "\n"); | |
| 1807 | |
| 1808 dpixDestroy(&dpixt); | |
| 1809 return 0; | |
| 1810 } | |
| 1811 | |
| 1812 | |
| 1813 /*! | |
| 1814 * \brief dpixWriteMem() | |
| 1815 * | |
| 1816 * \param[out] pdata data of serialized dpix | |
| 1817 * \param[out] psize size of returned data | |
| 1818 * \param[in] dpix | |
| 1819 * \return 0 if OK, 1 on error | |
| 1820 * | |
| 1821 * <pre> | |
| 1822 * Notes: | |
| 1823 * (1) Serializes a dpix in memory and puts the result in a buffer. | |
| 1824 * </pre> | |
| 1825 */ | |
| 1826 l_ok | |
| 1827 dpixWriteMem(l_uint8 **pdata, | |
| 1828 size_t *psize, | |
| 1829 DPIX *dpix) | |
| 1830 { | |
| 1831 l_int32 ret; | |
| 1832 FILE *fp; | |
| 1833 | |
| 1834 if (pdata) *pdata = NULL; | |
| 1835 if (psize) *psize = 0; | |
| 1836 if (!pdata) | |
| 1837 return ERROR_INT("&data not defined", __func__, 1); | |
| 1838 if (!psize) | |
| 1839 return ERROR_INT("&size not defined", __func__, 1); | |
| 1840 if (!dpix) | |
| 1841 return ERROR_INT("dpix not defined", __func__, 1); | |
| 1842 | |
| 1843 #if HAVE_FMEMOPEN | |
| 1844 if ((fp = open_memstream((char **)pdata, psize)) == NULL) | |
| 1845 return ERROR_INT("stream not opened", __func__, 1); | |
| 1846 ret = dpixWriteStream(fp, dpix); | |
| 1847 fputc('\0', fp); | |
| 1848 fclose(fp); | |
| 1849 *psize = *psize - 1; | |
| 1850 #else | |
| 1851 L_INFO("no fmemopen API --> work-around: write to temp file\n", __func__); | |
| 1852 #ifdef _WIN32 | |
| 1853 if ((fp = fopenWriteWinTempfile()) == NULL) | |
| 1854 return ERROR_INT("tmpfile stream not opened", __func__, 1); | |
| 1855 #else | |
| 1856 if ((fp = tmpfile()) == NULL) | |
| 1857 return ERROR_INT("tmpfile stream not opened", __func__, 1); | |
| 1858 #endif /* _WIN32 */ | |
| 1859 ret = dpixWriteStream(fp, dpix); | |
| 1860 rewind(fp); | |
| 1861 *pdata = l_binaryReadStream(fp, psize); | |
| 1862 fclose(fp); | |
| 1863 #endif /* HAVE_FMEMOPEN */ | |
| 1864 return ret; | |
| 1865 } | |
| 1866 | |
| 1867 | |
| 1868 /*! | |
| 1869 * \brief dpixEndianByteSwap() | |
| 1870 * | |
| 1871 * \param[in] dpixd [optional] can be either NULL, or equal to dpixs | |
| 1872 * \param[in] dpixs | |
| 1873 * \return dpixd always | |
| 1874 * | |
| 1875 * <pre> | |
| 1876 * Notes: | |
| 1877 * (1) On big-endian hardware, this does byte-swapping on each of | |
| 1878 * the 4-byte words in the dpix data. On little-endians, | |
| 1879 * the data is unchanged. This is used for serialization | |
| 1880 * of dpix; the data is serialized in little-endian byte | |
| 1881 * order because most hardware is little-endian. | |
| 1882 * (2) The operation can be either in-place or, if dpixd == NULL, | |
| 1883 * a new dpix is made. If not in-place, caller must catch | |
| 1884 * the returned pointer. | |
| 1885 * </pre> | |
| 1886 */ | |
| 1887 DPIX * | |
| 1888 dpixEndianByteSwap(DPIX *dpixd, | |
| 1889 DPIX *dpixs) | |
| 1890 { | |
| 1891 if (!dpixs) | |
| 1892 return (DPIX *)ERROR_PTR("dpixs not defined", __func__, dpixd); | |
| 1893 if (dpixd && (dpixs != dpixd)) | |
| 1894 return (DPIX *)ERROR_PTR("dpixd != dpixs", __func__, dpixd); | |
| 1895 | |
| 1896 #ifdef L_BIG_ENDIAN | |
| 1897 { | |
| 1898 l_uint32 *data; | |
| 1899 l_int32 i, j, w, h; | |
| 1900 l_uint32 word; | |
| 1901 | |
| 1902 dpixGetDimensions(dpixs, &w, &h); | |
| 1903 if (!dpixd) | |
| 1904 dpixd = dpixCopy(dpixs); | |
| 1905 | |
| 1906 data = (l_uint32 *)dpixGetData(dpixd); | |
| 1907 for (i = 0; i < h; i++) { | |
| 1908 for (j = 0; j < 2 * w; j++, data++) { | |
| 1909 word = *data; | |
| 1910 *data = (word >> 24) | | |
| 1911 ((word >> 8) & 0x0000ff00) | | |
| 1912 ((word << 8) & 0x00ff0000) | | |
| 1913 (word << 24); | |
| 1914 } | |
| 1915 } | |
| 1916 return dpixd; | |
| 1917 } | |
| 1918 #else /* L_LITTLE_ENDIAN */ | |
| 1919 | |
| 1920 if (dpixd) | |
| 1921 return dpixd; /* no-op */ | |
| 1922 else | |
| 1923 return dpixClone(dpixs); | |
| 1924 | |
| 1925 #endif /* L_BIG_ENDIAN */ | |
| 1926 } | |
| 1927 | |
| 1928 | |
| 1929 /*--------------------------------------------------------------------* | |
| 1930 * Print FPix (subsampled, for debugging) * | |
| 1931 *--------------------------------------------------------------------*/ | |
| 1932 /*! | |
| 1933 * \brief fpixPrintStream() | |
| 1934 * | |
| 1935 * \param[in] fp file stream | |
| 1936 * \param[in] fpix | |
| 1937 * \param[in] factor for subsampling | |
| 1938 * \return 0 if OK, 1 on error | |
| 1939 * | |
| 1940 * <pre> | |
| 1941 * Notes: | |
| 1942 * (1) Subsampled printout of fpix for debugging. | |
| 1943 * </pre> | |
| 1944 */ | |
| 1945 l_ok | |
| 1946 fpixPrintStream(FILE *fp, | |
| 1947 FPIX *fpix, | |
| 1948 l_int32 factor) | |
| 1949 { | |
| 1950 l_int32 i, j, w, h, count; | |
| 1951 l_float32 val; | |
| 1952 | |
| 1953 if (!fp) | |
| 1954 return ERROR_INT("stream not defined", __func__, 1); | |
| 1955 if (!fpix) | |
| 1956 return ERROR_INT("fpix not defined", __func__, 1); | |
| 1957 if (factor < 1) | |
| 1958 return ERROR_INT("sampling factor < 1f", __func__, 1); | |
| 1959 | |
| 1960 fpixGetDimensions(fpix, &w, &h); | |
| 1961 fprintf(fp, "\nFPix: w = %d, h = %d\n", w, h); | |
| 1962 for (i = 0; i < h; i += factor) { | |
| 1963 for (count = 0, j = 0; j < w; j += factor, count++) { | |
| 1964 fpixGetPixel(fpix, j, i, &val); | |
| 1965 fprintf(fp, "val[%d, %d] = %f ", i, j, val); | |
| 1966 if ((count + 1) % 3 == 0) fprintf(fp, "\n"); | |
| 1967 } | |
| 1968 if (count % 3) fprintf(fp, "\n"); | |
| 1969 } | |
| 1970 fprintf(fp, "\n"); | |
| 1971 return 0; | |
| 1972 } |
