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 pixcomp.c
29 * <pre>
30 *
31 * Pixcomp creation and destruction
32 * PIXC *pixcompCreateFromPix()
33 * PIXC *pixcompCreateFromString()
34 * PIXC *pixcompCreateFromFile()
35 * void pixcompDestroy()
36 * PIXC *pixcompCopy()
37
38 * Pixcomp accessors
39 * l_int32 pixcompGetDimensions()
40 * l_int32 pixcompGetParameters()
41 *
42 * Pixcomp compression selection
43 * l_int32 pixcompDetermineFormat()
44 *
45 * Pixcomp conversion to Pix
46 * PIX *pixCreateFromPixcomp()
47 *
48 * Pixacomp creation and destruction
49 * PIXAC *pixacompCreate()
50 * PIXAC *pixacompCreateWithInit()
51 * PIXAC *pixacompCreateFromPixa()
52 * PIXAC *pixacompCreateFromFiles()
53 * PIXAC *pixacompCreateFromSA()
54 * void pixacompDestroy()
55 *
56 * Pixacomp addition/replacement
57 * l_int32 pixacompAddPix()
58 * l_int32 pixacompAddPixcomp()
59 * static l_int32 pixacompExtendArray()
60 * l_int32 pixacompReplacePix()
61 * l_int32 pixacompReplacePixcomp()
62 * l_int32 pixacompAddBox()
63 *
64 * Pixacomp accessors
65 * l_int32 pixacompGetCount()
66 * PIXC *pixacompGetPixcomp()
67 * PIX *pixacompGetPix()
68 * l_int32 pixacompGetPixDimensions()
69 * BOXA *pixacompGetBoxa()
70 * l_int32 pixacompGetBoxaCount()
71 * BOX *pixacompGetBox()
72 * l_int32 pixacompGetBoxGeometry()
73 * l_int32 pixacompGetOffset()
74 * l_int32 pixacompSetOffset()
75 *
76 * Pixacomp conversion to Pixa
77 * PIXA *pixaCreateFromPixacomp()
78 *
79 * Combining pixacomp
80 * l_int32 pixacompJoin()
81 * PIXAC *pixacompInterleave()
82 *
83 * Pixacomp serialized I/O
84 * PIXAC *pixacompRead()
85 * PIXAC *pixacompReadStream()
86 * PIXAC *pixacompReadMem()
87 * l_int32 pixacompWrite()
88 * l_int32 pixacompWriteStream()
89 * l_int32 pixacompWriteMem()
90 *
91 * Conversion to pdf
92 * l_int32 pixacompConvertToPdf()
93 * l_int32 pixacompConvertToPdfData()
94 * l_int32 pixacompFastConvertToPdfData()
95 *
96 * Output for debugging
97 * l_int32 pixacompWriteStreamInfo()
98 * l_int32 pixcompWriteStreamInfo()
99 * PIX *pixacompDisplayTiledAndScaled()
100 * l_int32 pixacompWriteFiles()
101 * l_int32 pixcompWriteFile()
102 *
103 * The Pixacomp is an array of Pixcomp, where each Pixcomp is a compressed
104 * string of the image. We don't use reference counting here.
105 * The basic application is to allow a large array of highly
106 * compressible images to reside in memory. We purposely don't
107 * reuse the Pixa for this, to avoid confusion and programming errors.
108 *
109 * Three compression formats are used: g4, png and jpeg.
110 * The compression type can be either specified or defaulted.
111 * If specified and it is not possible to compress (for example,
112 * you specify a jpeg on a 1 bpp image or one with a colormap),
113 * the compression type defaults to png. The jpeg compression quality
114 * can be specified using l_setJpegQuality(); otherwise the default is 75.
115 *
116 * The serialized version of the Pixacomp is similar to that for
117 * a Pixa, except that each Pixcomp can be compressed by one of
118 * tiffg4, png, or jpeg. Unlike serialization of the Pixa,
119 * serialization of the Pixacomp does not require any imaging
120 * libraries because it simply reads and writes the compressed data.
121 *
122 * There are two modes of use in accumulating images:
123 * (1) addition to the end of the array
124 * (2) random insertion (replacement) into the array
125 *
126 * In use, we assume that the array is fully populated up to the
127 * index value (n - 1), where n is the value of the pixcomp field n.
128 * Addition can only be made to the end of the fully populated array,
129 * at the index value n. Insertion can be made randomly, but again
130 * only within the array of pixcomps; i.e., within the set of
131 * indices {0 .... n-1}. The functions are pixacompReplacePix()
132 * and pixacompReplacePixcomp(), and they destroy the existing pixcomp.
133 *
134 * For addition to the end of the array, initialize the pixacomp with
135 * pixacompCreate(), which generates an empty array of pixcomps ptrs.
136 * For random insertion and replacement of pixcomp into a pixacomp,
137 * initialize a fully populated array using pixacompCreateWithInit().
138 *
139 * The offset field allows you to use an offset-based index to
140 * access the 0-based ptr array in the pixacomp. This would typically
141 * be used to map the pixacomp array index to a page number, or v.v.
142 * By default, the offset is 0. For example, suppose you have 50 images,
143 * corresponding to page numbers 10 - 59. Then you could use
144 * pixac = pixacompCreateWithInit(50, 10, ...);
145 * This would allocate an array of 50 pixcomps, but if you asked for
146 * the pix at index 10, using pixacompGetPix(pixac, 10), it would
147 * apply the offset internally, returning the pix at index 0 in the array.
148 * </pre>
149 */
150
151 #include <string.h>
152 #include "allheaders.h"
153
154 static const l_int32 INITIAL_PTR_ARRAYSIZE = 20; /* n'import quoi */
155
156 /* These two globals are defined in writefile.c */
157 extern l_int32 NumImageFileFormatExtensions;
158 extern const char *ImageFileFormatExtensions[];
159
160 /* Static functions */
161 static l_int32 pixacompExtendArray(PIXAC *pixac);
162 static l_int32 pixcompFastConvertToPdfData(PIXC *pixc, const char *title,
163 l_uint8 **pdata, size_t *pnbytes);
164
165
166 /*---------------------------------------------------------------------*
167 * Pixcomp creation and destruction *
168 *---------------------------------------------------------------------*/
169 /*!
170 * \brief pixcompCreateFromPix()
171 *
172 * \param[in] pix
173 * \param[in] comptype IFF_DEFAULT, IFF_TIFF_G4, IFF_PNG, IFF_JFIF_JPEG
174 * \return pixc, or NULL on error
175 *
176 * <pre>
177 * Notes:
178 * (1) Use %comptype == IFF_DEFAULT to have the compression
179 * type automatically determined.
180 * (2) To compress jpeg with a quality other than the default (75), use
181 * l_jpegSetQuality()
182 * </pre>
183 */
184 PIXC *
pixcompCreateFromPix(PIX * pix,l_int32 comptype)185 pixcompCreateFromPix(PIX *pix,
186 l_int32 comptype)
187 {
188 size_t size;
189 char *text;
190 l_int32 ret, format;
191 l_uint8 *data;
192 PIXC *pixc;
193
194 PROCNAME("pixcompCreateFromPix");
195
196 if (!pix)
197 return (PIXC *)ERROR_PTR("pix not defined", procName, NULL);
198 if (comptype != IFF_DEFAULT && comptype != IFF_TIFF_G4 &&
199 comptype != IFF_PNG && comptype != IFF_JFIF_JPEG)
200 return (PIXC *)ERROR_PTR("invalid comptype", procName, NULL);
201
202 if ((pixc = (PIXC *)LEPT_CALLOC(1, sizeof(PIXC))) == NULL)
203 return (PIXC *)ERROR_PTR("pixc not made", procName, NULL);
204 pixGetDimensions(pix, &pixc->w, &pixc->h, &pixc->d);
205 pixGetResolution(pix, &pixc->xres, &pixc->yres);
206 if (pixGetColormap(pix))
207 pixc->cmapflag = 1;
208 if ((text = pixGetText(pix)) != NULL)
209 pixc->text = stringNew(text);
210
211 pixcompDetermineFormat(comptype, pixc->d, pixc->cmapflag, &format);
212 pixc->comptype = format;
213 ret = pixWriteMem(&data, &size, pix, format);
214 if (ret) {
215 L_ERROR("write to memory failed\n", procName);
216 pixcompDestroy(&pixc);
217 return NULL;
218 }
219 pixc->data = data;
220 pixc->size = size;
221
222 return pixc;
223 }
224
225
226 /*!
227 * \brief pixcompCreateFromString()
228 *
229 * \param[in] data compressed string
230 * \param[in] size number of bytes
231 * \param[in] copyflag L_INSERT or L_COPY
232 * \return pixc, or NULL on error
233 *
234 * <pre>
235 * Notes:
236 * (1) This works when the compressed string is png, jpeg or tiffg4.
237 * (2) The copyflag determines if the data in the new Pixcomp is
238 * a copy of the input data.
239 * </pre>
240 */
241 PIXC *
pixcompCreateFromString(l_uint8 * data,size_t size,l_int32 copyflag)242 pixcompCreateFromString(l_uint8 *data,
243 size_t size,
244 l_int32 copyflag)
245 {
246 l_int32 format, w, h, d, bps, spp, iscmap;
247 PIXC *pixc;
248
249 PROCNAME("pixcompCreateFromString");
250
251 if (!data)
252 return (PIXC *)ERROR_PTR("data not defined", procName, NULL);
253 if (copyflag != L_INSERT && copyflag != L_COPY)
254 return (PIXC *)ERROR_PTR("invalid copyflag", procName, NULL);
255
256 if (pixReadHeaderMem(data, size, &format, &w, &h, &bps, &spp, &iscmap) == 1)
257 return (PIXC *)ERROR_PTR("header data not read", procName, NULL);
258 if ((pixc = (PIXC *)LEPT_CALLOC(1, sizeof(PIXC))) == NULL)
259 return (PIXC *)ERROR_PTR("pixc not made", procName, NULL);
260 d = (spp == 3) ? 32 : bps * spp;
261 pixc->w = w;
262 pixc->h = h;
263 pixc->d = d;
264 pixc->comptype = format;
265 pixc->cmapflag = iscmap;
266 if (copyflag == L_INSERT)
267 pixc->data = data;
268 else
269 pixc->data = l_binaryCopy(data, size);
270 pixc->size = size;
271 return pixc;
272 }
273
274
275 /*!
276 * \brief pixcompCreateFromFile()
277 *
278 * \param[in] filename
279 * \param[in] comptype IFF_DEFAULT, IFF_TIFF_G4, IFF_PNG, IFF_JFIF_JPEG
280 * \return pixc, or NULL on error
281 *
282 * <pre>
283 * Notes:
284 * (1) Use %comptype == IFF_DEFAULT to have the compression
285 * type automatically determined.
286 * (2) If the comptype is invalid for this file, the default will
287 * be substituted.
288 * </pre>
289 */
290 PIXC *
pixcompCreateFromFile(const char * filename,l_int32 comptype)291 pixcompCreateFromFile(const char *filename,
292 l_int32 comptype)
293 {
294 l_int32 format;
295 size_t nbytes;
296 l_uint8 *data;
297 PIX *pix;
298 PIXC *pixc;
299
300 PROCNAME("pixcompCreateFromFile");
301
302 if (!filename)
303 return (PIXC *)ERROR_PTR("filename not defined", procName, NULL);
304 if (comptype != IFF_DEFAULT && comptype != IFF_TIFF_G4 &&
305 comptype != IFF_PNG && comptype != IFF_JFIF_JPEG)
306 return (PIXC *)ERROR_PTR("invalid comptype", procName, NULL);
307
308 findFileFormat(filename, &format);
309 if (format == IFF_UNKNOWN) {
310 L_ERROR("unreadable file: %s\n", procName, filename);
311 return NULL;
312 }
313
314 /* Can we accept the encoded file directly? Remember that
315 * png is the "universal" compression type, so if requested
316 * it takes precedence. Otherwise, if the file is already
317 * compressed in g4 or jpeg, just accept the string. */
318 if ((format == IFF_TIFF_G4 && comptype != IFF_PNG) ||
319 (format == IFF_JFIF_JPEG && comptype != IFF_PNG))
320 comptype = format;
321 if (comptype != IFF_DEFAULT && comptype == format) {
322 data = l_binaryRead(filename, &nbytes);
323 if ((pixc = pixcompCreateFromString(data, nbytes, L_INSERT)) == NULL) {
324 LEPT_FREE(data);
325 return (PIXC *)ERROR_PTR("pixc not made (string)", procName, NULL);
326 }
327 return pixc;
328 }
329
330 /* Need to recompress in the default format */
331 if ((pix = pixRead(filename)) == NULL)
332 return (PIXC *)ERROR_PTR("pix not read", procName, NULL);
333 if ((pixc = pixcompCreateFromPix(pix, comptype)) == NULL) {
334 pixDestroy(&pix);
335 return (PIXC *)ERROR_PTR("pixc not made", procName, NULL);
336 }
337 pixDestroy(&pix);
338 return pixc;
339 }
340
341
342 /*!
343 * \brief pixcompDestroy()
344 *
345 * \param[in,out] ppixc will be nulled
346 * \return void
347 *
348 * <pre>
349 * Notes:
350 * (1) Always nulls the input ptr.
351 * </pre>
352 */
353 void
pixcompDestroy(PIXC ** ppixc)354 pixcompDestroy(PIXC **ppixc)
355 {
356 PIXC *pixc;
357
358 PROCNAME("pixcompDestroy");
359
360 if (!ppixc) {
361 L_WARNING("ptr address is null!\n", procName);
362 return;
363 }
364
365 if ((pixc = *ppixc) == NULL)
366 return;
367
368 LEPT_FREE(pixc->data);
369 if (pixc->text)
370 LEPT_FREE(pixc->text);
371 LEPT_FREE(pixc);
372 *ppixc = NULL;
373 return;
374 }
375
376
377 /*!
378 * \brief pixcompCopy()
379 *
380 * \param[in] pixcs
381 * \return pixcd, or NULL on error
382 */
383 PIXC *
pixcompCopy(PIXC * pixcs)384 pixcompCopy(PIXC *pixcs)
385 {
386 size_t size;
387 l_uint8 *datas, *datad;
388 PIXC *pixcd;
389
390 PROCNAME("pixcompCopy");
391
392 if (!pixcs)
393 return (PIXC *)ERROR_PTR("pixcs not defined", procName, NULL);
394
395 if ((pixcd = (PIXC *)LEPT_CALLOC(1, sizeof(PIXC))) == NULL)
396 return (PIXC *)ERROR_PTR("pixcd not made", procName, NULL);
397 pixcd->w = pixcs->w;
398 pixcd->h = pixcs->h;
399 pixcd->d = pixcs->d;
400 pixcd->xres = pixcs->xres;
401 pixcd->yres = pixcs->yres;
402 pixcd->comptype = pixcs->comptype;
403 if (pixcs->text != NULL)
404 pixcd->text = stringNew(pixcs->text);
405 pixcd->cmapflag = pixcs->cmapflag;
406
407 /* Copy image data */
408 size = pixcs->size;
409 datas = pixcs->data;
410 datad = (l_uint8 *)LEPT_CALLOC(size, sizeof(l_int8));
411 memcpy((char*)datad, (char*)datas, size);
412 pixcd->data = datad;
413 pixcd->size = size;
414 return pixcd;
415 }
416
417
418 /*---------------------------------------------------------------------*
419 * Pixcomp accessors *
420 *---------------------------------------------------------------------*/
421 /*!
422 * \brief pixcompGetDimensions()
423 *
424 * \param[in] pixc
425 * \param[out] pw, ph, pd [optional]
426 * \return 0 if OK, 1 on error
427 */
428 l_int32
pixcompGetDimensions(PIXC * pixc,l_int32 * pw,l_int32 * ph,l_int32 * pd)429 pixcompGetDimensions(PIXC *pixc,
430 l_int32 *pw,
431 l_int32 *ph,
432 l_int32 *pd)
433 {
434 PROCNAME("pixcompGetDimensions");
435
436 if (!pixc)
437 return ERROR_INT("pixc not defined", procName, 1);
438 if (pw) *pw = pixc->w;
439 if (ph) *ph = pixc->h;
440 if (pd) *pd = pixc->d;
441 return 0;
442 }
443
444
445 /*!
446 * \brief pixcompGetParameters()
447 *
448 * \param[in] pixc
449 * \param[out] pxres, pyres, pcomptype, pcmapflag [all optional]
450 * \return 0 if OK, 1 on error
451 */
452 l_int32
pixcompGetParameters(PIXC * pixc,l_int32 * pxres,l_int32 * pyres,l_int32 * pcomptype,l_int32 * pcmapflag)453 pixcompGetParameters(PIXC *pixc,
454 l_int32 *pxres,
455 l_int32 *pyres,
456 l_int32 *pcomptype,
457 l_int32 *pcmapflag)
458 {
459 PROCNAME("pixcompGetParameters");
460
461 if (!pixc)
462 return ERROR_INT("pixc not defined", procName, 1);
463 if (pxres) *pxres = pixc->xres;
464 if (pyres) *pyres = pixc->yres;
465 if (pcomptype) *pcomptype = pixc->comptype;
466 if (pcmapflag) *pcmapflag = pixc->cmapflag;
467 return 0;
468 }
469
470
471 /*---------------------------------------------------------------------*
472 * Pixcomp compression selection *
473 *---------------------------------------------------------------------*/
474 /*!
475 * \brief pixcompDetermineFormat()
476 *
477 * \param[in] comptype IFF_DEFAULT, IFF_TIFF_G4, IFF_PNG, IFF_JFIF_JPEG
478 * \param[in] d pix depth
479 * \param[in] cmapflag 1 if pix to be compressed as a colormap; 0 otherwise
480 * \param[out] pformat return IFF_TIFF, IFF_PNG or IFF_JFIF_JPEG
481 * \return 0 if OK; 1 on error
482 *
483 * <pre>
484 * Notes:
485 * (1) This determines the best format for a pix, given both
486 * the request (%comptype) and the image characteristics.
487 * (2) If %comptype == IFF_DEFAULT, this does not necessarily result
488 * in png encoding. Instead, it returns one of the three formats
489 * that is both valid and most likely to give best compression.
490 * (3) If the pix cannot be compressed by the input value of
491 * %comptype, this selects IFF_PNG, which can compress all pix.
492 * </pre>
493 */
494 l_int32
pixcompDetermineFormat(l_int32 comptype,l_int32 d,l_int32 cmapflag,l_int32 * pformat)495 pixcompDetermineFormat(l_int32 comptype,
496 l_int32 d,
497 l_int32 cmapflag,
498 l_int32 *pformat)
499 {
500
501 PROCNAME("pixcompDetermineFormat");
502
503 if (!pformat)
504 return ERROR_INT("&format not defined", procName, 1);
505 *pformat = IFF_PNG; /* init value and default */
506 if (comptype != IFF_DEFAULT && comptype != IFF_TIFF_G4 &&
507 comptype != IFF_PNG && comptype != IFF_JFIF_JPEG)
508 return ERROR_INT("invalid comptype", procName, 1);
509
510 if (comptype == IFF_DEFAULT) {
511 if (d == 1)
512 *pformat = IFF_TIFF_G4;
513 else if (d == 16)
514 *pformat = IFF_PNG;
515 else if (d >= 8 && !cmapflag)
516 *pformat = IFF_JFIF_JPEG;
517 } else if (comptype == IFF_TIFF_G4 && d == 1) {
518 *pformat = IFF_TIFF_G4;
519 } else if (comptype == IFF_JFIF_JPEG && d >= 8 && !cmapflag) {
520 *pformat = IFF_JFIF_JPEG;
521 }
522
523 return 0;
524 }
525
526
527 /*---------------------------------------------------------------------*
528 * Pixcomp conversion to Pix *
529 *---------------------------------------------------------------------*/
530 /*!
531 * \brief pixCreateFromPixcomp()
532 *
533 * \param[in] pixc
534 * \return pix, or NULL on error
535 */
536 PIX *
pixCreateFromPixcomp(PIXC * pixc)537 pixCreateFromPixcomp(PIXC *pixc)
538 {
539 l_int32 w, h, d, cmapinpix, format;
540 PIX *pix;
541
542 PROCNAME("pixCreateFromPixcomp");
543
544 if (!pixc)
545 return (PIX *)ERROR_PTR("pixc not defined", procName, NULL);
546
547 if ((pix = pixReadMem(pixc->data, pixc->size)) == NULL)
548 return (PIX *)ERROR_PTR("pix not read", procName, NULL);
549 pixSetResolution(pix, pixc->xres, pixc->yres);
550 if (pixc->text)
551 pixSetText(pix, pixc->text);
552
553 /* Check fields for consistency */
554 pixGetDimensions(pix, &w, &h, &d);
555 if (pixc->w != w) {
556 L_INFO("pix width %d != pixc width %d\n", procName, w, pixc->w);
557 L_ERROR("pix width %d != pixc width\n", procName, w);
558 }
559 if (pixc->h != h)
560 L_ERROR("pix height %d != pixc height\n", procName, h);
561 if (pixc->d != d) {
562 if (pixc->d == 16) /* we strip 16 --> 8 bpp by default */
563 L_WARNING("pix depth %d != pixc depth 16\n", procName, d);
564 else
565 L_ERROR("pix depth %d != pixc depth\n", procName, d);
566 }
567 cmapinpix = (pixGetColormap(pix) != NULL);
568 if ((cmapinpix && !pixc->cmapflag) || (!cmapinpix && pixc->cmapflag))
569 L_ERROR("pix cmap flag inconsistent\n", procName);
570 format = pixGetInputFormat(pix);
571 if (format != pixc->comptype) {
572 L_ERROR("pix comptype %d not equal to pixc comptype\n",
573 procName, format);
574 }
575
576 return pix;
577 }
578
579
580 /*---------------------------------------------------------------------*
581 * Pixacomp creation and destruction *
582 *---------------------------------------------------------------------*/
583 /*!
584 * \brief pixacompCreate()
585 *
586 * \param[in] n initial number of ptrs
587 * \return pixac, or NULL on error
588 */
589 PIXAC *
pixacompCreate(l_int32 n)590 pixacompCreate(l_int32 n)
591 {
592 PIXAC *pixac;
593
594 PROCNAME("pixacompCreate");
595
596 if (n <= 0)
597 n = INITIAL_PTR_ARRAYSIZE;
598
599 if ((pixac = (PIXAC *)LEPT_CALLOC(1, sizeof(PIXAC))) == NULL)
600 return (PIXAC *)ERROR_PTR("pixac not made", procName, NULL);
601 pixac->n = 0;
602 pixac->nalloc = n;
603 pixac->offset = 0;
604
605 if ((pixac->pixc = (PIXC **)LEPT_CALLOC(n, sizeof(PIXC *))) == NULL) {
606 pixacompDestroy(&pixac);
607 return (PIXAC *)ERROR_PTR("pixc ptrs not made", procName, NULL);
608 }
609 if ((pixac->boxa = boxaCreate(n)) == NULL) {
610 pixacompDestroy(&pixac);
611 return (PIXAC *)ERROR_PTR("boxa not made", procName, NULL);
612 }
613
614 return pixac;
615 }
616
617
618 /*!
619 * \brief pixacompCreateWithInit()
620 *
621 * \param[in] n initial number of ptrs
622 * \param[in] offset difference: accessor index - pixacomp array index
623 * \param[in] pix [optional] initialize each ptr in pixacomp to this pix;
624 * can be NULL
625 * \param[in] comptype IFF_DEFAULT, IFF_TIFF_G4, IFF_PNG, IFF_JFIF_JPEG
626 * \return pixac, or NULL on error
627 *
628 * <pre>
629 * Notes:
630 * (1) Initializes a pixacomp to be fully populated with %pix,
631 * compressed using %comptype. If %pix == NULL, %comptype
632 * is ignored.
633 * (2) Typically, the array is initialized with a tiny pix.
634 * This is most easily done by setting %pix == NULL, causing
635 * initialization of each array element with a tiny placeholder
636 * pix (w = h = d = 1), using comptype = IFF_TIFF_G4 .
637 * (3) Example usage:
638 * // Generate pixacomp for pages 30 - 49. This has an array
639 * // size of 20 and the page number offset is 30.
640 * PixaComp *pixac = pixacompCreateWithInit(20, 30, NULL,
641 * IFF_TIFF_G4);
642 * // Now insert png-compressed images into the initialized array
643 * for (pageno = 30; pageno < 50; pageno++) {
644 * Pix *pixt = ... // derived from image[pageno]
645 * if (pixt)
646 * pixacompReplacePix(pixac, pageno, pixt, IFF_PNG);
647 * pixDestroy(&pixt);
648 * }
649 * The result is a pixac with 20 compressed strings, and with
650 * selected pixt replacing the placeholders.
651 * To extract the image for page 38, which is decompressed
652 * from element 8 in the array, use:
653 * pixt = pixacompGetPix(pixac, 38);
654 * </pre>
655 */
656 PIXAC *
pixacompCreateWithInit(l_int32 n,l_int32 offset,PIX * pix,l_int32 comptype)657 pixacompCreateWithInit(l_int32 n,
658 l_int32 offset,
659 PIX *pix,
660 l_int32 comptype)
661 {
662 l_int32 i;
663 PIX *pixt;
664 PIXC *pixc;
665 PIXAC *pixac;
666
667 PROCNAME("pixacompCreateWithInit");
668
669 if (n <= 0)
670 return (PIXAC *)ERROR_PTR("n must be > 0", procName, NULL);
671 if (pix) {
672 if (comptype != IFF_DEFAULT && comptype != IFF_TIFF_G4 &&
673 comptype != IFF_PNG && comptype != IFF_JFIF_JPEG)
674 return (PIXAC *)ERROR_PTR("invalid comptype", procName, NULL);
675 } else {
676 comptype = IFF_TIFF_G4;
677 }
678 if (offset < 0) {
679 L_WARNING("offset < 0; setting to 0\n", procName);
680 offset = 0;
681 }
682
683 if ((pixac = pixacompCreate(n)) == NULL)
684 return (PIXAC *)ERROR_PTR("pixac not made", procName, NULL);
685 pixacompSetOffset(pixac, offset);
686 if (pix)
687 pixt = pixClone(pix);
688 else
689 pixt = pixCreate(1, 1, 1);
690 for (i = 0; i < n; i++) {
691 pixc = pixcompCreateFromPix(pixt, comptype);
692 pixacompAddPixcomp(pixac, pixc, L_INSERT);
693 }
694 pixDestroy(&pixt);
695
696 return pixac;
697 }
698
699
700 /*!
701 * \brief pixacompCreateFromPixa()
702 *
703 * \param[in] pixa
704 * \param[in] comptype IFF_DEFAULT, IFF_TIFF_G4, IFF_PNG, IFF_JFIF_JPEG
705 * \param[in] accesstype L_COPY, L_CLONE, L_COPY_CLONE
706 * \return 0 if OK, 1 on error
707 *
708 * <pre>
709 * Notes:
710 * (1) If %format == IFF_DEFAULT, the conversion format for each
711 * image is chosen automatically. Otherwise, we use the
712 * specified format unless it can't be done (e.g., jpeg
713 * for a 1, 2 or 4 bpp pix, or a pix with a colormap),
714 * in which case we use the default (assumed best) compression.
715 * (2) %accesstype is used to extract a boxa from %pixa.
716 * (3) To compress jpeg with a quality other than the default (75), use
717 * l_jpegSetQuality()
718 * </pre>
719 */
720 PIXAC *
pixacompCreateFromPixa(PIXA * pixa,l_int32 comptype,l_int32 accesstype)721 pixacompCreateFromPixa(PIXA *pixa,
722 l_int32 comptype,
723 l_int32 accesstype)
724 {
725 l_int32 i, n;
726 BOXA *boxa;
727 PIX *pix;
728 PIXAC *pixac;
729
730 PROCNAME("pixacompCreateFromPixa");
731
732 if (!pixa)
733 return (PIXAC *)ERROR_PTR("pixa not defined", procName, NULL);
734 if (comptype != IFF_DEFAULT && comptype != IFF_TIFF_G4 &&
735 comptype != IFF_PNG && comptype != IFF_JFIF_JPEG)
736 return (PIXAC *)ERROR_PTR("invalid comptype", procName, NULL);
737 if (accesstype != L_COPY && accesstype != L_CLONE &&
738 accesstype != L_COPY_CLONE)
739 return (PIXAC *)ERROR_PTR("invalid accesstype", procName, NULL);
740
741 n = pixaGetCount(pixa);
742 if ((pixac = pixacompCreate(n)) == NULL)
743 return (PIXAC *)ERROR_PTR("pixac not made", procName, NULL);
744 for (i = 0; i < n; i++) {
745 pix = pixaGetPix(pixa, i, L_CLONE);
746 pixacompAddPix(pixac, pix, comptype);
747 pixDestroy(&pix);
748 }
749 if ((boxa = pixaGetBoxa(pixa, accesstype)) != NULL) {
750 boxaDestroy(&pixac->boxa);
751 pixac->boxa = boxa;
752 }
753
754 return pixac;
755 }
756
757
758 /*!
759 * \brief pixacompCreateFromFiles()
760 *
761 * \param[in] dirname
762 * \param[in] substr [optional] substring filter on filenames; can be null
763 * \param[in] comptype IFF_DEFAULT, IFF_TIFF_G4, IFF_PNG, IFF_JFIF_JPEG
764 * \return pixac, or NULL on error
765 *
766 * <pre>
767 * Notes:
768 * (1) %dirname is the full path for the directory.
769 * (2) %substr is the part of the file name (excluding
770 * the directory) that is to be matched. All matching
771 * filenames are read into the Pixa. If substr is NULL,
772 * all filenames are read into the Pixa.
773 * (3) Use %comptype == IFF_DEFAULT to have the compression
774 * type automatically determined for each file.
775 * (4) If the comptype is invalid for a file, the default will
776 * be substituted.
777 * </pre>
778 */
779 PIXAC *
pixacompCreateFromFiles(const char * dirname,const char * substr,l_int32 comptype)780 pixacompCreateFromFiles(const char *dirname,
781 const char *substr,
782 l_int32 comptype)
783 {
784 PIXAC *pixac;
785 SARRAY *sa;
786
787 PROCNAME("pixacompCreateFromFiles");
788
789 if (!dirname)
790 return (PIXAC *)ERROR_PTR("dirname not defined", procName, NULL);
791 if (comptype != IFF_DEFAULT && comptype != IFF_TIFF_G4 &&
792 comptype != IFF_PNG && comptype != IFF_JFIF_JPEG)
793 return (PIXAC *)ERROR_PTR("invalid comptype", procName, NULL);
794
795 if ((sa = getSortedPathnamesInDirectory(dirname, substr, 0, 0)) == NULL)
796 return (PIXAC *)ERROR_PTR("sa not made", procName, NULL);
797 pixac = pixacompCreateFromSA(sa, comptype);
798 sarrayDestroy(&sa);
799 return pixac;
800 }
801
802
803 /*!
804 * \brief pixacompCreateFromSA()
805 *
806 * \param[in] sa full pathnames for all files
807 * \param[in] comptype IFF_DEFAULT, IFF_TIFF_G4, IFF_PNG, IFF_JFIF_JPEG
808 * \return pixac, or NULL on error
809 *
810 * <pre>
811 * Notes:
812 * (1) Use %comptype == IFF_DEFAULT to have the compression
813 * type automatically determined for each file.
814 * (2) If the comptype is invalid for a file, the default will
815 * be substituted.
816 * </pre>
817 */
818 PIXAC *
pixacompCreateFromSA(SARRAY * sa,l_int32 comptype)819 pixacompCreateFromSA(SARRAY *sa,
820 l_int32 comptype)
821 {
822 char *str;
823 l_int32 i, n;
824 PIXC *pixc;
825 PIXAC *pixac;
826
827 PROCNAME("pixacompCreateFromSA");
828
829 if (!sa)
830 return (PIXAC *)ERROR_PTR("sarray not defined", procName, NULL);
831 if (comptype != IFF_DEFAULT && comptype != IFF_TIFF_G4 &&
832 comptype != IFF_PNG && comptype != IFF_JFIF_JPEG)
833 return (PIXAC *)ERROR_PTR("invalid comptype", procName, NULL);
834
835 n = sarrayGetCount(sa);
836 pixac = pixacompCreate(n);
837 for (i = 0; i < n; i++) {
838 str = sarrayGetString(sa, i, L_NOCOPY);
839 if ((pixc = pixcompCreateFromFile(str, comptype)) == NULL) {
840 L_ERROR("pixc not read from file: %s\n", procName, str);
841 continue;
842 }
843 pixacompAddPixcomp(pixac, pixc, L_INSERT);
844 }
845 return pixac;
846 }
847
848
849 /*!
850 * \brief pixacompDestroy()
851 *
852 * \param[in,out] ppixac to be nulled
853 * \return void
854 *
855 * <pre>
856 * Notes:
857 * (1) Always nulls the input ptr.
858 * </pre>
859 */
860 void
pixacompDestroy(PIXAC ** ppixac)861 pixacompDestroy(PIXAC **ppixac)
862 {
863 l_int32 i;
864 PIXAC *pixac;
865
866 PROCNAME("pixacompDestroy");
867
868 if (ppixac == NULL) {
869 L_WARNING("ptr address is NULL!\n", procName);
870 return;
871 }
872
873 if ((pixac = *ppixac) == NULL)
874 return;
875
876 for (i = 0; i < pixac->n; i++)
877 pixcompDestroy(&pixac->pixc[i]);
878 LEPT_FREE(pixac->pixc);
879 boxaDestroy(&pixac->boxa);
880 LEPT_FREE(pixac);
881
882 *ppixac = NULL;
883 return;
884 }
885
886
887 /*---------------------------------------------------------------------*
888 * Pixacomp addition *
889 *---------------------------------------------------------------------*/
890 /*!
891 * \brief pixacompAddPix()
892 *
893 * \param[in] pixac
894 * \param[in] pix to be added
895 * \param[in] comptype IFF_DEFAULT, IFF_TIFF_G4, IFF_PNG, IFF_JFIF_JPEG
896 * \return 0 if OK; 1 on error
897 *
898 * <pre>
899 * Notes:
900 * (1) The array is filled up to the (n-1)-th element, and this
901 * converts the input pix to a pixc and adds it at
902 * the n-th position.
903 * (2) The pixc produced from the pix is owned by the pixac.
904 * The input pix is not affected.
905 * </pre>
906 */
907 l_int32
pixacompAddPix(PIXAC * pixac,PIX * pix,l_int32 comptype)908 pixacompAddPix(PIXAC *pixac,
909 PIX *pix,
910 l_int32 comptype)
911 {
912 l_int32 cmapflag, format;
913 PIXC *pixc;
914
915 PROCNAME("pixacompAddPix");
916
917 if (!pixac)
918 return ERROR_INT("pixac not defined", procName, 1);
919 if (!pix)
920 return ERROR_INT("pix not defined", procName, 1);
921 if (comptype != IFF_DEFAULT && comptype != IFF_TIFF_G4 &&
922 comptype != IFF_PNG && comptype != IFF_JFIF_JPEG)
923 return ERROR_INT("invalid format", procName, 1);
924
925 cmapflag = pixGetColormap(pix) ? 1 : 0;
926 pixcompDetermineFormat(comptype, pixGetDepth(pix), cmapflag, &format);
927 if ((pixc = pixcompCreateFromPix(pix, format)) == NULL)
928 return ERROR_INT("pixc not made", procName, 1);
929 pixacompAddPixcomp(pixac, pixc, L_INSERT);
930 return 0;
931 }
932
933
934 /*!
935 * \brief pixacompAddPixcomp()
936 *
937 * \param[in] pixac
938 * \param[in] pixc to be added by insertion
939 * \param[in] copyflag L_INSERT, L_COPY
940 * \return 0 if OK; 1 on error
941 *
942 * <pre>
943 * Notes:
944 * (1) Anything added to a pixac is owned by the pixac.
945 * So do not L_INSERT a pixc that is owned by another pixac,
946 * or destroy a pixc that has been L_INSERTed.
947 * </pre>
948 */
949 l_int32
pixacompAddPixcomp(PIXAC * pixac,PIXC * pixc,l_int32 copyflag)950 pixacompAddPixcomp(PIXAC *pixac,
951 PIXC *pixc,
952 l_int32 copyflag)
953 {
954 l_int32 n;
955
956 PROCNAME("pixacompAddPixcomp");
957
958 if (!pixac)
959 return ERROR_INT("pixac not defined", procName, 1);
960 if (!pixc)
961 return ERROR_INT("pixc not defined", procName, 1);
962 if (copyflag != L_INSERT && copyflag != L_COPY)
963 return ERROR_INT("invalid copyflag", procName, 1);
964
965 n = pixac->n;
966 if (n >= pixac->nalloc)
967 pixacompExtendArray(pixac);
968 if (copyflag == L_INSERT)
969 pixac->pixc[n] = pixc;
970 else /* L_COPY */
971 pixac->pixc[n] = pixcompCopy(pixc);
972 pixac->n++;
973
974 return 0;
975 }
976
977
978 /*!
979 * \brief pixacompExtendArray()
980 *
981 * \param[in] pixac
982 * \return 0 if OK; 1 on error
983 *
984 * <pre>
985 * Notes:
986 * (1) We extend the boxa array simultaneously. This is
987 * necessary in case we are NOT adding boxes simultaneously
988 * with adding pixc. We always want the sizes of the
989 * pixac and boxa ptr arrays to be equal.
990 * </pre>
991 */
992 static l_int32
pixacompExtendArray(PIXAC * pixac)993 pixacompExtendArray(PIXAC *pixac)
994 {
995 PROCNAME("pixacompExtendArray");
996
997 if (!pixac)
998 return ERROR_INT("pixac not defined", procName, 1);
999
1000 if ((pixac->pixc = (PIXC **)reallocNew((void **)&pixac->pixc,
1001 sizeof(PIXC *) * pixac->nalloc,
1002 2 * sizeof(PIXC *) * pixac->nalloc)) == NULL)
1003 return ERROR_INT("new ptr array not returned", procName, 1);
1004 pixac->nalloc = 2 * pixac->nalloc;
1005 boxaExtendArray(pixac->boxa);
1006 return 0;
1007 }
1008
1009
1010 /*!
1011 * \brief pixacompReplacePix()
1012 *
1013 * \param[in] pixac
1014 * \param[in] index caller's view of index within pixac; includes offset
1015 * \param[in] pix owned by the caller
1016 * \param[in] comptype IFF_DEFAULT, IFF_TIFF_G4, IFF_PNG, IFF_JFIF_JPEG
1017 * \return 0 if OK; 1 on error
1018 *
1019 * <pre>
1020 * Notes:
1021 * (1) The %index includes the offset, which must be subtracted
1022 * to get the actual index into the ptr array.
1023 * (2) The input %pix is converted to a pixc, which is then inserted
1024 * into the pixac.
1025 * </pre>
1026 */
1027 l_int32
pixacompReplacePix(PIXAC * pixac,l_int32 index,PIX * pix,l_int32 comptype)1028 pixacompReplacePix(PIXAC *pixac,
1029 l_int32 index,
1030 PIX *pix,
1031 l_int32 comptype)
1032 {
1033 l_int32 n, aindex;
1034 PIXC *pixc;
1035
1036 PROCNAME("pixacompReplacePix");
1037
1038 if (!pixac)
1039 return ERROR_INT("pixac not defined", procName, 1);
1040 n = pixacompGetCount(pixac);
1041 aindex = index - pixac->offset;
1042 if (aindex < 0 || aindex >= n)
1043 return ERROR_INT("array index out of bounds", procName, 1);
1044 if (!pix)
1045 return ERROR_INT("pix not defined", procName, 1);
1046 if (comptype != IFF_DEFAULT && comptype != IFF_TIFF_G4 &&
1047 comptype != IFF_PNG && comptype != IFF_JFIF_JPEG)
1048 return ERROR_INT("invalid format", procName, 1);
1049
1050 pixc = pixcompCreateFromPix(pix, comptype);
1051 pixacompReplacePixcomp(pixac, index, pixc);
1052 return 0;
1053 }
1054
1055
1056 /*!
1057 * \brief pixacompReplacePixcomp()
1058 *
1059 * \param[in] pixac
1060 * \param[in] index caller's view of index within pixac; includes offset
1061 * \param[in] pixc to replace existing one, which is destroyed
1062 * \return 0 if OK; 1 on error
1063 *
1064 * <pre>
1065 * Notes:
1066 * (1) The %index includes the offset, which must be subtracted
1067 * to get the actual index into the ptr array.
1068 * (2) The inserted %pixc is now owned by the pixac. The caller
1069 * must not destroy it.
1070 * </pre>
1071 */
1072 l_int32
pixacompReplacePixcomp(PIXAC * pixac,l_int32 index,PIXC * pixc)1073 pixacompReplacePixcomp(PIXAC *pixac,
1074 l_int32 index,
1075 PIXC *pixc)
1076 {
1077 l_int32 n, aindex;
1078 PIXC *pixct;
1079
1080 PROCNAME("pixacompReplacePixcomp");
1081
1082 if (!pixac)
1083 return ERROR_INT("pixac not defined", procName, 1);
1084 n = pixacompGetCount(pixac);
1085 aindex = index - pixac->offset;
1086 if (aindex < 0 || aindex >= n)
1087 return ERROR_INT("array index out of bounds", procName, 1);
1088 if (!pixc)
1089 return ERROR_INT("pixc not defined", procName, 1);
1090
1091 pixct = pixacompGetPixcomp(pixac, index, L_NOCOPY); /* use %index */
1092 pixcompDestroy(&pixct);
1093 pixac->pixc[aindex] = pixc; /* replace; use array index */
1094
1095 return 0;
1096 }
1097
1098
1099 /*!
1100 * \brief pixacompAddBox()
1101 *
1102 * \param[in] pixac
1103 * \param[in] box
1104 * \param[in] copyflag L_INSERT, L_COPY
1105 * \return 0 if OK, 1 on error
1106 */
1107 l_int32
pixacompAddBox(PIXAC * pixac,BOX * box,l_int32 copyflag)1108 pixacompAddBox(PIXAC *pixac,
1109 BOX *box,
1110 l_int32 copyflag)
1111 {
1112 PROCNAME("pixacompAddBox");
1113
1114 if (!pixac)
1115 return ERROR_INT("pixac not defined", procName, 1);
1116 if (!box)
1117 return ERROR_INT("box not defined", procName, 1);
1118 if (copyflag != L_INSERT && copyflag != L_COPY)
1119 return ERROR_INT("invalid copyflag", procName, 1);
1120
1121 boxaAddBox(pixac->boxa, box, copyflag);
1122 return 0;
1123 }
1124
1125
1126 /*---------------------------------------------------------------------*
1127 * Pixacomp accessors *
1128 *---------------------------------------------------------------------*/
1129 /*!
1130 * \brief pixacompGetCount()
1131 *
1132 * \param[in] pixac
1133 * \return count, or 0 if no pixa
1134 */
1135 l_int32
pixacompGetCount(PIXAC * pixac)1136 pixacompGetCount(PIXAC *pixac)
1137 {
1138 PROCNAME("pixacompGetCount");
1139
1140 if (!pixac)
1141 return ERROR_INT("pixac not defined", procName, 0);
1142
1143 return pixac->n;
1144 }
1145
1146
1147 /*!
1148 * \brief pixacompGetPixcomp()
1149 *
1150 * \param[in] pixac
1151 * \param[in] index caller's view of index within pixac; includes offset
1152 * \param[in] copyflag L_NOCOPY, L_COPY
1153 * \return pixc, or NULL on error
1154 *
1155 * <pre>
1156 * Notes:
1157 * (1) The %index includes the offset, which must be subtracted
1158 * to get the actual index into the ptr array.
1159 * (2) If copyflag == L_NOCOPY, the pixc is owned by %pixac; do
1160 * not destroy.
1161 * </pre>
1162 */
1163 PIXC *
pixacompGetPixcomp(PIXAC * pixac,l_int32 index,l_int32 copyflag)1164 pixacompGetPixcomp(PIXAC *pixac,
1165 l_int32 index,
1166 l_int32 copyflag)
1167 {
1168 l_int32 aindex;
1169
1170 PROCNAME("pixacompGetPixcomp");
1171
1172 if (!pixac)
1173 return (PIXC *)ERROR_PTR("pixac not defined", procName, NULL);
1174 if (copyflag != L_NOCOPY && copyflag != L_COPY)
1175 return (PIXC *)ERROR_PTR("invalid copyflag", procName, NULL);
1176 aindex = index - pixac->offset;
1177 if (aindex < 0 || aindex >= pixac->n)
1178 return (PIXC *)ERROR_PTR("array index not valid", procName, NULL);
1179
1180 if (copyflag == L_NOCOPY)
1181 return pixac->pixc[aindex];
1182 else /* L_COPY */
1183 return pixcompCopy(pixac->pixc[aindex]);
1184 }
1185
1186
1187 /*!
1188 * \brief pixacompGetPix()
1189 *
1190 * \param[in] pixac
1191 * \param[in] index caller's view of index within pixac; includes offset
1192 * \return pix, or NULL on error
1193 *
1194 * <pre>
1195 * Notes:
1196 * (1) The %index includes the offset, which must be subtracted
1197 * to get the actual index into the ptr array.
1198 * </pre>
1199 */
1200 PIX *
pixacompGetPix(PIXAC * pixac,l_int32 index)1201 pixacompGetPix(PIXAC *pixac,
1202 l_int32 index)
1203 {
1204 l_int32 aindex;
1205 PIXC *pixc;
1206
1207 PROCNAME("pixacompGetPix");
1208
1209 if (!pixac)
1210 return (PIX *)ERROR_PTR("pixac not defined", procName, NULL);
1211 aindex = index - pixac->offset;
1212 if (aindex < 0 || aindex >= pixac->n)
1213 return (PIX *)ERROR_PTR("array index not valid", procName, NULL);
1214
1215 pixc = pixacompGetPixcomp(pixac, index, L_NOCOPY);
1216 return pixCreateFromPixcomp(pixc);
1217 }
1218
1219
1220 /*!
1221 * \brief pixacompGetPixDimensions()
1222 *
1223 * \param[in] pixac
1224 * \param[in] index caller's view of index within pixac; includes offset
1225 * \param[out] pw, ph, pd [optional] each can be null
1226 * \return 0 if OK, 1 on error
1227 *
1228 * <pre>
1229 * Notes:
1230 * (1) The %index includes the offset, which must be subtracted
1231 * to get the actual index into the ptr array.
1232 * </pre>
1233 */
1234 l_int32
pixacompGetPixDimensions(PIXAC * pixac,l_int32 index,l_int32 * pw,l_int32 * ph,l_int32 * pd)1235 pixacompGetPixDimensions(PIXAC *pixac,
1236 l_int32 index,
1237 l_int32 *pw,
1238 l_int32 *ph,
1239 l_int32 *pd)
1240 {
1241 l_int32 aindex;
1242 PIXC *pixc;
1243
1244 PROCNAME("pixacompGetPixDimensions");
1245
1246 if (!pixac)
1247 return ERROR_INT("pixac not defined", procName, 1);
1248 aindex = index - pixac->offset;
1249 if (aindex < 0 || aindex >= pixac->n)
1250 return ERROR_INT("array index not valid", procName, 1);
1251
1252 if ((pixc = pixac->pixc[aindex]) == NULL)
1253 return ERROR_INT("pixc not found!", procName, 1);
1254 pixcompGetDimensions(pixc, pw, ph, pd);
1255 return 0;
1256 }
1257
1258
1259 /*!
1260 * \brief pixacompGetBoxa()
1261 *
1262 * \param[in] pixac
1263 * \param[in] accesstype L_COPY, L_CLONE, L_COPY_CLONE
1264 * \return boxa, or NULL on error
1265 */
1266 BOXA *
pixacompGetBoxa(PIXAC * pixac,l_int32 accesstype)1267 pixacompGetBoxa(PIXAC *pixac,
1268 l_int32 accesstype)
1269 {
1270 PROCNAME("pixacompGetBoxa");
1271
1272 if (!pixac)
1273 return (BOXA *)ERROR_PTR("pixac not defined", procName, NULL);
1274 if (!pixac->boxa)
1275 return (BOXA *)ERROR_PTR("boxa not defined", procName, NULL);
1276 if (accesstype != L_COPY && accesstype != L_CLONE &&
1277 accesstype != L_COPY_CLONE)
1278 return (BOXA *)ERROR_PTR("invalid accesstype", procName, NULL);
1279
1280 return boxaCopy(pixac->boxa, accesstype);
1281 }
1282
1283
1284 /*!
1285 * \brief pixacompGetBoxaCount()
1286 *
1287 * \param[in] pixac
1288 * \return count, or 0 on error
1289 */
1290 l_int32
pixacompGetBoxaCount(PIXAC * pixac)1291 pixacompGetBoxaCount(PIXAC *pixac)
1292 {
1293 PROCNAME("pixacompGetBoxaCount");
1294
1295 if (!pixac)
1296 return ERROR_INT("pixac not defined", procName, 0);
1297
1298 return boxaGetCount(pixac->boxa);
1299 }
1300
1301
1302 /*!
1303 * \brief pixacompGetBox()
1304 *
1305 * \param[in] pixac
1306 * \param[in] index caller's view of index within pixac; includes offset
1307 * \param[in] accesstype L_COPY or L_CLONE
1308 * \return box if null, not automatically an error, or NULL on error
1309 *
1310 * <pre>
1311 * Notes:
1312 * (1) The %index includes the offset, which must be subtracted
1313 * to get the actual index into the ptr array.
1314 * (2) There is always a boxa with a pixac, and it is initialized so
1315 * that each box ptr is NULL.
1316 * (3) In general, we expect that there is either a box associated
1317 * with each pixc, or no boxes at all in the boxa.
1318 * (4) Having no boxes is thus not an automatic error. Whether it
1319 * is an actual error is determined by the calling program.
1320 * If the caller expects to get a box, it is an error; see, e.g.,
1321 * pixacGetBoxGeometry().
1322 * </pre>
1323 */
1324 BOX *
pixacompGetBox(PIXAC * pixac,l_int32 index,l_int32 accesstype)1325 pixacompGetBox(PIXAC *pixac,
1326 l_int32 index,
1327 l_int32 accesstype)
1328 {
1329 l_int32 aindex;
1330 BOX *box;
1331
1332 PROCNAME("pixacompGetBox");
1333
1334 if (!pixac)
1335 return (BOX *)ERROR_PTR("pixac not defined", procName, NULL);
1336 if (!pixac->boxa)
1337 return (BOX *)ERROR_PTR("boxa not defined", procName, NULL);
1338 aindex = index - pixac->offset;
1339 if (aindex < 0 || aindex >= pixac->boxa->n)
1340 return (BOX *)ERROR_PTR("array index not valid", procName, NULL);
1341 if (accesstype != L_COPY && accesstype != L_CLONE)
1342 return (BOX *)ERROR_PTR("invalid accesstype", procName, NULL);
1343
1344 box = pixac->boxa->box[aindex];
1345 if (box) {
1346 if (accesstype == L_COPY)
1347 return boxCopy(box);
1348 else /* accesstype == L_CLONE */
1349 return boxClone(box);
1350 } else {
1351 return NULL;
1352 }
1353 }
1354
1355
1356 /*!
1357 * \brief pixacompGetBoxGeometry()
1358 *
1359 * \param[in] pixac
1360 * \param[in] index caller's view of index within pixac; includes offset
1361 * \param[out] px, py, pw, ph [optional] each can be null
1362 * \return 0 if OK, 1 on error
1363 *
1364 * <pre>
1365 * Notes:
1366 * (1) The %index includes the offset, which must be subtracted
1367 * to get the actual index into the ptr array.
1368 * </pre>
1369 */
1370 l_int32
pixacompGetBoxGeometry(PIXAC * pixac,l_int32 index,l_int32 * px,l_int32 * py,l_int32 * pw,l_int32 * ph)1371 pixacompGetBoxGeometry(PIXAC *pixac,
1372 l_int32 index,
1373 l_int32 *px,
1374 l_int32 *py,
1375 l_int32 *pw,
1376 l_int32 *ph)
1377 {
1378 l_int32 aindex;
1379 BOX *box;
1380
1381 PROCNAME("pixacompGetBoxGeometry");
1382
1383 if (!pixac)
1384 return ERROR_INT("pixac not defined", procName, 1);
1385 aindex = index - pixac->offset;
1386 if (aindex < 0 || aindex >= pixac->n)
1387 return ERROR_INT("array index not valid", procName, 1);
1388
1389 if ((box = pixacompGetBox(pixac, aindex, L_CLONE)) == NULL)
1390 return ERROR_INT("box not found!", procName, 1);
1391 boxGetGeometry(box, px, py, pw, ph);
1392 boxDestroy(&box);
1393 return 0;
1394 }
1395
1396
1397 /*!
1398 * \brief pixacompGetOffset()
1399 *
1400 * \param[in] pixac
1401 * \return offset, or 0 on error
1402 *
1403 * <pre>
1404 * Notes:
1405 * (1) The offset is the difference between the caller's view of
1406 * the index into the array and the actual array index.
1407 * By default it is 0.
1408 * </pre>
1409 */
1410 l_int32
pixacompGetOffset(PIXAC * pixac)1411 pixacompGetOffset(PIXAC *pixac)
1412 {
1413 PROCNAME("pixacompGetOffset");
1414
1415 if (!pixac)
1416 return ERROR_INT("pixac not defined", procName, 0);
1417 return pixac->offset;
1418 }
1419
1420
1421 /*!
1422 * \brief pixacompSetOffset()
1423 *
1424 * \param[in] pixac
1425 * \param[in] offset non-negative
1426 * \return 0 if OK, 1 on error
1427 *
1428 * <pre>
1429 * Notes:
1430 * (1) The offset is the difference between the caller's view of
1431 * the index into the array and the actual array index.
1432 * By default it is 0.
1433 * </pre>
1434 */
1435 l_int32
pixacompSetOffset(PIXAC * pixac,l_int32 offset)1436 pixacompSetOffset(PIXAC *pixac,
1437 l_int32 offset)
1438 {
1439 PROCNAME("pixacompSetOffset");
1440
1441 if (!pixac)
1442 return ERROR_INT("pixac not defined", procName, 1);
1443 pixac->offset = L_MAX(0, offset);
1444 return 0;
1445 }
1446
1447
1448 /*---------------------------------------------------------------------*
1449 * Pixacomp conversion to Pixa *
1450 *---------------------------------------------------------------------*/
1451 /*!
1452 * \brief pixaCreateFromPixacomp()
1453 *
1454 * \param[in] pixac
1455 * \param[in] accesstype L_COPY, L_CLONE, L_COPY_CLONE; for boxa
1456 * \return pixa if OK, or NULL on error
1457 *
1458 * <pre>
1459 * Notes:
1460 * (1) Because the pixa has no notion of offset, the offset must
1461 * be set to 0 before the conversion, so that pixacompGetPix()
1462 * fetches all the pixcomps. It is reset at the end.
1463 * </pre>
1464 */
1465 PIXA *
pixaCreateFromPixacomp(PIXAC * pixac,l_int32 accesstype)1466 pixaCreateFromPixacomp(PIXAC *pixac,
1467 l_int32 accesstype)
1468 {
1469 l_int32 i, n, offset;
1470 PIX *pix;
1471 PIXA *pixa;
1472
1473 PROCNAME("pixaCreateFromPixacomp");
1474
1475 if (!pixac)
1476 return (PIXA *)ERROR_PTR("pixac not defined", procName, NULL);
1477 if (accesstype != L_COPY && accesstype != L_CLONE &&
1478 accesstype != L_COPY_CLONE)
1479 return (PIXA *)ERROR_PTR("invalid accesstype", procName, NULL);
1480
1481 n = pixacompGetCount(pixac);
1482 offset = pixacompGetOffset(pixac);
1483 pixacompSetOffset(pixac, 0);
1484 if ((pixa = pixaCreate(n)) == NULL)
1485 return (PIXA *)ERROR_PTR("pixa not made", procName, NULL);
1486 for (i = 0; i < n; i++) {
1487 if ((pix = pixacompGetPix(pixac, i)) == NULL) {
1488 L_WARNING("pix %d not made\n", procName, i);
1489 continue;
1490 }
1491 pixaAddPix(pixa, pix, L_INSERT);
1492 }
1493 if (pixa->boxa) {
1494 boxaDestroy(&pixa->boxa);
1495 pixa->boxa = pixacompGetBoxa(pixac, accesstype);
1496 }
1497 pixacompSetOffset(pixac, offset);
1498
1499 return pixa;
1500 }
1501
1502
1503 /*---------------------------------------------------------------------*
1504 * Combining pixacomp
1505 *---------------------------------------------------------------------*/
1506 /*!
1507 * \brief pixacompJoin()
1508 *
1509 * \param[in] pixacd dest pixac; add to this one
1510 * \param[in] pixacs [optional] source pixac; add from this one
1511 * \param[in] istart starting index in pixacs
1512 * \param[in] iend ending index in pixacs; use -1 to cat all
1513 * \return 0 if OK, 1 on error
1514 *
1515 * <pre>
1516 * Notes:
1517 * (1) This appends a clone of each indicated pixc in pixcas to pixcad
1518 * (2) istart < 0 is taken to mean 'read from the start' (istart = 0)
1519 * (3) iend < 0 means 'read to the end'
1520 * (4) If pixacs is NULL or contains no pixc, this is a no-op.
1521 * </pre>
1522 */
1523 l_int32
pixacompJoin(PIXAC * pixacd,PIXAC * pixacs,l_int32 istart,l_int32 iend)1524 pixacompJoin(PIXAC *pixacd,
1525 PIXAC *pixacs,
1526 l_int32 istart,
1527 l_int32 iend)
1528 {
1529 l_int32 i, n, nb;
1530 BOXA *boxas, *boxad;
1531 PIXC *pixc;
1532
1533 PROCNAME("pixacompJoin");
1534
1535 if (!pixacd)
1536 return ERROR_INT("pixacd not defined", procName, 1);
1537 if (!pixacs || ((n = pixacompGetCount(pixacs)) == 0))
1538 return 0;
1539
1540 if (istart < 0)
1541 istart = 0;
1542 if (iend < 0 || iend >= n)
1543 iend = n - 1;
1544 if (istart > iend)
1545 return ERROR_INT("istart > iend; nothing to add", procName, 1);
1546
1547 for (i = istart; i <= iend; i++) {
1548 pixc = pixacompGetPixcomp(pixacs, i, L_NOCOPY);
1549 pixacompAddPixcomp(pixacd, pixc, L_COPY);
1550 }
1551
1552 boxas = pixacompGetBoxa(pixacs, L_CLONE);
1553 boxad = pixacompGetBoxa(pixacd, L_CLONE);
1554 nb = pixacompGetBoxaCount(pixacs);
1555 iend = L_MIN(iend, nb - 1);
1556 boxaJoin(boxad, boxas, istart, iend);
1557 boxaDestroy(&boxas); /* just the clones */
1558 boxaDestroy(&boxad); /* ditto */
1559 return 0;
1560 }
1561
1562
1563 /*!
1564 * \brief pixacompInterleave()
1565 *
1566 * \param[in] pixac1 first src pixac
1567 * \param[in] pixac2 second src pixac
1568 * \return pixacd interleaved from sources, or NULL on error.
1569 *
1570 * <pre>
1571 * Notes:
1572 * (1) If the two pixac have different sizes, a warning is issued,
1573 * and the number of pairs returned is the minimum size.
1574 * </pre>
1575 */
1576 PIXAC *
pixacompInterleave(PIXAC * pixac1,PIXAC * pixac2)1577 pixacompInterleave(PIXAC *pixac1,
1578 PIXAC *pixac2)
1579 {
1580 l_int32 i, n1, n2, n, nb1, nb2;
1581 BOX *box;
1582 PIXC *pixc1, *pixc2;
1583 PIXAC *pixacd;
1584
1585 PROCNAME("pixacompInterleave");
1586
1587 if (!pixac1)
1588 return (PIXAC *)ERROR_PTR("pixac1 not defined", procName, NULL);
1589 if (!pixac2)
1590 return (PIXAC *)ERROR_PTR("pixac2 not defined", procName, NULL);
1591 n1 = pixacompGetCount(pixac1);
1592 n2 = pixacompGetCount(pixac2);
1593 n = L_MIN(n1, n2);
1594 if (n == 0)
1595 return (PIXAC *)ERROR_PTR("at least one input pixac is empty",
1596 procName, NULL);
1597 if (n1 != n2)
1598 L_WARNING("counts differ: %d != %d\n", procName, n1, n2);
1599
1600 pixacd = pixacompCreate(2 * n);
1601 nb1 = pixacompGetBoxaCount(pixac1);
1602 nb2 = pixacompGetBoxaCount(pixac2);
1603 for (i = 0; i < n; i++) {
1604 pixc1 = pixacompGetPixcomp(pixac1, i, L_COPY);
1605 pixacompAddPixcomp(pixacd, pixc1, L_INSERT);
1606 if (i < nb1) {
1607 box = pixacompGetBox(pixac1, i, L_COPY);
1608 pixacompAddBox(pixacd, box, L_INSERT);
1609 }
1610 pixc2 = pixacompGetPixcomp(pixac2, i, L_COPY);
1611 pixacompAddPixcomp(pixacd, pixc2, L_INSERT);
1612 if (i < nb2) {
1613 box = pixacompGetBox(pixac2, i, L_COPY);
1614 pixacompAddBox(pixacd, box, L_INSERT);
1615 }
1616 }
1617
1618 return pixacd;
1619 }
1620
1621
1622 /*---------------------------------------------------------------------*
1623 * Pixacomp serialized I/O *
1624 *---------------------------------------------------------------------*/
1625 /*!
1626 * \brief pixacompRead()
1627 *
1628 * \param[in] filename
1629 * \return pixac, or NULL on error
1630 *
1631 * <pre>
1632 * Notes:
1633 * (1) Unlike the situation with serialized Pixa, where the image
1634 * data is stored in png format, the Pixacomp image data
1635 * can be stored in tiffg4, png and jpg formats.
1636 * </pre>
1637 */
1638 PIXAC *
pixacompRead(const char * filename)1639 pixacompRead(const char *filename)
1640 {
1641 FILE *fp;
1642 PIXAC *pixac;
1643
1644 PROCNAME("pixacompRead");
1645
1646 if (!filename)
1647 return (PIXAC *)ERROR_PTR("filename not defined", procName, NULL);
1648
1649 if ((fp = fopenReadStream(filename)) == NULL)
1650 return (PIXAC *)ERROR_PTR("stream not opened", procName, NULL);
1651 pixac = pixacompReadStream(fp);
1652 fclose(fp);
1653 if (!pixac)
1654 return (PIXAC *)ERROR_PTR("pixac not read", procName, NULL);
1655 return pixac;
1656 }
1657
1658
1659 /*!
1660 * \brief pixacompReadStream()
1661 *
1662 * \param[in] fp file stream
1663 * \return pixac, or NULL on error
1664 */
1665 PIXAC *
pixacompReadStream(FILE * fp)1666 pixacompReadStream(FILE *fp)
1667 {
1668 char buf[256];
1669 l_uint8 *data;
1670 l_int32 n, offset, i, w, h, d, ignore;
1671 l_int32 comptype, size, cmapflag, version, xres, yres;
1672 BOXA *boxa;
1673 PIXC *pixc;
1674 PIXAC *pixac;
1675
1676 PROCNAME("pixacompReadStream");
1677
1678 if (!fp)
1679 return (PIXAC *)ERROR_PTR("stream not defined", procName, NULL);
1680
1681 if (fscanf(fp, "\nPixacomp Version %d\n", &version) != 1)
1682 return (PIXAC *)ERROR_PTR("not a pixacomp file", procName, NULL);
1683 if (version != PIXACOMP_VERSION_NUMBER)
1684 return (PIXAC *)ERROR_PTR("invalid pixacomp version", procName, NULL);
1685 if (fscanf(fp, "Number of pixcomp = %d\n", &n) != 1)
1686 return (PIXAC *)ERROR_PTR("not a pixacomp file", procName, NULL);
1687 if (fscanf(fp, "Offset of index into array = %d", &offset) != 1)
1688 return (PIXAC *)ERROR_PTR("offset not read", procName, NULL);
1689
1690 if ((pixac = pixacompCreate(n)) == NULL)
1691 return (PIXAC *)ERROR_PTR("pixac not made", procName, NULL);
1692 if ((boxa = boxaReadStream(fp)) == NULL) {
1693 pixacompDestroy(&pixac);
1694 return (PIXAC *)ERROR_PTR("boxa not made", procName, NULL);
1695 }
1696 boxaDestroy(&pixac->boxa); /* empty */
1697 pixac->boxa = boxa;
1698 pixacompSetOffset(pixac, offset);
1699
1700 for (i = 0; i < n; i++) {
1701 if (fscanf(fp, "\nPixcomp[%d]: w = %d, h = %d, d = %d\n",
1702 &ignore, &w, &h, &d) != 4) {
1703 pixacompDestroy(&pixac);
1704 return (PIXAC *)ERROR_PTR("size reading", procName, NULL);
1705 }
1706 if (fscanf(fp, " comptype = %d, size = %d, cmapflag = %d\n",
1707 &comptype, &size, &cmapflag) != 3) {
1708 pixacompDestroy(&pixac);
1709 return (PIXAC *)ERROR_PTR("comptype/size reading", procName, NULL);
1710 }
1711
1712 /* Use fgets() and sscanf(); not fscanf(), for the last
1713 * bit of header data before the binary data. The reason is
1714 * that fscanf throws away white space, and if the binary data
1715 * happens to begin with ascii character(s) that are white
1716 * space, it will swallow them and all will be lost! */
1717 if (fgets(buf, sizeof(buf), fp) == NULL) {
1718 pixacompDestroy(&pixac);
1719 return (PIXAC *)ERROR_PTR("fgets read fail", procName, NULL);
1720 }
1721 if (sscanf(buf, " xres = %d, yres = %d\n", &xres, &yres) != 2) {
1722 pixacompDestroy(&pixac);
1723 return (PIXAC *)ERROR_PTR("read fail for res", procName, NULL);
1724 }
1725 if ((data = (l_uint8 *)LEPT_CALLOC(1, size)) == NULL) {
1726 pixacompDestroy(&pixac);
1727 return (PIXAC *)ERROR_PTR("calloc fail for data", procName, NULL);
1728 }
1729 if (fread(data, 1, size, fp) != size) {
1730 pixacompDestroy(&pixac);
1731 LEPT_FREE(data);
1732 return (PIXAC *)ERROR_PTR("error reading data", procName, NULL);
1733 }
1734 fgetc(fp); /* swallow the ending nl */
1735 pixc = (PIXC *)LEPT_CALLOC(1, sizeof(PIXC));
1736 pixc->w = w;
1737 pixc->h = h;
1738 pixc->d = d;
1739 pixc->xres = xres;
1740 pixc->yres = yres;
1741 pixc->comptype = comptype;
1742 pixc->cmapflag = cmapflag;
1743 pixc->data = data;
1744 pixc->size = size;
1745 pixacompAddPixcomp(pixac, pixc, L_INSERT);
1746 }
1747 return pixac;
1748 }
1749
1750
1751 /*!
1752 * \brief pixacompReadMem()
1753 *
1754 * \param[in] data const; pixacomp format
1755 * \param[in] size of data
1756 * \return pixac, or NULL on error
1757 *
1758 * <pre>
1759 * Notes:
1760 * (1) Deseralizes a buffer of pixacomp data into a pixac in memory.
1761 * </pre>
1762 */
1763 PIXAC *
pixacompReadMem(const l_uint8 * data,size_t size)1764 pixacompReadMem(const l_uint8 *data,
1765 size_t size)
1766 {
1767 FILE *fp;
1768 PIXAC *pixac;
1769
1770 PROCNAME("pixacompReadMem");
1771
1772 if (!data)
1773 return (PIXAC *)ERROR_PTR("data not defined", procName, NULL);
1774 if ((fp = fopenReadFromMemory(data, size)) == NULL)
1775 return (PIXAC *)ERROR_PTR("stream not opened", procName, NULL);
1776
1777 pixac = pixacompReadStream(fp);
1778 fclose(fp);
1779 if (!pixac) L_ERROR("pixac not read\n", procName);
1780 return pixac;
1781 }
1782
1783
1784 /*!
1785 * \brief pixacompWrite()
1786 *
1787 * \param[in] filename
1788 * \param[in] pixac
1789 * \return 0 if OK, 1 on error
1790 *
1791 * <pre>
1792 * Notes:
1793 * (1) Unlike the situation with serialized Pixa, where the image
1794 * data is stored in png format, the Pixacomp image data
1795 * can be stored in tiffg4, png and jpg formats.
1796 * </pre>
1797 */
1798 l_int32
pixacompWrite(const char * filename,PIXAC * pixac)1799 pixacompWrite(const char *filename,
1800 PIXAC *pixac)
1801 {
1802 l_int32 ret;
1803 FILE *fp;
1804
1805 PROCNAME("pixacompWrite");
1806
1807 if (!filename)
1808 return ERROR_INT("filename not defined", procName, 1);
1809 if (!pixac)
1810 return ERROR_INT("pixacomp not defined", procName, 1);
1811
1812 if ((fp = fopenWriteStream(filename, "wb")) == NULL)
1813 return ERROR_INT("stream not opened", procName, 1);
1814 ret = pixacompWriteStream(fp, pixac);
1815 fclose(fp);
1816 if (ret)
1817 return ERROR_INT("pixacomp not written to stream", procName, 1);
1818 return 0;
1819 }
1820
1821
1822 /*!
1823 * \brief pixacompWriteStream()
1824 *
1825 * \param[in] fp file stream
1826 * \param[in] pixac
1827 * \return 0 if OK, 1 on error
1828 */
1829 l_int32
pixacompWriteStream(FILE * fp,PIXAC * pixac)1830 pixacompWriteStream(FILE *fp,
1831 PIXAC *pixac)
1832 {
1833 l_int32 n, i;
1834 PIXC *pixc;
1835
1836 PROCNAME("pixacompWriteStream");
1837
1838 if (!fp)
1839 return ERROR_INT("stream not defined", procName, 1);
1840 if (!pixac)
1841 return ERROR_INT("pixac not defined", procName, 1);
1842
1843 n = pixacompGetCount(pixac);
1844 fprintf(fp, "\nPixacomp Version %d\n", PIXACOMP_VERSION_NUMBER);
1845 fprintf(fp, "Number of pixcomp = %d\n", n);
1846 fprintf(fp, "Offset of index into array = %d", pixac->offset);
1847 boxaWriteStream(fp, pixac->boxa);
1848 for (i = 0; i < n; i++) {
1849 if ((pixc = pixacompGetPixcomp(pixac, pixac->offset + i, L_NOCOPY))
1850 == NULL)
1851 return ERROR_INT("pixc not found", procName, 1);
1852 fprintf(fp, "\nPixcomp[%d]: w = %d, h = %d, d = %d\n",
1853 i, pixc->w, pixc->h, pixc->d);
1854 fprintf(fp, " comptype = %d, size = %lu, cmapflag = %d\n",
1855 pixc->comptype, (unsigned long)pixc->size, pixc->cmapflag);
1856 fprintf(fp, " xres = %d, yres = %d\n", pixc->xres, pixc->yres);
1857 fwrite(pixc->data, 1, pixc->size, fp);
1858 fprintf(fp, "\n");
1859 }
1860 return 0;
1861 }
1862
1863
1864 /*!
1865 * \brief pixacompWriteMem()
1866 *
1867 * \param[out] pdata serialized data of pixac
1868 * \param[out] psize size of serialized data
1869 * \param[in] pixac
1870 * \return 0 if OK, 1 on error
1871 *
1872 * <pre>
1873 * Notes:
1874 * (1) Serializes a pixac in memory and puts the result in a buffer.
1875 * </pre>
1876 */
1877 l_int32
pixacompWriteMem(l_uint8 ** pdata,size_t * psize,PIXAC * pixac)1878 pixacompWriteMem(l_uint8 **pdata,
1879 size_t *psize,
1880 PIXAC *pixac)
1881 {
1882 l_int32 ret;
1883 FILE *fp;
1884
1885 PROCNAME("pixacompWriteMem");
1886
1887 if (pdata) *pdata = NULL;
1888 if (psize) *psize = 0;
1889 if (!pdata)
1890 return ERROR_INT("&data not defined", procName, 1);
1891 if (!psize)
1892 return ERROR_INT("&size not defined", procName, 1);
1893 if (!pixac)
1894 return ERROR_INT("&pixac not defined", procName, 1);
1895
1896 #if HAVE_FMEMOPEN
1897 if ((fp = open_memstream((char **)pdata, psize)) == NULL)
1898 return ERROR_INT("stream not opened", procName, 1);
1899 ret = pixacompWriteStream(fp, pixac);
1900 #else
1901 L_INFO("work-around: writing to a temp file\n", procName);
1902 #ifdef _WIN32
1903 if ((fp = fopenWriteWinTempfile()) == NULL)
1904 return ERROR_INT("tmpfile stream not opened", procName, 1);
1905 #else
1906 if ((fp = tmpfile()) == NULL)
1907 return ERROR_INT("tmpfile stream not opened", procName, 1);
1908 #endif /* _WIN32 */
1909 ret = pixacompWriteStream(fp, pixac);
1910 rewind(fp);
1911 *pdata = l_binaryReadStream(fp, psize);
1912 #endif /* HAVE_FMEMOPEN */
1913 fclose(fp);
1914 return ret;
1915 }
1916
1917
1918 /*--------------------------------------------------------------------*
1919 * Conversion to pdf *
1920 *--------------------------------------------------------------------*/
1921 /*!
1922 * \brief pixacompConvertToPdf()
1923 *
1924 * \param[in] pixac containing images all at the same resolution
1925 * \param[in] res override the resolution of each input image, in ppi;
1926 * use 0 to respect the resolution embedded in the input
1927 * \param[in] scalefactor scaling factor applied to each image; > 0.0
1928 * \param[in] type encoding type (L_JPEG_ENCODE, L_G4_ENCODE,
1929 * L_FLATE_ENCODE, or L_DEFAULT_ENCODE for default
1930 * \param[in] quality used for JPEG only; 0 for default (75)
1931 * \param[in] title [optional] pdf title
1932 * \param[in] fileout pdf file of all images
1933 * \return 0 if OK, 1 on error
1934 *
1935 * <pre>
1936 * Notes:
1937 * (1) This follows closely the function pixaConvertToPdf() in pdfio.c.
1938 * (2) The images are encoded with G4 if 1 bpp; JPEG if 8 bpp without
1939 * colormap and many colors, or 32 bpp; FLATE for anything else.
1940 * (3) The scalefactor must be > 0.0; otherwise it is set to 1.0.
1941 * (4) Specifying one of the three encoding types for %type forces
1942 * all images to be compressed with that type. Use 0 to have
1943 * the type determined for each image based on depth and whether
1944 * or not it has a colormap.
1945 * (5) If all images are jpeg compressed, don't require scaling
1946 * and have the same resolution, it is much faster to skip
1947 * transcoding with pixacompFastConvertToPdfData(), and then
1948 * write the data out to file.
1949 * </pre>
1950 */
1951 l_int32
pixacompConvertToPdf(PIXAC * pixac,l_int32 res,l_float32 scalefactor,l_int32 type,l_int32 quality,const char * title,const char * fileout)1952 pixacompConvertToPdf(PIXAC *pixac,
1953 l_int32 res,
1954 l_float32 scalefactor,
1955 l_int32 type,
1956 l_int32 quality,
1957 const char *title,
1958 const char *fileout)
1959 {
1960 l_uint8 *data;
1961 l_int32 ret;
1962 size_t nbytes;
1963
1964 PROCNAME("pixacompConvertToPdf");
1965
1966 if (!pixac)
1967 return ERROR_INT("pixac not defined", procName, 1);
1968
1969 ret = pixacompConvertToPdfData(pixac, res, scalefactor, type, quality,
1970 title, &data, &nbytes);
1971 if (ret) {
1972 LEPT_FREE(data);
1973 return ERROR_INT("conversion to pdf failed", procName, 1);
1974 }
1975
1976 ret = l_binaryWrite(fileout, "w", data, nbytes);
1977 LEPT_FREE(data);
1978 if (ret)
1979 L_ERROR("pdf data not written to file\n", procName);
1980 return ret;
1981 }
1982
1983
1984 /*!
1985 * \brief pixacompConvertToPdfData()
1986 *
1987 * \param[in] pixac containing images all at the same resolution
1988 * \param[in] res input resolution of all images
1989 * \param[in] scalefactor scaling factor applied to each image; > 0.0
1990 * \param[in] type encoding type (L_JPEG_ENCODE, L_G4_ENCODE,
1991 * L_FLATE_ENCODE, or L_DEFAULT_ENCODE for default
1992 * \param[in] quality used for JPEG only; 0 for default (75)
1993 * \param[in] title [optional] pdf title
1994 * \param[out] pdata output pdf data (of all images
1995 * \param[out] pnbytes size of output pdf data
1996 * \return 0 if OK, 1 on error
1997 *
1998 * <pre>
1999 * Notes:
2000 * (1) See pixacompConvertToPdf().
2001 * </pre>
2002 */
2003 l_int32
pixacompConvertToPdfData(PIXAC * pixac,l_int32 res,l_float32 scalefactor,l_int32 type,l_int32 quality,const char * title,l_uint8 ** pdata,size_t * pnbytes)2004 pixacompConvertToPdfData(PIXAC *pixac,
2005 l_int32 res,
2006 l_float32 scalefactor,
2007 l_int32 type,
2008 l_int32 quality,
2009 const char *title,
2010 l_uint8 **pdata,
2011 size_t *pnbytes)
2012 {
2013 l_uint8 *imdata;
2014 l_int32 i, n, ret, scaledres, pagetype;
2015 size_t imbytes;
2016 L_BYTEA *ba;
2017 PIX *pixs, *pix;
2018 L_PTRA *pa_data;
2019
2020 PROCNAME("pixacompConvertToPdfData");
2021
2022 if (!pdata)
2023 return ERROR_INT("&data not defined", procName, 1);
2024 *pdata = NULL;
2025 if (!pnbytes)
2026 return ERROR_INT("&nbytes not defined", procName, 1);
2027 *pnbytes = 0;
2028 if (!pixac)
2029 return ERROR_INT("pixac not defined", procName, 1);
2030 if (scalefactor <= 0.0) scalefactor = 1.0;
2031 if (type < L_DEFAULT_ENCODE || type > L_FLATE_ENCODE) {
2032 L_WARNING("invalid compression type; using per-page default\n",
2033 procName);
2034 type = L_DEFAULT_ENCODE;
2035 }
2036
2037 /* Generate all the encoded pdf strings */
2038 n = pixacompGetCount(pixac);
2039 pa_data = ptraCreate(n);
2040 for (i = 0; i < n; i++) {
2041 if ((pixs =
2042 pixacompGetPix(pixac, pixacompGetOffset(pixac) + i)) == NULL) {
2043 L_ERROR("pix[%d] not retrieved\n", procName, i);
2044 continue;
2045 }
2046 if (pixGetWidth(pixs) == 1) { /* used sometimes as placeholders */
2047 L_INFO("placeholder image[%d] has w = 1\n", procName, i);
2048 pixDestroy(&pixs);
2049 continue;
2050 }
2051 if (scalefactor != 1.0)
2052 pix = pixScale(pixs, scalefactor, scalefactor);
2053 else
2054 pix = pixClone(pixs);
2055 pixDestroy(&pixs);
2056 scaledres = (l_int32)(res * scalefactor);
2057 if (type != L_DEFAULT_ENCODE) {
2058 pagetype = type;
2059 } else if (selectDefaultPdfEncoding(pix, &pagetype) != 0) {
2060 L_ERROR("encoding type selection failed for pix[%d]\n",
2061 procName, i);
2062 pixDestroy(&pix);
2063 continue;
2064 }
2065 ret = pixConvertToPdfData(pix, pagetype, quality, &imdata, &imbytes,
2066 0, 0, scaledres, title, NULL, 0);
2067 pixDestroy(&pix);
2068 if (ret) {
2069 L_ERROR("pdf encoding failed for pix[%d]\n", procName, i);
2070 continue;
2071 }
2072 ba = l_byteaInitFromMem(imdata, imbytes);
2073 LEPT_FREE(imdata);
2074 ptraAdd(pa_data, ba);
2075 }
2076 ptraGetActualCount(pa_data, &n);
2077 if (n == 0) {
2078 L_ERROR("no pdf files made\n", procName);
2079 ptraDestroy(&pa_data, FALSE, FALSE);
2080 return 1;
2081 }
2082
2083 /* Concatenate them */
2084 ret = ptraConcatenatePdfToData(pa_data, NULL, pdata, pnbytes);
2085
2086 ptraGetActualCount(pa_data, &n); /* recalculate in case it changes */
2087 for (i = 0; i < n; i++) {
2088 ba = (L_BYTEA *)ptraRemove(pa_data, i, L_NO_COMPACTION);
2089 l_byteaDestroy(&ba);
2090 }
2091 ptraDestroy(&pa_data, FALSE, FALSE);
2092 return ret;
2093 }
2094
2095
2096 /*!
2097 * \brief pixacompFastConvertToPdfData()
2098 *
2099 * \param[in] pixac containing images all at the same resolution
2100 * \param[in] res input resolution of all images
2101 * \param[in] title [optional] pdf title
2102 * \param[out] pdata output pdf data (of all images
2103 * \param[out] pnbytes size of output pdf data
2104 * \return 0 if OK, 1 on error
2105 *
2106 * <pre>
2107 * Notes:
2108 * (1) This generates the pdf without transcoding if all the
2109 * images in %pixac are compressed with jpeg.
2110 * Images not jpeg compressed are skipped.
2111 * (2) It assumes all images have the same resolution, and that
2112 * the resolution embedded in each jpeg file is correct.
2113 * </pre>
2114 */
2115 l_int32
pixacompFastConvertToPdfData(PIXAC * pixac,const char * title,l_uint8 ** pdata,size_t * pnbytes)2116 pixacompFastConvertToPdfData(PIXAC *pixac,
2117 const char *title,
2118 l_uint8 **pdata,
2119 size_t *pnbytes)
2120 {
2121 l_uint8 *imdata;
2122 l_int32 i, n, ret, comptype;
2123 size_t imbytes;
2124 L_BYTEA *ba;
2125 PIXC *pixc;
2126 L_PTRA *pa_data;
2127
2128 PROCNAME("pixacompFastConvertToPdfData");
2129
2130 if (!pdata)
2131 return ERROR_INT("&data not defined", procName, 1);
2132 *pdata = NULL;
2133 if (!pnbytes)
2134 return ERROR_INT("&nbytes not defined", procName, 1);
2135 *pnbytes = 0;
2136 if (!pixac)
2137 return ERROR_INT("pixac not defined", procName, 1);
2138
2139 /* Generate all the encoded pdf strings */
2140 n = pixacompGetCount(pixac);
2141 pa_data = ptraCreate(n);
2142 for (i = 0; i < n; i++) {
2143 if ((pixc = pixacompGetPixcomp(pixac, i, L_NOCOPY)) == NULL) {
2144 L_ERROR("pixc[%d] not retrieved\n", procName, i);
2145 continue;
2146 }
2147 pixcompGetParameters(pixc, NULL, NULL, &comptype, NULL);
2148 if (comptype != IFF_JFIF_JPEG) {
2149 L_ERROR("pixc[%d] not jpeg compressed\n", procName, i);
2150 continue;
2151 }
2152 ret = pixcompFastConvertToPdfData(pixc, title, &imdata, &imbytes);
2153 if (ret) {
2154 L_ERROR("pdf encoding failed for pixc[%d]\n", procName, i);
2155 continue;
2156 }
2157 ba = l_byteaInitFromMem(imdata, imbytes);
2158 LEPT_FREE(imdata);
2159 ptraAdd(pa_data, ba);
2160 }
2161 ptraGetActualCount(pa_data, &n);
2162 if (n == 0) {
2163 L_ERROR("no pdf files made\n", procName);
2164 ptraDestroy(&pa_data, FALSE, FALSE);
2165 return 1;
2166 }
2167
2168 /* Concatenate them */
2169 ret = ptraConcatenatePdfToData(pa_data, NULL, pdata, pnbytes);
2170
2171 /* Clean up */
2172 ptraGetActualCount(pa_data, &n); /* recalculate in case it changes */
2173 for (i = 0; i < n; i++) {
2174 ba = (L_BYTEA *)ptraRemove(pa_data, i, L_NO_COMPACTION);
2175 l_byteaDestroy(&ba);
2176 }
2177 ptraDestroy(&pa_data, FALSE, FALSE);
2178 return ret;
2179 }
2180
2181
2182 /*!
2183 * \brief pixcompFastConvertToPdfData()
2184 *
2185 * \param[in] pixc containing images all at the same resolution
2186 * \param[in] title [optional] pdf title
2187 * \param[out] pdata output pdf data (of all images
2188 * \param[out] pnbytes size of output pdf data
2189 * \return 0 if OK, 1 on error
2190 *
2191 * <pre>
2192 * Notes:
2193 * (1) This generates the pdf without transcoding.
2194 * (2) It assumes all images are jpeg encoded, have the same
2195 * resolution, and that the resolution embedded in each
2196 * jpeg file is correct. (It is transferred to the pdf
2197 * via the cid.)
2198 * </pre>
2199 */
2200 static l_int32
pixcompFastConvertToPdfData(PIXC * pixc,const char * title,l_uint8 ** pdata,size_t * pnbytes)2201 pixcompFastConvertToPdfData(PIXC *pixc,
2202 const char *title,
2203 l_uint8 **pdata,
2204 size_t *pnbytes)
2205 {
2206 l_uint8 *data;
2207 L_COMP_DATA *cid;
2208
2209 PROCNAME("pixacompFastConvertToPdfData");
2210
2211 if (!pdata)
2212 return ERROR_INT("&data not defined", procName, 1);
2213 *pdata = NULL;
2214 if (!pnbytes)
2215 return ERROR_INT("&nbytes not defined", procName, 1);
2216 *pnbytes = 0;
2217 if (!pixc)
2218 return ERROR_INT("pixc not defined", procName, 1);
2219
2220 /* Make a copy of the data */
2221 data = l_binaryCopy(pixc->data, pixc->size);
2222 cid = l_generateJpegDataMem(data, pixc->size, 0);
2223
2224 /* Note: cid is destroyed, along with data, by this function */
2225 return cidConvertToPdfData(cid, title, pdata, pnbytes);
2226 }
2227
2228
2229 /*--------------------------------------------------------------------*
2230 * Output for debugging *
2231 *--------------------------------------------------------------------*/
2232 /*!
2233 * \brief pixacompWriteStreamInfo()
2234 *
2235 * \param[in] fp file stream
2236 * \param[in] pixac
2237 * \param[in] text [optional] identifying string; can be null
2238 * \return 0 if OK, 1 on error
2239 */
2240 l_int32
pixacompWriteStreamInfo(FILE * fp,PIXAC * pixac,const char * text)2241 pixacompWriteStreamInfo(FILE *fp,
2242 PIXAC *pixac,
2243 const char *text)
2244 {
2245 l_int32 i, n, nboxes;
2246 PIXC *pixc;
2247
2248 PROCNAME("pixacompWriteStreamInfo");
2249
2250 if (!fp)
2251 return ERROR_INT("fp not defined", procName, 1);
2252 if (!pixac)
2253 return ERROR_INT("pixac not defined", procName, 1);
2254
2255 if (text)
2256 fprintf(fp, "Pixacomp Info for %s:\n", text);
2257 else
2258 fprintf(fp, "Pixacomp Info:\n");
2259 n = pixacompGetCount(pixac);
2260 nboxes = pixacompGetBoxaCount(pixac);
2261 fprintf(fp, "Number of pixcomp: %d\n", n);
2262 fprintf(fp, "Size of pixcomp array alloc: %d\n", pixac->nalloc);
2263 fprintf(fp, "Offset of index into array: %d\n", pixac->offset);
2264 if (nboxes > 0)
2265 fprintf(fp, "Boxa has %d boxes\n", nboxes);
2266 else
2267 fprintf(fp, "Boxa is empty\n");
2268 for (i = 0; i < n; i++) {
2269 pixc = pixacompGetPixcomp(pixac, pixac->offset + i, L_NOCOPY);
2270 pixcompWriteStreamInfo(fp, pixc, NULL);
2271 }
2272 return 0;
2273 }
2274
2275
2276 /*!
2277 * \brief pixcompWriteStreamInfo()
2278 *
2279 * \param[in] fp file stream
2280 * \param[in] pixc
2281 * \param[in] text [optional] identifying string; can be null
2282 * \return 0 if OK, 1 on error
2283 */
2284 l_int32
pixcompWriteStreamInfo(FILE * fp,PIXC * pixc,const char * text)2285 pixcompWriteStreamInfo(FILE *fp,
2286 PIXC *pixc,
2287 const char *text)
2288 {
2289 PROCNAME("pixcompWriteStreamInfo");
2290
2291 if (!fp)
2292 return ERROR_INT("fp not defined", procName, 1);
2293 if (!pixc)
2294 return ERROR_INT("pixc not defined", procName, 1);
2295
2296 if (text)
2297 fprintf(fp, " Pixcomp Info for %s:", text);
2298 else
2299 fprintf(fp, " Pixcomp Info:");
2300 fprintf(fp, " width = %d, height = %d, depth = %d\n",
2301 pixc->w, pixc->h, pixc->d);
2302 fprintf(fp, " xres = %d, yres = %d, size in bytes = %lu\n",
2303 pixc->xres, pixc->yres, (unsigned long)pixc->size);
2304 if (pixc->cmapflag)
2305 fprintf(fp, " has colormap\n");
2306 else
2307 fprintf(fp, " no colormap\n");
2308 if (pixc->comptype < NumImageFileFormatExtensions) {
2309 fprintf(fp, " comptype = %s (%d)\n",
2310 ImageFileFormatExtensions[pixc->comptype], pixc->comptype);
2311 } else {
2312 fprintf(fp, " Error!! Invalid comptype index: %d\n", pixc->comptype);
2313 }
2314 return 0;
2315 }
2316
2317
2318 /*!
2319 * \brief pixacompDisplayTiledAndScaled()
2320 *
2321 * \param[in] pixac
2322 * \param[in] outdepth output depth: 1, 8 or 32 bpp
2323 * \param[in] tilewidth each pix is scaled to this width
2324 * \param[in] ncols number of tiles in each row
2325 * \param[in] background 0 for white, 1 for black; this is the color
2326 * of the spacing between the images
2327 * \param[in] spacing between images, and on outside
2328 * \param[in] border width of additional black border on each image;
2329 * use 0 for no border
2330 * \return pix of tiled images, or NULL on error
2331 *
2332 * <pre>
2333 * Notes:
2334 * (1) This is the same function as pixaDisplayTiledAndScaled(),
2335 * except it works on a Pixacomp instead of a Pix. It is particularly
2336 * useful for showing the images in a Pixacomp at reduced resolution.
2337 * (2) See pixaDisplayTiledAndScaled() for details.
2338 * </pre>
2339 */
2340 PIX *
pixacompDisplayTiledAndScaled(PIXAC * pixac,l_int32 outdepth,l_int32 tilewidth,l_int32 ncols,l_int32 background,l_int32 spacing,l_int32 border)2341 pixacompDisplayTiledAndScaled(PIXAC *pixac,
2342 l_int32 outdepth,
2343 l_int32 tilewidth,
2344 l_int32 ncols,
2345 l_int32 background,
2346 l_int32 spacing,
2347 l_int32 border)
2348 {
2349 PIX *pixd;
2350 PIXA *pixa;
2351
2352 PROCNAME("pixacompDisplayTiledAndScaled");
2353
2354 if (!pixac)
2355 return (PIX *)ERROR_PTR("pixac not defined", procName, NULL);
2356
2357 if ((pixa = pixaCreateFromPixacomp(pixac, L_COPY)) == NULL)
2358 return (PIX *)ERROR_PTR("pixa not made", procName, NULL);
2359
2360 pixd = pixaDisplayTiledAndScaled(pixa, outdepth, tilewidth, ncols,
2361 background, spacing, border);
2362 pixaDestroy(&pixa);
2363 return pixd;
2364 }
2365
2366
2367 /*!
2368 * \brief pixacompWriteFiles()
2369 *
2370 * \param[in] pixac
2371 * \param[in] subdir (subdirectory of /tmp)
2372 * \return 0 if OK, 1 on error
2373 */
2374 l_int32
pixacompWriteFiles(PIXAC * pixac,const char * subdir)2375 pixacompWriteFiles(PIXAC *pixac,
2376 const char *subdir)
2377 {
2378 char buf[128];
2379 l_int32 i, n;
2380 PIXC *pixc;
2381
2382 PROCNAME("pixacompWriteFiles");
2383
2384 if (!pixac)
2385 return ERROR_INT("pixac not defined", procName, 1);
2386
2387 if (lept_mkdir(subdir) > 0)
2388 return ERROR_INT("invalid subdir", procName, 1);
2389
2390 n = pixacompGetCount(pixac);
2391 for (i = 0; i < n; i++) {
2392 pixc = pixacompGetPixcomp(pixac, i, L_NOCOPY);
2393 snprintf(buf, sizeof(buf), "/tmp/%s/%03d", subdir, i);
2394 pixcompWriteFile(buf, pixc);
2395 }
2396 return 0;
2397 }
2398
2399 extern const char *ImageFileFormatExtensions[];
2400
2401 /*!
2402 * \brief pixcompWriteFile()
2403 *
2404 * \param[in] rootname
2405 * \param[in] pixc
2406 * \return 0 if OK, 1 on error
2407 *
2408 * <pre>
2409 * Notes:
2410 * (1) The compressed data is written to file, and the filename is
2411 * generated by appending the format extension to %rootname.
2412 * </pre>
2413 */
2414 l_int32
pixcompWriteFile(const char * rootname,PIXC * pixc)2415 pixcompWriteFile(const char *rootname,
2416 PIXC *pixc)
2417 {
2418 char buf[128];
2419
2420 PROCNAME("pixcompWriteFile");
2421
2422 if (!pixc)
2423 return ERROR_INT("pixc not defined", procName, 1);
2424
2425 snprintf(buf, sizeof(buf), "%s.%s", rootname,
2426 ImageFileFormatExtensions[pixc->comptype]);
2427 l_binaryWrite(buf, "w", pixc->data, pixc->size);
2428 return 0;
2429 }
2430
2431
2432