Leptonica 1.84.1
Image processing and image analysis suite
Loading...
Searching...
No Matches
bmpio.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
42#ifdef HAVE_CONFIG_H
43#include <config_auto.h>
44#endif /* HAVE_CONFIG_H */
45
46#include <string.h>
47#include "allheaders.h"
48#include "pix_internal.h"
49#include "bmp.h"
50
51/* --------------------------------------------*/
52#if USE_BMPIO /* defined in environ.h */
53/* --------------------------------------------*/
54
55 /* Here we're setting the pixel value 0 to white (255) and the
56 * value 1 to black (0). This is the convention for grayscale, but
57 * the opposite of the convention for 1 bpp, where 0 is white
58 * and 1 is black. Both colormap entries are opaque (alpha = 255) */
59RGBA_QUAD bwmap[2] = { {255,255,255,255}, {0,0,0,255} };
60
61 /* Image dimension limits */
62static const l_int32 L_MAX_ALLOWED_WIDTH = 1000000;
63static const l_int32 L_MAX_ALLOWED_HEIGHT = 1000000;
64static const l_int64 L_MAX_ALLOWED_PIXELS = 400000000LL;
65static const l_int32 L_MAX_ALLOWED_RES = 10000000; /* pixels/meter */
66
67#ifndef NO_CONSOLE_IO
68#define DEBUG 0
69#endif /* ~NO_CONSOLE_IO */
70
71/*--------------------------------------------------------------*
72 * Read bmp *
73 *--------------------------------------------------------------*/
87PIX *
89{
90l_uint8 *data;
91size_t size;
92PIX *pix;
93
94 if (!fp)
95 return (PIX *)ERROR_PTR("fp not defined", __func__, NULL);
96
97 /* Read data from file and decode into Y,U,V arrays */
98 rewind(fp);
99 if ((data = l_binaryReadStream(fp, &size)) == NULL)
100 return (PIX *)ERROR_PTR("data not read", __func__, NULL);
101
102 pix = pixReadMemBmp(data, size);
103 LEPT_FREE(data);
104 return pix;
105}
106
107
131PIX *
132pixReadMemBmp(const l_uint8 *cdata,
133 size_t size)
134{
135l_uint8 pel[4];
136l_uint8 *cmapBuf, *fdata, *data;
137l_int16 bftype, depth, d;
138l_int32 offset, ihbytes, width, height, height_neg, xres, yres, spp;
139l_int32 compression, imagebytes, fdatabytes, cmapbytes, ncolors, maxcolors;
140l_int32 fdatabpl, extrabytes, filebpp, pixWpl, pixBpl, i, j, k;
141l_uint32 *line, *pixdata, *pword;
142l_int64 npixels;
143BMP_FH *bmpfh;
144#if defined(__GNUC__)
145BMP_HEADER *bmph;
146#define bmpih (&bmph->bmpih)
147#else
148BMP_IH *bmpih;
149#endif
150PIX *pix, *pix1;
151PIXCMAP *cmap;
152
153 if (!cdata)
154 return (PIX *)ERROR_PTR("cdata not defined", __func__, NULL);
155 if (size < sizeof(BMP_FH) + sizeof(BMP_IH))
156 return (PIX *)ERROR_PTR("bmf size error", __func__, NULL);
157
158 /* Verify this is an uncompressed bmp */
159 bmpfh = (BMP_FH *)cdata;
160 bftype = bmpfh->bfType[0] + ((l_int32)bmpfh->bfType[1] << 8);
161 if (bftype != BMP_ID)
162 return (PIX *)ERROR_PTR("not bmf format", __func__, NULL);
163#if defined(__GNUC__)
164 bmph = (BMP_HEADER *)bmpfh;
165#else
166 bmpih = (BMP_IH *)(cdata + BMP_FHBYTES);
167#endif
168 compression = convertOnBigEnd32(bmpih->biCompression);
169 if (compression != 0)
170 return (PIX *)ERROR_PTR("cannot read compressed BMP files",
171 __func__, NULL);
172
173 /* Find the offset from the beginning of the file to the image data */
174 offset = bmpfh->bfOffBits[0];
175 offset += (l_int32)bmpfh->bfOffBits[1] << 8;
176 offset += (l_int32)bmpfh->bfOffBits[2] << 16;
177 offset += (l_uint32)bmpfh->bfOffBits[3] << 24;
178
179 /* Read the remaining useful data in the infoheader.
180 * Note that the first 4 bytes give the infoheader size. */
181 ihbytes = convertOnBigEnd32(*(l_uint32 *)(bmpih));
182 width = convertOnBigEnd32(bmpih->biWidth);
183 height = convertOnBigEnd32(bmpih->biHeight);
184 depth = convertOnBigEnd16(bmpih->biBitCount);
185 imagebytes = convertOnBigEnd32(bmpih->biSizeImage);
186 xres = convertOnBigEnd32(bmpih->biXPelsPerMeter);
187 yres = convertOnBigEnd32(bmpih->biYPelsPerMeter);
188
189 /* Some sanity checking. We impose limits on the image
190 * dimensions, resolution and number of pixels. We make sure the
191 * file is the correct size to hold the amount of uncompressed data
192 * that is specified in the header. The number of colormap
193 * entries is checked: it can be either 0 (no cmap) or some
194 * number between 2 and 256.
195 * Note that the imagebytes for uncompressed images is either
196 * 0 or the size of the file data. (The fact that it can
197 * be 0 is perhaps some legacy glitch). */
198 if (width < 1)
199 return (PIX *)ERROR_PTR("width < 1", __func__, NULL);
200 if (width > L_MAX_ALLOWED_WIDTH)
201 return (PIX *)ERROR_PTR("width too large", __func__, NULL);
202 if (height == 0 || height < -L_MAX_ALLOWED_HEIGHT ||
203 height > L_MAX_ALLOWED_HEIGHT)
204 return (PIX *)ERROR_PTR("invalid height", __func__, NULL);
205 if (xres < 0 || xres > L_MAX_ALLOWED_RES ||
206 yres < 0 || yres > L_MAX_ALLOWED_RES)
207 return (PIX *)ERROR_PTR("invalid resolution", __func__, NULL);
208 height_neg = 0;
209 if (height < 0) {
210 height_neg = 1;
211 height = -height;
212 }
213 if (ihbytes != 40 && ihbytes != 108 && ihbytes != 124) {
214 L_ERROR("invalid ihbytes = %d; not in {40, 108, 124}\n",
215 __func__, ihbytes);
216 return NULL;
217 }
218 npixels = 1LL * width * height;
219 if (npixels > L_MAX_ALLOWED_PIXELS)
220 return (PIX *)ERROR_PTR("npixels too large", __func__, NULL);
221 if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
222 depth != 16 && depth != 24 && depth != 32) {
223 L_ERROR("invalid depth = %d; not in {1, 2, 4, 8, 16, 24, 32}\n",
224 __func__, depth);
225 return NULL;
226 }
227 fdatabpl = 4 * ((1LL * width * depth + 31)/32);
228 fdatabytes = fdatabpl * height;
229 if (imagebytes != 0 && imagebytes != fdatabytes) {
230 L_ERROR("invalid imagebytes = %d; not equal to fdatabytes = %d\n",
231 __func__, imagebytes, fdatabytes);
232 return NULL;
233 }
234
235 /* In the original spec, BITMAPINFOHEADER is 40 bytes.
236 * There have been a number of revisions, to capture more information.
237 * For example, the fifth version, BITMAPV5HEADER, adds 84 bytes
238 * of ICC color profiles. We use the size of the infoheader
239 * to accommodate these newer formats. Knowing the size of the
240 * infoheader gives more opportunity to sanity check input params. */
241 cmapbytes = offset - BMP_FHBYTES - ihbytes;
242 ncolors = cmapbytes / sizeof(RGBA_QUAD);
243 if (ncolors < 0 || ncolors == 1)
244 return (PIX *)ERROR_PTR("invalid: cmap size < 0 or 1", __func__, NULL);
245 if (ncolors > 0 && depth > 8)
246 return (PIX *)ERROR_PTR("can't have cmap for d > 8", __func__, NULL);
247 maxcolors = (depth <= 8) ? 1 << depth : 0;
248 if (ncolors > maxcolors) {
249 L_ERROR("cmap too large for depth %d: ncolors = %d > maxcolors = %d\n",
250 __func__, depth, ncolors, maxcolors);
251 return NULL;
252 }
253 if (size != 1LL * offset + 1LL * fdatabytes)
254 return (PIX *)ERROR_PTR("size incommensurate with image data",
255 __func__,NULL);
256
257 /* Handle the colormap */
258 cmapBuf = NULL;
259 if (ncolors > 0) {
260 if ((cmapBuf = (l_uint8 *)LEPT_CALLOC(ncolors, sizeof(RGBA_QUAD)))
261 == NULL)
262 return (PIX *)ERROR_PTR("cmapBuf alloc fail", __func__, NULL );
263
264 /* Read the colormap entry data from bmp. The RGBA_QUAD colormap
265 * entries are used for both bmp and leptonica colormaps. */
266 memcpy(cmapBuf, cdata + BMP_FHBYTES + ihbytes,
267 ncolors * sizeof(RGBA_QUAD));
268 }
269
270 /* Make a 32 bpp pix if file depth is 24 bpp */
271 d = (depth == 24) ? 32 : depth;
272 if ((pix = pixCreate(width, height, d)) == NULL) {
273 LEPT_FREE(cmapBuf);
274 return (PIX *)ERROR_PTR( "pix not made", __func__, NULL);
275 }
276 pixSetXRes(pix, (l_int32)((l_float32)xres / 39.37 + 0.5)); /* to ppi */
277 pixSetYRes(pix, (l_int32)((l_float32)yres / 39.37 + 0.5)); /* to ppi */
278 pixSetInputFormat(pix, IFF_BMP);
279 pixWpl = pixGetWpl(pix);
280 pixBpl = 4 * pixWpl;
281 if (depth <= 16)
282 spp = 1;
283 else if (depth == 24)
284 spp = 3;
285 else /* depth == 32 */
286 spp = 4;
287 pixSetSpp(pix, spp);
288
289 /* Convert the bmp colormap to a pixcmap */
290 cmap = NULL;
291 if (ncolors > 0) { /* import the colormap to the pix cmap */
292 cmap = pixcmapCreate(L_MIN(d, 8));
293 LEPT_FREE(cmap->array); /* remove generated cmap array */
294 cmap->array = (void *)cmapBuf; /* and replace */
295 cmap->n = L_MIN(ncolors, 256);
296 for (i = 0; i < cmap->n; i++) /* set all colors opaque */
297 pixcmapSetAlpha (cmap, i, 255);
298 }
299 if (pixSetColormap(pix, cmap)) {
300 pixDestroy(&pix);
301 return (PIX *)ERROR_PTR("invalid colormap", __func__, NULL);
302 }
303
304 /* Acquire the image data. Image origin for bmp is at lower right. */
305 fdata = (l_uint8 *)cdata + offset; /* start of the bmp image data */
306 pixdata = pixGetData(pix);
307 if (depth != 24 && depth != 32) { /* typ. 1 or 8 bpp */
308 data = (l_uint8 *)pixdata + pixBpl * (height - 1);
309 for (i = 0; i < height; i++) {
310 memcpy(data, fdata, fdatabpl);
311 fdata += fdatabpl;
312 data -= pixBpl;
313 }
314 } else { /* 24 or 32 bpp file; 32 bpp pix
315 * Note: for rgb bmp files, pel[0] is blue, pel[1] is green,
316 * and pel[2] is red. This is opposite to the storage
317 * in the pix, which puts the red pixel in the 0 byte,
318 * the green in the 1 byte and the blue in the 2 byte.
319 * Note also that all words are endian flipped after
320 * assignment on L_LITTLE_ENDIAN platforms.
321 *
322 * We can then make these assignments for little endians:
323 * SET_DATA_BYTE(pword, 1, pel[0]); blue
324 * SET_DATA_BYTE(pword, 2, pel[1]); green
325 * SET_DATA_BYTE(pword, 3, pel[2]); red
326 * This looks like:
327 * 3 (R) 2 (G) 1 (B) 0
328 * |-----------|------------|-----------|-----------|
329 * and after byte flipping:
330 * 3 2 (B) 1 (G) 0 (R)
331 * |-----------|------------|-----------|-----------|
332 *
333 * For big endians we set:
334 * SET_DATA_BYTE(pword, 2, pel[0]); blue
335 * SET_DATA_BYTE(pword, 1, pel[1]); green
336 * SET_DATA_BYTE(pword, 0, pel[2]); red
337 * This looks like:
338 * 0 (R) 1 (G) 2 (B) 3
339 * |-----------|------------|-----------|-----------|
340 * so in both cases we get the correct assignment in the PIX.
341 *
342 * Can we do a platform-independent assignment?
343 * Yes, set the bytes without using macros:
344 * *((l_uint8 *)pword) = pel[2]; red
345 * *((l_uint8 *)pword + 1) = pel[1]; green
346 * *((l_uint8 *)pword + 2) = pel[0]; blue
347 * For little endians, before flipping, this looks again like:
348 * 3 (R) 2 (G) 1 (B) 0
349 * |-----------|------------|-----------|-----------|
350 *
351 * For reading an spp == 4 file with a transparency component,
352 * the code below shows where the alpha component is located
353 * in each pixel.
354 */
355 filebpp = (depth == 24) ? 3 : 4;
356 extrabytes = fdatabpl - filebpp * width;
357 line = pixdata + pixWpl * (height - 1);
358 for (i = 0; i < height; i++) {
359 for (j = 0; j < width; j++) {
360 pword = line + j;
361 memcpy(&pel, fdata, filebpp);
362 fdata += filebpp;
363 *((l_uint8 *)pword + COLOR_RED) = pel[2];
364 *((l_uint8 *)pword + COLOR_GREEN) = pel[1];
365 *((l_uint8 *)pword + COLOR_BLUE) = pel[0];
366 /* Set the alpha byte to opaque for rgb */
367 if (depth == 24)
368 *((l_uint8 *)pword + L_ALPHA_CHANNEL) = 255;
369 else
370 *((l_uint8 *)pword + L_ALPHA_CHANNEL) = pel[3];
371 }
372 if (extrabytes) {
373 for (k = 0; k < extrabytes; k++) {
374 memcpy(&pel, fdata, 1);
375 fdata++;
376 }
377 }
378 line -= pixWpl;
379 }
380 }
381
382 pixEndianByteSwap(pix);
383 if (height_neg)
384 pixFlipTB(pix, pix);
385
386 /* ----------------------------------------------
387 * We do not use 1 bpp pix with colormaps in leptonica.
388 * The colormap must be removed in such a way that the pixel
389 * values are not changed. If the values are only black and
390 * white, return a 1 bpp image; if gray, return an 8 bpp pix;
391 * otherwise, return a 32 bpp rgb pix.
392 * ---------------------------------------------- */
393 if (depth == 1 && cmap) {
394 L_INFO("removing opaque cmap from 1 bpp\n", __func__);
395 pix1 = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
396 pixDestroy(&pix);
397 pix = pix1; /* rename */
398 }
399
400 return pix;
401}
402
403
404/*--------------------------------------------------------------*
405 * Write bmp *
406 *--------------------------------------------------------------*/
414l_ok
416 PIX *pix)
417{
418l_uint8 *data;
419size_t size, nbytes;
420
421 if (!fp)
422 return ERROR_INT("stream not defined", __func__, 1);
423 if (!pix)
424 return ERROR_INT("pix not defined", __func__, 1);
425
426 pixWriteMemBmp(&data, &size, pix);
427 rewind(fp);
428 nbytes = fwrite(data, 1, size, fp);
429 free(data);
430 if (nbytes != size)
431 return ERROR_INT("Write error", __func__, 1);
432 return 0;
433}
434
435
456l_ok
457pixWriteMemBmp(l_uint8 **pfdata,
458 size_t *pfsize,
459 PIX *pixs)
460{
461l_uint8 pel[4];
462l_uint8 *cta = NULL; /* address of the bmp color table array */
463l_uint8 *fdata, *data, *fmdata;
464l_int32 cmaplen; /* number of bytes in the bmp colormap */
465l_int32 ncolors, val, stepsize, w, h, d, fdepth, xres, yres, valid;
466l_int32 pixWpl, pixBpl, extrabytes, spp, fBpl, fWpl, i, j, k;
467l_int32 heapcm; /* extra copy of cta on the heap ? 1 : 0 */
468l_uint32 offbytes, fimagebytes;
469l_uint32 *line, *pword;
470size_t fsize;
471BMP_FH *bmpfh;
472#if defined(__GNUC__)
473BMP_HEADER *bmph;
474#define bmpih (&bmph->bmpih)
475#else
476BMP_IH *bmpih;
477#endif
478PIX *pix;
479PIXCMAP *cmap;
480RGBA_QUAD *pquad;
481
482 if (pfdata) *pfdata = NULL;
483 if (pfsize) *pfsize = 0;
484 if (!pfdata)
485 return ERROR_INT("&fdata not defined", __func__, 1 );
486 if (!pfsize)
487 return ERROR_INT("&fsize not defined", __func__, 1 );
488 if (!pixs)
489 return ERROR_INT("pixs not defined", __func__, 1);
490
491 /* Verify validity of colormap */
492 if ((cmap = pixGetColormap(pixs)) != NULL) {
493 pixcmapIsValid(cmap, pixs, &valid);
494 if (!valid)
495 return ERROR_INT("colormap is not valid", __func__, 1);
496 }
497
498 pixGetDimensions(pixs, &w, &h, &d);
499 spp = pixGetSpp(pixs);
500 if (spp != 1 && spp != 3 && spp != 4) {
501 L_ERROR("unsupported spp = %d\n", __func__, spp);
502 return 1;
503 }
504 if (d == 2) {
505 L_WARNING("2 bpp files can't be read; converting to 8 bpp\n",
506 __func__);
507 pix = pixConvert2To8(pixs, 0, 85, 170, 255, 1);
508 d = 8;
509 } else if (d == 24) {
510 pix = pixConvert24To32(pixs);
511 d = 32;
512 } else {
513 pix = pixCopy(NULL, pixs);
514 }
515
516 /* Find the bits/pixel to be written to file */
517 if (spp == 1)
518 fdepth = d;
519 else if (spp == 3)
520 fdepth = 24;
521 else /* spp == 4 */
522 fdepth = 32;
523
524 /* Resolution is given in pixels/meter */
525 xres = (l_int32)(39.37 * (l_float32)pixGetXRes(pix) + 0.5);
526 yres = (l_int32)(39.37 * (l_float32)pixGetYRes(pix) + 0.5);
527
528 pixWpl = pixGetWpl(pix);
529 pixBpl = 4 * pixWpl;
530 fWpl = (w * fdepth + 31) / 32;
531 fBpl = 4 * fWpl;
532 fimagebytes = h * fBpl;
533 if (fimagebytes > 4LL * L_MAX_ALLOWED_PIXELS) {
534 pixDestroy(&pix);
535 return ERROR_INT("image data is too large", __func__, 1);
536 }
537
538 /* If not rgb or 16 bpp, the bmp data is required to have a colormap */
539 heapcm = 0;
540 if (d == 32 || d == 16) { /* 24 bpp rgb or 16 bpp: no colormap */
541 ncolors = 0;
542 cmaplen = 0;
543 } else if ((cmap = pixGetColormap(pix))) { /* existing colormap */
544 ncolors = pixcmapGetCount(cmap);
545 cmaplen = ncolors * sizeof(RGBA_QUAD);
546 cta = (l_uint8 *)cmap->array;
547 } else { /* no existing colormap; d <= 8; make a binary or gray one */
548 if (d == 1) {
549 cmaplen = sizeof(bwmap);
550 ncolors = 2;
551 cta = (l_uint8 *)bwmap;
552 } else { /* d = 2,4,8; use a grayscale output colormap */
553 ncolors = 1 << fdepth;
554 cmaplen = ncolors * sizeof(RGBA_QUAD);
555 heapcm = 1;
556 cta = (l_uint8 *)LEPT_CALLOC(cmaplen, 1);
557 stepsize = 255 / (ncolors - 1);
558 for (i = 0, val = 0, pquad = (RGBA_QUAD *)cta;
559 i < ncolors;
560 i++, val += stepsize, pquad++) {
561 pquad->blue = pquad->green = pquad->red = val;
562 pquad->alpha = 255; /* opaque */
563 }
564 }
565 }
566
567#if DEBUG
568 {l_uint8 *pcmptr;
569 pcmptr = (l_uint8 *)pixGetColormap(pix)->array;
570 lept_stderr("Pix colormap[0] = %c%c%c%d\n",
571 pcmptr[0], pcmptr[1], pcmptr[2], pcmptr[3]);
572 lept_stderr("Pix colormap[1] = %c%c%c%d\n",
573 pcmptr[4], pcmptr[5], pcmptr[6], pcmptr[7]);
574 }
575#endif /* DEBUG */
576
577 offbytes = BMP_FHBYTES + BMP_IHBYTES + cmaplen;
578 fsize = offbytes + fimagebytes;
579 fdata = (l_uint8 *)LEPT_CALLOC(fsize, 1);
580 *pfdata = fdata;
581 *pfsize = fsize;
582
583 /* Write little-endian file header data */
584 bmpfh = (BMP_FH *)fdata;
585 bmpfh->bfType[0] = (l_uint8)(BMP_ID >> 0);
586 bmpfh->bfType[1] = (l_uint8)(BMP_ID >> 8);
587 bmpfh->bfSize[0] = (l_uint8)(fsize >> 0);
588 bmpfh->bfSize[1] = (l_uint8)(fsize >> 8);
589 bmpfh->bfSize[2] = (l_uint8)(fsize >> 16);
590 bmpfh->bfSize[3] = (l_uint8)(fsize >> 24);
591 bmpfh->bfOffBits[0] = (l_uint8)(offbytes >> 0);
592 bmpfh->bfOffBits[1] = (l_uint8)(offbytes >> 8);
593 bmpfh->bfOffBits[2] = (l_uint8)(offbytes >> 16);
594 bmpfh->bfOffBits[3] = (l_uint8)(offbytes >> 24);
595
596 /* Convert to little-endian and write the info header data */
597#if defined(__GNUC__)
598 bmph = (BMP_HEADER *)bmpfh;
599#else
600 bmpih = (BMP_IH *)(fdata + BMP_FHBYTES);
601#endif
602 bmpih->biSize = convertOnBigEnd32(BMP_IHBYTES);
603 bmpih->biWidth = convertOnBigEnd32(w);
604 bmpih->biHeight = convertOnBigEnd32(h);
605 bmpih->biPlanes = convertOnBigEnd16(1);
606 bmpih->biBitCount = convertOnBigEnd16(fdepth);
607 bmpih->biSizeImage = convertOnBigEnd32(fimagebytes);
608 bmpih->biXPelsPerMeter = convertOnBigEnd32(xres);
609 bmpih->biYPelsPerMeter = convertOnBigEnd32(yres);
610 bmpih->biClrUsed = convertOnBigEnd32(ncolors);
611 bmpih->biClrImportant = convertOnBigEnd32(ncolors);
612
613 /* Copy the colormap data and free the cta if necessary */
614 if (ncolors > 0) {
615 memcpy(fdata + BMP_FHBYTES + BMP_IHBYTES, cta, cmaplen);
616 if (heapcm) LEPT_FREE(cta);
617 }
618
619 /* When you write a binary image with a colormap
620 * that sets BLACK to 0, you must invert the data */
621 if (fdepth == 1 && cmap && ((l_uint8 *)(cmap->array))[0] == 0x0) {
622 pixInvert(pix, pix);
623 }
624
625 /* An endian byte swap is also required */
626 pixEndianByteSwap(pix);
627
628 /* Transfer the image data. Image origin for bmp is at lower right. */
629 fmdata = fdata + offbytes;
630 if (fdepth != 24 && fdepth != 32) { /* typ 1 or 8 bpp */
631 data = (l_uint8 *)pixGetData(pix) + pixBpl * (h - 1);
632 for (i = 0; i < h; i++) {
633 memcpy(fmdata, data, fBpl);
634 data -= pixBpl;
635 fmdata += fBpl;
636 }
637 } else { /* 32 bpp pix; 24 bpp or 32 bpp file
638 * See the comments in pixReadStreamBmp() to
639 * understand the logic behind the pixel ordering below.
640 * Note that we have again done an endian swap on
641 * little endian machines before arriving here, so that
642 * the bytes are ordered on both platforms as:
643 * Red Green Blue --
644 * |-----------|------------|-----------|-----------|
645 *
646 * For writing an spp == 4 file, the code below shows where
647 * the alpha component is written to file in each pixel.
648 */
649 extrabytes = fBpl - spp * w;
650 line = pixGetData(pix) + pixWpl * (h - 1);
651 for (i = 0; i < h; i++) {
652 for (j = 0; j < w; j++) {
653 pword = line + j;
654 pel[2] = *((l_uint8 *)pword + COLOR_RED);
655 pel[1] = *((l_uint8 *)pword + COLOR_GREEN);
656 pel[0] = *((l_uint8 *)pword + COLOR_BLUE);
657 if (spp == 4)
658 pel[3] = *((l_uint8 *)pword + L_ALPHA_CHANNEL);
659 memcpy(fmdata, &pel, spp);
660 fmdata += spp;
661 }
662 if (extrabytes) {
663 for (k = 0; k < extrabytes; k++) {
664 memcpy(fmdata, &pel, 1);
665 fmdata++;
666 }
667 }
668 line -= pixWpl;
669 }
670 }
671
672 pixDestroy(&pix);
673 return 0;
674}
675
676/* --------------------------------------------*/
677#endif /* USE_BMPIO */
#define BMP_IHBYTES
Definition bmp.h:108
#define BMP_FHBYTES
Definition bmp.h:83
l_ok pixWriteStreamBmp(FILE *fp, PIX *pix)
pixWriteStreamBmp()
Definition bmpio.c:415
PIX * pixReadStreamBmp(FILE *fp)
pixReadStreamBmp()
Definition bmpio.c:88
l_ok pixWriteMemBmp(l_uint8 **pfdata, size_t *pfsize, PIX *pixs)
pixWriteMemBmp()
Definition bmpio.c:457
PIX * pixReadMemBmp(const l_uint8 *cdata, size_t size)
pixReadMemBmp()
Definition bmpio.c:132
@ BMP_ID
Definition imageio.h:126
@ COLOR_BLUE
Definition pix.h:330
@ COLOR_RED
Definition pix.h:328
@ L_ALPHA_CHANNEL
Definition pix.h:331
@ COLOR_GREEN
Definition pix.h:329
@ REMOVE_CMAP_BASED_ON_SRC
Definition pix.h:384
struct RGBA_Quad RGBA_QUAD
Definition pix.h:237
l_uint8 bfOffBits[4]
Definition bmp.h:78
l_uint8 bfSize[4]
Definition bmp.h:70
l_uint8 bfType[2]
Definition bmp.h:69
l_int32 biSizeImage
Definition bmp.h:99
l_int32 biXPelsPerMeter
Definition bmp.h:100
l_int32 biClrImportant
Definition bmp.h:103
l_int32 biClrUsed
Definition bmp.h:102
l_int32 biSize
Definition bmp.h:93
l_int32 biYPelsPerMeter
Definition bmp.h:101
l_int16 biPlanes
Definition bmp.h:96
l_int32 biWidth
Definition bmp.h:94
l_int16 biBitCount
Definition bmp.h:97
l_int32 biHeight
Definition bmp.h:95
l_int32 biCompression
Definition bmp.h:98
l_uint8 alpha
l_uint8 green
l_uint8 blue
l_uint8 red