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