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