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 "bmp.h"
49
50 /* --------------------------------------------*/
51 #if USE_BMPIO /* defined in environ.h */
52 /* --------------------------------------------*/
53
54 /* Here we're setting the pixel value 0 to white (255) and the
55 * value 1 to black (0). This is the convention for grayscale, but
56 * the opposite of the convention for 1 bpp, where 0 is white
57 * and 1 is black. Both colormap entries are opaque (alpha = 255) */
58 RGBA_QUAD bwmap[2] = { {255,255,255,255}, {0,0,0,255} };
59
60 /* Colormap size limit */
61 static const l_int32 L_MAX_ALLOWED_NUM_COLORS = 256;
62
63 /* Image dimension limits */
64 static const l_int32 L_MAX_ALLOWED_WIDTH = 1000000;
65 static const l_int32 L_MAX_ALLOWED_HEIGHT = 1000000;
66 static const l_int64 L_MAX_ALLOWED_PIXELS = 400000000LL;
67
68 #ifndef NO_CONSOLE_IO
69 #define DEBUG 0
70 #endif /* ~NO_CONSOLE_IO */
71
72 /*--------------------------------------------------------------*
73 * Read bmp *
74 *--------------------------------------------------------------*/
75 /*!
76 * \brief pixReadStreamBmp()
77 *
78 * \param[in] fp file stream opened for read
79 * \return pix, or NULL on error
80 *
81 * <pre>
82 * Notes:
83 * (1) Here are references on the bmp file format:
84 * http://en.wikipedia.org/wiki/BMP_file_format
85 * http://www.fortunecity.com/skyscraper/windows/364/bmpffrmt.html
86 * </pre>
87 */
88 PIX *
pixReadStreamBmp(FILE * fp)89 pixReadStreamBmp(FILE *fp)
90 {
91 l_uint8 *data;
92 size_t size;
93 PIX *pix;
94
95 PROCNAME("pixReadStreamBmp");
96
97 if (!fp)
98 return (PIX *)ERROR_PTR("fp not defined", procName, NULL);
99
100 /* Read data from file and decode into Y,U,V arrays */
101 rewind(fp);
102 if ((data = l_binaryReadStream(fp, &size)) == NULL)
103 return (PIX *)ERROR_PTR("data not read", procName, NULL);
104
105 pix = pixReadMemBmp(data, size);
106 LEPT_FREE(data);
107 return pix;
108 }
109
110
111 /*!
112 * \brief pixReadMemBmp()
113 *
114 * \param[in] cdata bmp data
115 * \param[in] size number of bytes of bmp-formatted data
116 * \return pix, or NULL on error
117 */
118 PIX *
pixReadMemBmp(const l_uint8 * cdata,size_t size)119 pixReadMemBmp(const l_uint8 *cdata,
120 size_t size)
121 {
122 l_uint8 pel[4];
123 l_uint8 *cmapBuf, *fdata, *data;
124 l_int16 bftype, offset, depth, d;
125 l_int32 width, height, height_neg, xres, yres, compression, imagebytes;
126 l_int32 cmapbytes, cmapEntries;
127 l_int32 fdatabpl, extrabytes, pixWpl, pixBpl, i, j, k;
128 l_uint32 *line, *pixdata, *pword;
129 l_int64 npixels;
130 BMP_FH *bmpfh;
131 BMP_IH *bmpih;
132 PIX *pix, *pix1;
133 PIXCMAP *cmap;
134
135 PROCNAME("pixReadMemBmp");
136
137 if (!cdata)
138 return (PIX *)ERROR_PTR("cdata not defined", procName, NULL);
139 if (size < sizeof(BMP_FH) + sizeof(BMP_IH))
140 return (PIX *)ERROR_PTR("bmf size error", procName, NULL);
141
142 /* Verify this is an uncompressed bmp */
143 bmpfh = (BMP_FH *)cdata;
144 bftype = convertOnBigEnd16(bmpfh->bfType);
145 if (bftype != BMP_ID)
146 return (PIX *)ERROR_PTR("not bmf format", procName, NULL);
147 bmpih = (BMP_IH *)(cdata + BMP_FHBYTES);
148 if (!bmpih)
149 return (PIX *)ERROR_PTR("bmpih not defined", procName, NULL);
150 compression = convertOnBigEnd32(bmpih->biCompression);
151 if (compression != 0)
152 return (PIX *)ERROR_PTR("cannot read compressed BMP files",
153 procName, NULL);
154
155 /* Read the rest of the useful header information */
156 offset = convertOnBigEnd16(bmpfh->bfOffBits);
157 width = convertOnBigEnd32(bmpih->biWidth);
158 height = convertOnBigEnd32(bmpih->biHeight);
159 depth = convertOnBigEnd16(bmpih->biBitCount);
160 imagebytes = convertOnBigEnd32(bmpih->biSizeImage);
161 xres = convertOnBigEnd32(bmpih->biXPelsPerMeter);
162 yres = convertOnBigEnd32(bmpih->biYPelsPerMeter);
163
164 /* Some sanity checking. We impose limits on the image
165 * dimensions and number of pixels. We make sure the file
166 * is the correct size to hold the amount of uncompressed data
167 * that is specified in the header. The number of colormap
168 * entries is checked: it can be either 0 (no cmap) or some
169 * number between 2 and 256.
170 * Note that the imagebytes for uncompressed images is either
171 * 0 or the size of the file data. (The fact that it can
172 * be 0 is perhaps some legacy glitch). */
173 if (width < 1)
174 return (PIX *)ERROR_PTR("width < 1", procName, NULL);
175 if (width > L_MAX_ALLOWED_WIDTH)
176 return (PIX *)ERROR_PTR("width too large", procName, NULL);
177 height_neg = 0;
178 if (height < 0) {
179 height_neg = 1;
180 height = -height;
181 }
182 if (height == 0 || height > L_MAX_ALLOWED_HEIGHT)
183 return (PIX *)ERROR_PTR("invalid height", procName, NULL);
184 npixels = 1LL * width * height;
185 if (npixels > L_MAX_ALLOWED_PIXELS)
186 return (PIX *)ERROR_PTR("npixels too large", procName, NULL);
187 if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
188 depth != 16 && depth != 24 && depth != 32)
189 return (PIX *)ERROR_PTR("depth not in {1, 2, 4, 8, 16, 24, 32}",
190 procName,NULL);
191 fdatabpl = 4 * ((1LL * width * depth + 31)/32);
192 if (imagebytes != 0 && imagebytes != fdatabpl * height)
193 return (PIX *)ERROR_PTR("invalid imagebytes", procName, NULL);
194 cmapbytes = offset - BMP_FHBYTES - BMP_IHBYTES;
195 cmapEntries = cmapbytes / sizeof(RGBA_QUAD);
196 if (cmapEntries < 0 || cmapEntries == 1)
197 return (PIX *)ERROR_PTR("invalid: cmap size < 0 or 1", procName, NULL);
198 if (cmapEntries > L_MAX_ALLOWED_NUM_COLORS)
199 return (PIX *)ERROR_PTR("invalid cmap: too large", procName,NULL);
200 if (size != 1LL * offset + 1LL * fdatabpl * height)
201 return (PIX *)ERROR_PTR("size incommensurate with image data",
202 procName,NULL);
203
204 /* Handle the colormap */
205 cmapBuf = NULL;
206 if (cmapEntries > 0) {
207 if ((cmapBuf = (l_uint8 *)LEPT_CALLOC(cmapEntries, sizeof(RGBA_QUAD)))
208 == NULL)
209 return (PIX *)ERROR_PTR("cmapBuf alloc fail", procName, NULL );
210
211 /* Read the colormap entry data from bmp. The RGBA_QUAD colormap
212 * entries are used for both bmp and leptonica colormaps. */
213 memcpy(cmapBuf, cdata + BMP_FHBYTES + BMP_IHBYTES,
214 sizeof(RGBA_QUAD) * cmapEntries);
215 }
216
217 /* Make a 32 bpp pix if depth is 24 bpp */
218 d = (depth == 24) ? 32 : depth;
219 if ((pix = pixCreate(width, height, d)) == NULL) {
220 LEPT_FREE(cmapBuf);
221 return (PIX *)ERROR_PTR( "pix not made", procName, NULL);
222 }
223 pixSetXRes(pix, (l_int32)((l_float32)xres / 39.37 + 0.5)); /* to ppi */
224 pixSetYRes(pix, (l_int32)((l_float32)yres / 39.37 + 0.5)); /* to ppi */
225 pixSetInputFormat(pix, IFF_BMP);
226 pixWpl = pixGetWpl(pix);
227 pixBpl = 4 * pixWpl;
228
229 /* Convert the bmp colormap to a pixcmap */
230 cmap = NULL;
231 if (cmapEntries > 0) { /* import the colormap to the pix cmap */
232 cmap = pixcmapCreate(L_MIN(d, 8));
233 LEPT_FREE(cmap->array); /* remove generated cmap array */
234 cmap->array = (void *)cmapBuf; /* and replace */
235 cmap->n = L_MIN(cmapEntries, 256);
236 for (i = 0; i < cmap->n; i++) /* set all colors opaque */
237 pixcmapSetAlpha (cmap, i, 255);
238 }
239 pixSetColormap(pix, cmap);
240
241 /* Acquire the image data. Image origin for bmp is at lower right. */
242 fdata = (l_uint8 *)cdata + offset; /* start of the bmp image data */
243 pixdata = pixGetData(pix);
244 if (depth != 24) { /* typ. 1 or 8 bpp */
245 data = (l_uint8 *)pixdata + pixBpl * (height - 1);
246 for (i = 0; i < height; i++) {
247 memcpy(data, fdata, fdatabpl);
248 fdata += fdatabpl;
249 data -= pixBpl;
250 }
251 } else { /* 24 bpp file; 32 bpp pix
252 * Note: for bmp files, pel[0] is blue, pel[1] is green,
253 * and pel[2] is red. This is opposite to the storage
254 * in the pix, which puts the red pixel in the 0 byte,
255 * the green in the 1 byte and the blue in the 2 byte.
256 * Note also that all words are endian flipped after
257 * assignment on L_LITTLE_ENDIAN platforms.
258 *
259 * We can then make these assignments for little endians:
260 * SET_DATA_BYTE(pword, 1, pel[0]); blue
261 * SET_DATA_BYTE(pword, 2, pel[1]); green
262 * SET_DATA_BYTE(pword, 3, pel[2]); red
263 * This looks like:
264 * 3 (R) 2 (G) 1 (B) 0
265 * |-----------|------------|-----------|-----------|
266 * and after byte flipping:
267 * 3 2 (B) 1 (G) 0 (R)
268 * |-----------|------------|-----------|-----------|
269 *
270 * For big endians we set:
271 * SET_DATA_BYTE(pword, 2, pel[0]); blue
272 * SET_DATA_BYTE(pword, 1, pel[1]); green
273 * SET_DATA_BYTE(pword, 0, pel[2]); red
274 * This looks like:
275 * 0 (R) 1 (G) 2 (B) 3
276 * |-----------|------------|-----------|-----------|
277 * so in both cases we get the correct assignment in the PIX.
278 *
279 * Can we do a platform-independent assignment?
280 * Yes, set the bytes without using macros:
281 * *((l_uint8 *)pword) = pel[2]; red
282 * *((l_uint8 *)pword + 1) = pel[1]; green
283 * *((l_uint8 *)pword + 2) = pel[0]; blue
284 * For little endians, before flipping, this looks again like:
285 * 3 (R) 2 (G) 1 (B) 0
286 * |-----------|------------|-----------|-----------|
287 */
288 extrabytes = fdatabpl - 3 * width;
289 line = pixdata + pixWpl * (height - 1);
290 for (i = 0; i < height; i++) {
291 for (j = 0; j < width; j++) {
292 pword = line + j;
293 memcpy(&pel, fdata, 3);
294 fdata += 3;
295 *((l_uint8 *)pword + COLOR_RED) = pel[2];
296 *((l_uint8 *)pword + COLOR_GREEN) = pel[1];
297 *((l_uint8 *)pword + COLOR_BLUE) = pel[0];
298 }
299 if (extrabytes) {
300 for (k = 0; k < extrabytes; k++) {
301 memcpy(&pel, fdata, 1);
302 fdata++;
303 }
304 }
305 line -= pixWpl;
306 }
307 }
308
309 pixEndianByteSwap(pix);
310 if (height_neg)
311 pixFlipTB(pix, pix);
312
313 /* ----------------------------------------------
314 * The bmp colormap determines the values of black
315 * and white pixels for binary in the following way:
316 * (a) white = 0 [255], black = 1 [0]
317 * 255, 255, 255, 255, 0, 0, 0, 255
318 * (b) black = 0 [0], white = 1 [255]
319 * 0, 0, 0, 255, 255, 255, 255, 255
320 * We have no need for a 1 bpp pix with a colormap!
321 * Note: the alpha component here is 255 (opaque)
322 * ---------------------------------------------- */
323 if (depth == 1 && cmap) {
324 pix1 = pixRemoveColormap(pix, REMOVE_CMAP_TO_BINARY);
325 pixDestroy(&pix);
326 pix = pix1; /* rename */
327 }
328
329 return pix;
330 }
331
332
333 /*--------------------------------------------------------------*
334 * Write bmp *
335 *--------------------------------------------------------------*/
336 /*!
337 * \brief pixWriteStreamBmp()
338 *
339 * \param[in] fp file stream
340 * \param[in] pix all depths
341 * \return 0 if OK, 1 on error
342 */
343 l_int32
pixWriteStreamBmp(FILE * fp,PIX * pix)344 pixWriteStreamBmp(FILE *fp,
345 PIX *pix)
346 {
347 l_uint8 *data;
348 size_t size, nbytes;
349
350 PROCNAME("pixWriteStreamBmp");
351
352 if (!fp)
353 return ERROR_INT("stream not defined", procName, 1);
354 if (!pix)
355 return ERROR_INT("pix not defined", procName, 1);
356
357 pixWriteMemBmp(&data, &size, pix);
358 rewind(fp);
359 nbytes = fwrite(data, 1, size, fp);
360 free(data);
361 if (nbytes != size)
362 return ERROR_INT("Write error", procName, 1);
363 return 0;
364 }
365
366
367 /*!
368 * \brief pixWriteMemBmp()
369 *
370 * \param[out] pfdata data of bmp formatted image
371 * \param[out] pfsize size of returned data
372 * \param[in] pixs 1, 2, 4, 8, 16, 32 bpp
373 * \return 0 if OK, 1 on error
374 *
375 * <pre>
376 * Notes:
377 * (1) 2 bpp bmp files are not valid in the spec, and are
378 * written as 8 bpp.
379 * (2) pix with depth <= 8 bpp are written with a colormap.
380 * 16 bpp gray and 32 bpp rgb pix are written without a colormap.
381 * (3) The transparency component in an rgb pix is ignored.
382 * All 32 bpp pix have the bmp alpha component set to 255 (opaque).
383 * (4) The bmp colormap entries, RGBA_QUAD, are the same as
384 * the ones used for colormaps in leptonica. This allows
385 * a simple memcpy for bmp output.
386 * </pre>
387 */
388 l_int32
pixWriteMemBmp(l_uint8 ** pfdata,size_t * pfsize,PIX * pixs)389 pixWriteMemBmp(l_uint8 **pfdata,
390 size_t *pfsize,
391 PIX *pixs)
392 {
393 l_uint8 pel[4];
394 l_uint8 *cta = NULL; /* address of the bmp color table array */
395 l_uint8 *fdata, *data, *fmdata;
396 l_int32 cmaplen; /* number of bytes in the bmp colormap */
397 l_int32 ncolors, val, stepsize;
398 l_int32 w, h, d, fdepth, xres, yres;
399 l_int32 pixWpl, pixBpl, extrabytes, fBpl, fWpl, i, j, k;
400 l_int32 heapcm; /* extra copy of cta on the heap ? 1 : 0 */
401 l_uint32 offbytes, fimagebytes;
402 l_uint32 *line, *pword;
403 size_t fsize;
404 BMP_FH *bmpfh;
405 BMP_IH *bmpih;
406 PIX *pix;
407 PIXCMAP *cmap;
408 RGBA_QUAD *pquad;
409
410 PROCNAME("pixWriteMemBmp");
411
412 if (pfdata) *pfdata = NULL;
413 if (pfsize) *pfsize = 0;
414 if (!pfdata)
415 return ERROR_INT("&fdata not defined", procName, 1 );
416 if (!pfsize)
417 return ERROR_INT("&fsize not defined", procName, 1 );
418 if (!pixs)
419 return ERROR_INT("pixs not defined", procName, 1);
420
421 pixGetDimensions(pixs, &w, &h, &d);
422 if (d == 2) {
423 L_WARNING("2 bpp files can't be read; converting to 8 bpp\n", procName);
424 pix = pixConvert2To8(pixs, 0, 85, 170, 255, 1);
425 d = 8;
426 } else {
427 pix = pixCopy(NULL, pixs);
428 }
429 fdepth = (d == 32) ? 24 : d;
430
431 /* Resolution is given in pixels/meter */
432 xres = (l_int32)(39.37 * (l_float32)pixGetXRes(pix) + 0.5);
433 yres = (l_int32)(39.37 * (l_float32)pixGetYRes(pix) + 0.5);
434
435 pixWpl = pixGetWpl(pix);
436 pixBpl = 4 * pixWpl;
437 fWpl = (w * fdepth + 31) / 32;
438 fBpl = 4 * fWpl;
439 fimagebytes = h * fBpl;
440 if (fimagebytes > 4LL * L_MAX_ALLOWED_PIXELS) {
441 pixDestroy(&pix);
442 return ERROR_INT("image data is too large", procName, 1);
443 }
444
445 /* If not rgb or 16 bpp, the bmp data is required to have a colormap */
446 heapcm = 0;
447 if (d == 32 || d == 16) { /* 24 bpp rgb or 16 bpp: no colormap */
448 ncolors = 0;
449 cmaplen = 0;
450 } else if ((cmap = pixGetColormap(pix))) { /* existing colormap */
451 ncolors = pixcmapGetCount(cmap);
452 cmaplen = ncolors * sizeof(RGBA_QUAD);
453 cta = (l_uint8 *)cmap->array;
454 } else { /* no existing colormap; d <= 8; make a binary or gray one */
455 if (d == 1) {
456 cmaplen = sizeof(bwmap);
457 ncolors = 2;
458 cta = (l_uint8 *)bwmap;
459 } else { /* d = 2,4,8; use a grayscale output colormap */
460 ncolors = 1 << fdepth;
461 cmaplen = ncolors * sizeof(RGBA_QUAD);
462 heapcm = 1;
463 cta = (l_uint8 *)LEPT_CALLOC(cmaplen, 1);
464 stepsize = 255 / (ncolors - 1);
465 for (i = 0, val = 0, pquad = (RGBA_QUAD *)cta;
466 i < ncolors;
467 i++, val += stepsize, pquad++) {
468 pquad->blue = pquad->green = pquad->red = val;
469 pquad->alpha = 255; /* opaque */
470 }
471 }
472 }
473
474 #if DEBUG
475 {l_uint8 *pcmptr;
476 pcmptr = (l_uint8 *)pixGetColormap(pix)->array;
477 fprintf(stderr, "Pix colormap[0] = %c%c%c%d\n",
478 pcmptr[0], pcmptr[1], pcmptr[2], pcmptr[3]);
479 fprintf(stderr, "Pix colormap[1] = %c%c%c%d\n",
480 pcmptr[4], pcmptr[5], pcmptr[6], pcmptr[7]);
481 }
482 #endif /* DEBUG */
483
484 offbytes = BMP_FHBYTES + BMP_IHBYTES + cmaplen;
485 fsize = offbytes + fimagebytes;
486 fdata = (l_uint8 *)LEPT_CALLOC(fsize, 1);
487 *pfdata = fdata;
488 *pfsize = fsize;
489
490 /* Convert to little-endian and write the file header data */
491 bmpfh = (BMP_FH *)fdata;
492 bmpfh->bfType = convertOnBigEnd16(BMP_ID);
493 bmpfh->bfSize = convertOnBigEnd16(fsize & 0x0000ffff);
494 bmpfh->bfFill1 = convertOnBigEnd16((fsize >> 16) & 0x0000ffff);
495 bmpfh->bfOffBits = convertOnBigEnd16(offbytes & 0x0000ffff);
496 bmpfh->bfFill2 = convertOnBigEnd16((offbytes >> 16) & 0x0000ffff);
497
498 /* Convert to little-endian and write the info header data */
499 bmpih = (BMP_IH *)(fdata + BMP_FHBYTES);
500 bmpih->biSize = convertOnBigEnd32(BMP_IHBYTES);
501 bmpih->biWidth = convertOnBigEnd32(w);
502 bmpih->biHeight = convertOnBigEnd32(h);
503 bmpih->biPlanes = convertOnBigEnd16(1);
504 bmpih->biBitCount = convertOnBigEnd16(fdepth);
505 bmpih->biSizeImage = convertOnBigEnd32(fimagebytes);
506 bmpih->biXPelsPerMeter = convertOnBigEnd32(xres);
507 bmpih->biYPelsPerMeter = convertOnBigEnd32(yres);
508 bmpih->biClrUsed = convertOnBigEnd32(ncolors);
509 bmpih->biClrImportant = convertOnBigEnd32(ncolors);
510
511 /* Copy the colormap data and free the cta if necessary */
512 if (ncolors > 0) {
513 memcpy(fdata + BMP_FHBYTES + BMP_IHBYTES, cta, cmaplen);
514 if (heapcm) LEPT_FREE(cta);
515 }
516
517 /* When you write a binary image with a colormap
518 * that sets BLACK to 0, you must invert the data */
519 if (fdepth == 1 && cmap && ((l_uint8 *)(cmap->array))[0] == 0x0) {
520 pixInvert(pix, pix);
521 }
522
523 /* An endian byte swap is also required */
524 pixEndianByteSwap(pix);
525
526 /* Transfer the image data. Image origin for bmp is at lower right. */
527 fmdata = fdata + offbytes;
528 if (fdepth != 24) { /* typ 1 or 8 bpp */
529 data = (l_uint8 *)pixGetData(pix) + pixBpl * (h - 1);
530 for (i = 0; i < h; i++) {
531 memcpy(fmdata, data, fBpl);
532 data -= pixBpl;
533 fmdata += fBpl;
534 }
535 } else { /* 32 bpp pix; 24 bpp file
536 * See the comments in pixReadStreamBmp() to
537 * understand the logic behind the pixel ordering below.
538 * Note that we have again done an endian swap on
539 * little endian machines before arriving here, so that
540 * the bytes are ordered on both platforms as:
541 Red Green Blue --
542 |-----------|------------|-----------|-----------|
543 */
544 extrabytes = fBpl - 3 * w;
545 line = pixGetData(pix) + pixWpl * (h - 1);
546 for (i = 0; i < h; i++) {
547 for (j = 0; j < w; j++) {
548 pword = line + j;
549 pel[2] = *((l_uint8 *)pword + COLOR_RED);
550 pel[1] = *((l_uint8 *)pword + COLOR_GREEN);
551 pel[0] = *((l_uint8 *)pword + COLOR_BLUE);
552 memcpy(fmdata, &pel, 3);
553 fmdata += 3;
554 }
555 if (extrabytes) {
556 for (k = 0; k < extrabytes; k++) {
557 memcpy(fmdata, &pel, 1);
558 fmdata++;
559 }
560 }
561 line -= pixWpl;
562 }
563 }
564
565 pixDestroy(&pix);
566 return 0;
567 }
568
569 /* --------------------------------------------*/
570 #endif /* USE_BMPIO */
571