comparison mupdf-source/thirdparty/leptonica/src/bmpio.c @ 2:b50eed0cc0ef upstream

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