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 }