Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
spixio.c
Go to the documentation of this file.
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
59#ifdef HAVE_CONFIG_H
60#include <config_auto.h>
61#endif /* HAVE_CONFIG_H */
62
63#include <string.h>
64#include "allheaders.h"
65
66 /* Image dimension limits */
67static const l_int32 MaxAllowedWidth = 1000000;
68static const l_int32 MaxAllowedHeight = 1000000;
69static const l_int64 MaxAllowedArea = 400000000LL;
70
71#ifndef NO_CONSOLE_IO
72#define DEBUG_SERIALIZE 0
73#endif /* ~NO_CONSOLE_IO */
74
75
76/*-----------------------------------------------------------------------*
77 * Reading spix from file *
78 *-----------------------------------------------------------------------*/
91PIX *
93{
94size_t nbytes;
95l_uint8 *data;
96PIX *pix;
97
98 if (!fp)
99 return (PIX *)ERROR_PTR("stream not defined", __func__, NULL);
100
101 if ((data = l_binaryReadStream(fp, &nbytes)) == NULL)
102 return (PIX *)ERROR_PTR("data not read", __func__, NULL);
103 pix = pixReadMemSpix(data, nbytes);
104 LEPT_FREE(data);
105 if (!pix)
106 return (PIX *)ERROR_PTR("pix not made", __func__, NULL);
107 return pix;
108}
109
110
127l_ok
128readHeaderSpix(const char *filename,
129 l_int32 *pwidth,
130 l_int32 *pheight,
131 l_int32 *pbps,
132 l_int32 *pspp,
133 l_int32 *piscmap)
134{
135l_int32 ret;
136FILE *fp;
137
138 if (!filename)
139 return ERROR_INT("filename not defined", __func__, 1);
140 if (!pwidth || !pheight || !pbps || !pspp)
141 return ERROR_INT("input ptr(s) not defined", __func__, 1);
142 if ((fp = fopenReadStream(filename)) == NULL)
143 return ERROR_INT_1("image file not found", filename, __func__, 1);
144 ret = freadHeaderSpix(fp, pwidth, pheight, pbps, pspp, piscmap);
145 fclose(fp);
146 return ret;
147}
148
149
166l_ok
168 l_int32 *pwidth,
169 l_int32 *pheight,
170 l_int32 *pbps,
171 l_int32 *pspp,
172 l_int32 *piscmap)
173{
174l_int32 nbytes, ret;
175l_uint32 data[6];
176
177 if (!fp)
178 return ERROR_INT("stream not defined", __func__, 1);
179 if (!pwidth || !pheight || !pbps || !pspp)
180 return ERROR_INT("input ptr(s) not defined", __func__, 1);
181
182 nbytes = fnbytesInFile(fp);
183 if (nbytes < 32)
184 return ERROR_INT("file too small to be spix", __func__, 1);
185 if (fread(data, 4, 6, fp) != 6)
186 return ERROR_INT("error reading data", __func__, 1);
187 ret = sreadHeaderSpix(data, nbytes, pwidth, pheight, pbps, pspp, piscmap);
188 return ret;
189}
190
191
209l_ok
210sreadHeaderSpix(const l_uint32 *data,
211 size_t size,
212 l_int32 *pwidth,
213 l_int32 *pheight,
214 l_int32 *pbps,
215 l_int32 *pspp,
216 l_int32 *piscmap)
217{
218char *id;
219l_int32 d, ncolors;
220
221 if (!data)
222 return ERROR_INT("data not defined", __func__, 1);
223 if (!pwidth || !pheight || !pbps || !pspp)
224 return ERROR_INT("input ptr(s) not defined", __func__, 1);
225 *pwidth = *pheight = *pbps = *pspp = 0;
226 if (piscmap)
227 *piscmap = 0;
228 if (size < 28)
229 return ERROR_INT("size too small", __func__, 1);
230
231 /* Check file id */
232 id = (char *)data;
233 if (id[0] != 's' || id[1] != 'p' || id[2] != 'i' || id[3] != 'x')
234 return ERROR_INT("not a valid spix file", __func__, 1);
235
236 *pwidth = data[1];
237 *pheight = data[2];
238 d = data[3];
239 if (d <= 16) {
240 *pbps = d;
241 *pspp = 1;
242 } else {
243 *pbps = 8;
244 *pspp = d / 8; /* if the pix is 32 bpp, call it 4 samples */
245 }
246 ncolors = data[5];
247 if (piscmap)
248 *piscmap = (ncolors == 0) ? 0 : 1;
249
250 return 0;
251}
252
253
254/*-----------------------------------------------------------------------*
255 * Writing spix to file *
256 *-----------------------------------------------------------------------*/
264l_ok
266 PIX *pix)
267{
268l_uint8 *data;
269size_t size;
270
271 if (!fp)
272 return ERROR_INT("stream not defined", __func__, 1);
273 if (!pix)
274 return ERROR_INT("pix not defined", __func__, 1);
275
276 if (pixWriteMemSpix(&data, &size, pix))
277 return ERROR_INT("failure to write pix to memory", __func__, 1);
278 fwrite(data, 1, size, fp);
279 LEPT_FREE(data);
280 return 0;
281}
282
283
284/*-----------------------------------------------------------------------*
285 * Low-level serialization of pix to/from memory (uncompressed) *
286 *-----------------------------------------------------------------------*/
294PIX *
295pixReadMemSpix(const l_uint8 *data,
296 size_t size)
297{
298 return pixDeserializeFromMemory((l_uint32 *)data, size);
299}
300
301
310l_ok
311pixWriteMemSpix(l_uint8 **pdata,
312 size_t *psize,
313 PIX *pix)
314{
315 return pixSerializeToMemory(pix, (l_uint32 **)pdata, psize);
316}
317
318
343l_ok
345 l_uint32 **pdata,
346 size_t *pnbytes)
347{
348char *id;
349l_int32 w, h, d, wpl, rdatasize, ncolors, nbytes, index, valid;
350l_uint8 *cdata; /* data in colormap array (4 bytes/color table entry) */
351l_uint32 *data;
352l_uint32 *rdata; /* data in pix raster */
353PIXCMAP *cmap;
354
355 if (!pdata || !pnbytes)
356 return ERROR_INT("&data and &nbytes not both defined", __func__, 1);
357 *pdata = NULL;
358 *pnbytes = 0;
359 if (!pixs)
360 return ERROR_INT("pixs not defined", __func__, 1);
361
362 pixGetDimensions(pixs, &w, &h, &d);
363 wpl = pixGetWpl(pixs);
364 rdata = pixGetData(pixs);
365 rdatasize = 4 * wpl * h;
366 ncolors = 0;
367 cdata = NULL;
368 if ((cmap = pixGetColormap(pixs)) != NULL) {
369 pixcmapIsValid(cmap, pixs, &valid);
370 if (!valid)
371 return ERROR_INT("colormap not valid", __func__, 1);
372 pixcmapSerializeToMemory(cmap, 4, &ncolors, &cdata);
373 }
374
375 nbytes = 24 + 4 * ncolors + 4 + rdatasize;
376 if ((data = (l_uint32 *)LEPT_CALLOC(nbytes / 4, sizeof(l_uint32)))
377 == NULL) {
378 LEPT_FREE(cdata);
379 return ERROR_INT("data not made", __func__, 1);
380 }
381 *pdata = data;
382 *pnbytes = nbytes;
383 id = (char *)data;
384 id[0] = 's';
385 id[1] = 'p';
386 id[2] = 'i';
387 id[3] = 'x';
388 data[1] = w;
389 data[2] = h;
390 data[3] = d;
391 data[4] = wpl;
392 data[5] = ncolors;
393 if (ncolors > 0)
394 memcpy(data + 6, cdata, 4 * ncolors);
395 index = 6 + ncolors;
396 data[index] = rdatasize;
397 memcpy(data + index + 1, rdata, rdatasize);
398
399#if DEBUG_SERIALIZE
400 lept_stderr("Serialize: "
401 "raster size = %d, ncolors in cmap = %d, total bytes = %d\n",
402 rdatasize, ncolors, nbytes);
403#endif /* DEBUG_SERIALIZE */
404
405 LEPT_FREE(cdata);
406 return 0;
407}
408
409
423PIX *
424pixDeserializeFromMemory(const l_uint32 *data,
425 size_t nbytes)
426{
427char *id;
428l_int32 w, h, d, pixdata_size, memdata_size, imdata_size, ncolors, valid;
429l_uint32 *imdata; /* data in pix raster */
430PIX *pix1, *pixd;
431PIXCMAP *cmap = NULL;
432
433 if (!data)
434 return (PIX *)ERROR_PTR("data not defined", __func__, NULL);
435 if (nbytes < 28 || nbytes > ((1LL << 31) - 1)) {
436 L_ERROR("invalid nbytes = %zu\n", __func__, nbytes);
437 return NULL;
438 }
439
440 id = (char *)data;
441 if (id[0] != 's' || id[1] != 'p' || id[2] != 'i' || id[3] != 'x')
442 return (PIX *)ERROR_PTR("invalid id string", __func__, NULL);
443 w = data[1];
444 h = data[2];
445 d = data[3];
446 ncolors = data[5];
447
448 /* Sanity checks on the amount of image data */
449 if (w < 1 || w > MaxAllowedWidth)
450 return (PIX *)ERROR_PTR("invalid width", __func__, NULL);
451 if (h < 1 || h > MaxAllowedHeight)
452 return (PIX *)ERROR_PTR("invalid height", __func__, NULL);
453 if (1LL * w * h > MaxAllowedArea)
454 return (PIX *)ERROR_PTR("area too large", __func__, NULL);
455 if (ncolors < 0 || ncolors > 256 || ncolors + 7 >= nbytes/sizeof(l_int32))
456 return (PIX *)ERROR_PTR("invalid ncolors", __func__, NULL);
457 if ((pix1 = pixCreateHeader(w, h, d)) == NULL) /* just make the header */
458 return (PIX *)ERROR_PTR("failed to make header", __func__, NULL);
459 pixdata_size = 4 * h * pixGetWpl(pix1);
460 memdata_size = nbytes - 24 - 4 * ncolors - 4;
461 imdata_size = data[6 + ncolors];
462 pixDestroy(&pix1);
463 if (pixdata_size != memdata_size || pixdata_size != imdata_size) {
464 L_ERROR("pixdata_size = %d, memdata_size = %d, imdata_size = %d "
465 "not all equal!\n", __func__, pixdata_size, memdata_size,
466 imdata_size);
467 return NULL;
468 }
469
470 if ((pixd = pixCreate(w, h, d)) == NULL)
471 return (PIX *)ERROR_PTR("pix not made", __func__, NULL);
472 if (ncolors > 0) {
473 cmap = pixcmapDeserializeFromMemory((l_uint8 *)(&data[6]), 4, ncolors);
474 if (!cmap) {
475 pixDestroy(&pixd);
476 return (PIX *)ERROR_PTR("cmap not made", __func__, NULL);
477 }
478 if (pixSetColormap(pixd, cmap)) {
479 pixDestroy(&pixd);
480 return (PIX *)ERROR_PTR("cmap is not valid", __func__, NULL);
481 }
482 }
483
484 /* Read the raster data */
485 imdata = pixGetData(pixd);
486 memcpy(imdata, data + 7 + ncolors, imdata_size);
487
488 /* Verify that the colormap is valid with the pix */
489 if (ncolors > 0) {
490 pixcmapIsValid(cmap, pixd, &valid);
491 if (!valid) {
492 pixDestroy(&pixd);
493 return (PIX *)ERROR_PTR("cmap is invalid with pix", __func__, NULL);
494 }
495 }
496
497#if DEBUG_SERIALIZE
498 lept_stderr("Deserialize: "
499 "raster size = %d, ncolors in cmap = %d, total bytes = %zu\n",
500 imdata_size, ncolors, nbytes);
501#endif /* DEBUG_SERIALIZE */
502
503 return pixd;
504}
l_ok freadHeaderSpix(FILE *fp, l_int32 *pwidth, l_int32 *pheight, l_int32 *pbps, l_int32 *pspp, l_int32 *piscmap)
freadHeaderSpix()
Definition spixio.c:167
PIX * pixDeserializeFromMemory(const l_uint32 *data, size_t nbytes)
pixDeserializeFromMemory()
Definition spixio.c:424
l_ok pixWriteMemSpix(l_uint8 **pdata, size_t *psize, PIX *pix)
pixWriteMemSpix()
Definition spixio.c:311
l_ok readHeaderSpix(const char *filename, l_int32 *pwidth, l_int32 *pheight, l_int32 *pbps, l_int32 *pspp, l_int32 *piscmap)
readHeaderSpix()
Definition spixio.c:128
l_ok pixWriteStreamSpix(FILE *fp, PIX *pix)
pixWriteStreamSpix()
Definition spixio.c:265
PIX * pixReadStreamSpix(FILE *fp)
pixReadStreamSpix()
Definition spixio.c:92
PIX * pixReadMemSpix(const l_uint8 *data, size_t size)
pixReadMemSpix()
Definition spixio.c:295
l_ok pixSerializeToMemory(PIX *pixs, l_uint32 **pdata, size_t *pnbytes)
pixSerializeToMemory()
Definition spixio.c:344
l_ok sreadHeaderSpix(const l_uint32 *data, size_t size, l_int32 *pwidth, l_int32 *pheight, l_int32 *pbps, l_int32 *pspp, l_int32 *piscmap)
sreadHeaderSpix()
Definition spixio.c:210