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