1/*---------------------------------------------------------------------------*
2 |              PDFlib - A library for generating PDF on the fly             |
3 +---------------------------------------------------------------------------+
4 | Copyright (c) 1997-2004 Thomas Merz and PDFlib GmbH. All rights reserved. |
5 +---------------------------------------------------------------------------+
6 |                                                                           |
7 |    This software is subject to the PDFlib license. It is NOT in the       |
8 |    public domain. Extended versions and commercial licenses are           |
9 |    available, please check http://www.pdflib.com.                         |
10 |                                                                           |
11 *---------------------------------------------------------------------------*/
12
13/* $Id: p_bmp.c 14574 2005-10-29 16:27:43Z bonefish $
14 *
15 * BMP processing for PDFlib
16 *
17 */
18
19#include "p_intern.h"
20#include "p_image.h"
21
22#ifndef PDF_BMP_SUPPORTED
23
24pdc_bool
25pdf_is_BMP_file(PDF *p, pdc_file *fp)
26{
27    (void) p;
28    (void) fp;
29
30    return pdc_false;
31}
32
33int
34pdf_process_BMP_data(
35    PDF *p,
36    int imageslot)
37{
38    (void) imageslot;
39
40    pdc_warning(p->pdc, PDF_E_UNSUPP_IMAGE, "BMP", 0, 0, 0);
41    return -1;
42}
43
44#else  /* !PDF_BMP_SUPPORTED */
45
46/* for documentation only */
47#if 0
48
49/* BMP file header structure */
50typedef struct
51{
52    pdc_ushort  bfType;           /* Magic number for file */
53    pdc_ulong   bfSize;           /* Size of file */
54    pdc_ushort  bfReserved1;      /* Reserved */
55    pdc_ushort  bfReserved2;      /* ... */
56    pdc_ulong   bfOffBits;        /* Offset to bitmap data */
57}
58BITMAPFILEHEADER;
59
60/* BMP file info structure */
61typedef struct
62{
63    pdc_ulong   biSize;           /* Size of info header */
64    pdc_long    biWidth;          /* Width of image */
65    pdc_long    biHeight;         /* Height of image */
66    pdc_ushort  biPlanes;         /* Number of color planes */
67    pdc_ushort  biBitCount;       /* Number of bits per pixel */
68    pdc_ulong   biCompression;    /* Type of compression to use */
69    pdc_ulong   biSizeImage;      /* Size of image data */
70    pdc_long    biXPelsPerMeter;  /* X pixels per meter */
71    pdc_long    biYPelsPerMeter;  /* Y pixels per meter */
72    pdc_ulong   biClrUsed;        /* Number of colors used */
73    pdc_ulong   biClrImportant;   /* Number of important colors */
74}
75BITMAPINFOHEADER;
76
77#endif
78
79#define PDF_GET_BYTE(pos)   *pos,                   pos += sizeof(pdc_byte)
80#define PDF_GET_SHORT(pos)  pdc_get_le_short(pos),  pos += sizeof(pdc_short)
81#define PDF_GET_USHORT(pos) pdc_get_le_ushort(pos), pos += sizeof(pdc_ushort)
82#define PDF_GET_LONG(pos)   pdc_get_le_long(pos),   pos += sizeof(pdc_long)
83#define PDF_GET_ULONG(pos)  pdc_get_le_ulong(pos),  pos += sizeof(pdc_ulong)
84
85#define PDF_BMP_STRING     "\102\115"   /* "BM" */
86
87#define PDF_BMP_RGB                 0   /* No compression - straight BGR data */
88#define PDF_BMP_RLE8                1   /* 8-bit run-length compression */
89#define PDF_BMP_RLE4                2   /* 4-bit run-length compression */
90#define PDF_BMP_BITFIELDS           3   /* RGB bitmap with RGB masks */
91
92#define PDF_BMP_FILE_HEADSIZE      14   /* File header size */
93#define PDF_BMP_INFO_HEAD2SIZE     12   /* Info header size BMP Version 2 */
94#define PDF_BMP_INFO_HEAD3SIZE     40   /* Info header size BMP Version 3 */
95#define PDF_BMP_INFO_HEAD4SIZE    108   /* Info header size BMP Version 4 */
96
97static void
98pdf_data_source_BMP_init(PDF *p, PDF_data_source *src)
99{
100    static const char *fn = "pdf_data_source_BMP_init";
101    pdf_image *image = (pdf_image *) src->private_data;
102
103    src->buffer_length = image->info.bmp.rowbytes_pdf;
104    src->buffer_start = (pdc_byte *)
105        pdc_calloc(p->pdc, image->info.bmp.rowbytes_pad, fn);
106    src->bytes_available = image->info.bmp.rowbytes_pdf;
107    src->next_byte = src->buffer_start;
108}
109
110static pdc_bool
111pdf_data_source_BMP_fill(PDF *p, PDF_data_source *src)
112{
113    pdf_image *image = (pdf_image *) src->private_data;
114    pdc_byte c;
115    int i;
116
117    /* No compression */
118    if (image->info.bmp.compression == PDF_BMP_RGB)
119    {
120        size_t avail;
121
122        /* Read 1 padded row from file */
123        avail = pdc_fread(src->buffer_start, 1, image->info.bmp.rowbytes_pad,
124                          image->fp);
125        if (avail > 0)
126        {
127            /* Fill up remaining bytes */
128            if (avail < image->info.bmp.rowbytes_pad)
129            {
130                for (i = (int) avail; i < (int) src->buffer_length; i++)
131                    src->buffer_start[i] = 0;
132            }
133
134            /* Swap red and blue */
135            if (image->colorspace == DeviceRGB)
136            {
137                for (i = 0; i < (int) src->bytes_available; i += 3)
138                {
139                    c = src->buffer_start[i];
140                    src->buffer_start[i] = src->buffer_start[i + 2];
141                    src->buffer_start[i + 2] = c;
142                }
143            }
144        }
145        else
146        {
147            src->bytes_available = 0;
148        }
149    }
150
151    /* Compression methods RLE8 and RLE4 */
152    else
153    {
154        int col = 0, fnibble = 1;
155        pdc_byte cc, ccc, cn[2], ccn;
156
157        if (image->info.bmp.pos < image->info.bmp.end)
158        {
159            if (image->info.bmp.skiprows)
160            {
161                for (; col < (int) image->info.bmp.rowbytes; col++)
162                    src->buffer_start[col] = 0;
163                image->info.bmp.skiprows--;
164            }
165            else
166            {
167                while (1)
168                {
169                    c = *image->info.bmp.pos;
170                    image->info.bmp.pos++;
171                    if (image->info.bmp.pos >= image->info.bmp.end)
172                        goto PDF_BMP_CORRUPT;
173                    cc = *image->info.bmp.pos;
174
175                    if (c != 0)
176                    {
177                        /* Repeat c time pixel value */
178                        if (image->info.bmp.compression == PDF_BMP_RLE8)
179                        {
180                            for (i = 0; i < (int) c; i++)
181                            {
182                                if (col >= (int) image->info.bmp.rowbytes)
183                                    goto PDF_BMP_CORRUPT;
184                                src->buffer_start[col] = cc;
185                                col++;
186                            }
187                        }
188                        else
189                        {
190                            cn[0] = (pdc_byte) ((cc & 0xF0) >> 4);
191                            cn[1] = (pdc_byte) (cc & 0x0F);
192                            for (i = 0; i < (int) c; i++)
193                            {
194                                if (col >= (int) image->info.bmp.rowbytes)
195                                    goto PDF_BMP_CORRUPT;
196                                ccn = cn[i%2];
197                                if (fnibble)
198                                {
199                                    fnibble = 0;
200                                    src->buffer_start[col] =
201                                        (pdc_byte) (ccn << 4);
202                                }
203                                else
204                                {
205                                    fnibble = 1;
206                                    src->buffer_start[col] |= ccn;
207                                    col++;
208                                }
209                            }
210                        }
211                    }
212                    else if (cc > 2)
213                    {
214                        /* cc different pixel values */
215                        if (image->info.bmp.compression == PDF_BMP_RLE8)
216                        {
217                            for (i = 0; i < (int) cc; i++)
218                            {
219                                image->info.bmp.pos++;
220                                if (image->info.bmp.pos >= image->info.bmp.end)
221                                    goto PDF_BMP_CORRUPT;
222                                if (col >= (int) image->info.bmp.rowbytes)
223                                    goto PDF_BMP_CORRUPT;
224                                src->buffer_start[col] = *image->info.bmp.pos;
225                                col++;
226                            }
227                        }
228                        else
229                        {
230                            for (i = 0; i < (int) cc; i++)
231                            {
232                                if (!(i%2))
233                                {
234                                    image->info.bmp.pos++;
235                                    if (image->info.bmp.pos >=
236                                        image->info.bmp.end)
237                                        goto PDF_BMP_CORRUPT;
238                                    ccc = *image->info.bmp.pos;
239                                    cn[0] = (pdc_byte) ((ccc & 0xF0) >> 4);
240                                    cn[1] = (pdc_byte) (ccc & 0x0F);
241                                }
242                                if (col >= (int) image->info.bmp.rowbytes)
243                                    goto PDF_BMP_CORRUPT;
244                                ccn = cn[i%2];
245                                if (fnibble)
246                                {
247                                    fnibble = 0;
248                                    src->buffer_start[col] =
249                                        (pdc_byte) (ccn << 4);
250                                }
251                                else
252                                {
253                                    fnibble = 1;
254                                    src->buffer_start[col] |= ccn;
255                                    col++;
256                                }
257                            }
258                            if (cc % 2) cc++;
259                            cc /= 2;
260                        }
261
262                        /* Odd number of bytes */
263                        if (cc % 2)
264                            image->info.bmp.pos++;
265                    }
266                    else if (cc < 2)
267                    {
268                        /* End of scan line or end of bitmap data*/
269                        for (; col < (int) image->info.bmp.rowbytes; col++)
270                            src->buffer_start[col] = 0;
271                    }
272                    else if (cc == 2)
273                    {
274                        int cola;
275
276                        /* Run offset marker */
277                        if (image->info.bmp.pos >= image->info.bmp.end - 1)
278                            goto PDF_BMP_CORRUPT;
279                        image->info.bmp.pos++;
280                        c = *image->info.bmp.pos;
281                        image->info.bmp.pos++;
282                        cc = *image->info.bmp.pos;
283
284                        /* Fill current row */
285                        cola = col;
286                        for (; col < (int) image->info.bmp.rowbytes; col++)
287                            src->buffer_start[col] = 0;
288                        if (col - cola != (int) c)
289                            goto PDF_BMP_CORRUPT;
290
291                        /* Number of rows to be skipped */
292                        image->info.bmp.skiprows = (size_t) cc;
293                    }
294
295                    image->info.bmp.pos++;
296                    if (col >= (int) image->info.bmp.rowbytes)
297                    {
298                        /* Skip end of scan line marker */
299                        if (image->info.bmp.pos < image->info.bmp.end - 1)
300                        {
301                            c = *image->info.bmp.pos;
302                            cc = *(image->info.bmp.pos + 1);
303                            if(cc == 0 && cc <= 1)
304                                image->info.bmp.pos += 2;
305                        }
306                        break;
307                    }
308                }
309            }
310        }
311        else
312        {
313            src->bytes_available = 0;
314        }
315    }
316
317    return (src->bytes_available ? pdc_true : pdc_false);
318
319    PDF_BMP_CORRUPT:
320    pdc_error(p->pdc, PDF_E_IMAGE_CORRUPT, "BMP",
321              pdc_errprintf(p->pdc, "%s", image->filename), 0, 0);
322    src->bytes_available = 0;
323    return pdc_false;
324}
325
326static void
327pdf_data_source_BMP_terminate(PDF *p, PDF_data_source *src)
328{
329    pdf_image *image = (pdf_image *) src->private_data;
330
331    pdc_free(p->pdc, (void *) src->buffer_start);
332    if (image->info.bmp.bitmap != NULL)
333        pdc_free(p->pdc, (void *) image->info.bmp.bitmap);
334}
335
336pdc_bool
337pdf_is_BMP_file(PDF *p, pdc_file *fp)
338{
339    pdc_byte buf[2];
340
341    (void) p;
342
343    if (pdc_fread(buf, 1, 2, fp) < 2 ||
344        strncmp((const char *) buf, PDF_BMP_STRING, 2) != 0)
345    {
346        pdc_fseek(fp, 0L, SEEK_SET);
347        return pdc_false;
348    }
349    return pdc_true;
350}
351
352int
353pdf_process_BMP_data(
354    PDF *p,
355    int imageslot)
356{
357    static const char *fn = "pdf_process_BMP_data";
358    pdc_byte buf[256], *pos, *cmap, bdummy;
359    pdf_image *image = &p->images[imageslot];
360    pdc_file *fp = image->fp;
361    pdc_ulong uldummy, infosize = 0, offras = 0, planes = 0, bitmapsize = 0;
362    pdc_ulong ncolors = 0, importcolors = 0, compression = PDF_BMP_RGB;
363    pdc_ushort usdummy, bpp = 0;
364    pdc_long width = 0, height = 0, dpi_x = 0, dpi_y = 0;
365    size_t nbytes;
366    pdf_colorspace cs;
367    pdf_colormap colormap;
368    int i, slot, colsize = 0, errcode = 0;
369
370    /* Error reading magic number or not a BMP file */
371    if (pdf_is_BMP_file(p, image->fp) == pdc_false)
372    {
373        errcode = PDC_E_IO_BADFORMAT;
374        goto PDF_BMP_ERROR;
375    }
376
377    /* read file header without FileType field + */
378    /* Size field of info header */
379    pos = &buf[2];
380    nbytes = PDF_BMP_FILE_HEADSIZE - 2 + 4;
381    if (!PDC_OK_FREAD(fp, pos, nbytes))
382    {
383        errcode = PDF_E_IMAGE_CORRUPT;
384        goto PDF_BMP_ERROR;
385    }
386    uldummy = PDF_GET_ULONG(pos);
387    usdummy = PDF_GET_USHORT(pos);
388    usdummy = PDF_GET_USHORT(pos);
389    offras = PDF_GET_ULONG(pos);
390    infosize = PDF_GET_ULONG(pos);
391
392    /* no support of later version than 3 */
393    if (infosize != PDF_BMP_INFO_HEAD2SIZE &&
394        infosize != PDF_BMP_INFO_HEAD3SIZE)
395    {
396        errcode = PDF_E_BMP_VERSUNSUPP;
397        goto PDF_BMP_ERROR;
398    }
399
400    /* info header */
401    pos = buf;
402    nbytes = infosize - 4;
403    if (!PDC_OK_FREAD(fp, pos, nbytes))
404    {
405        errcode = PDF_E_IMAGE_CORRUPT;
406        goto PDF_BMP_ERROR;
407    }
408    if (infosize == PDF_BMP_INFO_HEAD2SIZE)
409    {
410        width = PDF_GET_SHORT(pos);
411        height = PDF_GET_SHORT(pos);
412        planes = PDF_GET_USHORT(pos);
413        bpp = PDF_GET_USHORT(pos);
414        colsize = 3;
415    }
416    else if (infosize == PDF_BMP_INFO_HEAD3SIZE)
417    {
418        width = PDF_GET_LONG(pos);
419        height = PDF_GET_LONG(pos);
420        planes = PDF_GET_USHORT(pos);
421        bpp = PDF_GET_USHORT(pos);
422        compression = PDF_GET_ULONG(pos);
423        bitmapsize = PDF_GET_ULONG(pos);
424        dpi_x = PDF_GET_LONG(pos);
425        dpi_y = PDF_GET_LONG(pos);
426        ncolors = PDF_GET_ULONG(pos);
427        importcolors = PDF_GET_ULONG(pos);
428        colsize = 4;
429    }
430
431    /* only uncompressed BMP images */
432    if (compression > PDF_BMP_RLE4)
433    {
434        errcode = PDF_E_BMP_COMPUNSUPP;
435        goto PDF_BMP_ERROR;
436    }
437    image->bpc = bpp;
438    image->width = (float) width;
439    image->height = (float) -height;
440    image->dpi_x = (float) (PDC_INCH2METER * dpi_x);
441    image->dpi_y = (float) (PDC_INCH2METER * dpi_y);
442
443    /* color map only for bpp = 1, 4, 8 */
444    if (bpp < 16)
445    {
446        if (!ncolors)
447            ncolors = (pdc_ulong) (1 << bpp);
448        if (ncolors > (offras - PDF_BMP_FILE_HEADSIZE - infosize) / colsize)
449        {
450            errcode = PDF_E_IMAGE_CORRUPT;
451            goto PDF_BMP_ERROR;
452        }
453
454        /* allocate and read color map */
455        nbytes = colsize * ncolors;
456        cmap = (pdc_byte *) pdc_malloc(p->pdc, nbytes, fn);
457        if (!PDC_OK_FREAD(fp, cmap, nbytes))
458        {
459            errcode = PDF_E_IMAGE_CORRUPT;
460            goto PDF_BMP_ERROR;
461        }
462
463        /* set color map (bgr) */
464        pos = cmap;
465        for (i = 0; i < (int) ncolors; i++)
466        {
467            colormap[i][2] = PDF_GET_BYTE(pos);
468            colormap[i][1] = PDF_GET_BYTE(pos);
469            colormap[i][0] = PDF_GET_BYTE(pos);
470            if (infosize == PDF_BMP_INFO_HEAD3SIZE)
471            {
472                bdummy = PDF_GET_BYTE(pos);
473            }
474        }
475        pdc_free(p->pdc, cmap);
476
477        image->components = 1;
478
479	    cs.type = Indexed;
480	    cs.val.indexed.base = DeviceRGB;
481	    cs.val.indexed.palette_size = (int) ncolors;
482	    cs.val.indexed.colormap = &colormap;
483	    cs.val.indexed.colormap_id = PDC_BAD_ID;
484	    slot = pdf_add_colorspace(p, &cs, pdc_false);
485
486	    image->colorspace = (pdf_colorspacetype) slot;
487
488
489    }
490    else
491    {
492        image->colorspace = DeviceRGB;
493        image->components = 3;
494        image->bpc = 8;
495    }
496
497    if (image->imagemask)
498    {
499	if (image->components != 1) {
500	    errcode = PDF_E_IMAGE_BADMASK;
501	    goto PDF_BMP_ERROR;
502	}
503
504        if (p->compatibility <= PDC_1_3) {
505            if (image->components != 1 || image->bpc != 1) {
506                errcode = PDF_E_IMAGE_MASK1BIT13;
507                goto PDF_BMP_ERROR;
508            }
509        } else if (image->bpc > 1) {
510            /* images with more than one bit will be written as /SMask,
511             * and don't require an /ImageMask entry.
512             */
513            image->imagemask = pdc_false;
514        }
515        image->colorspace = DeviceGray;
516    }
517
518
519    /* we invert this flag later */
520    if (image->ignoremask)
521        image->transparent = pdc_true;
522
523    /* numbers of bytes per row  */
524    image->info.bmp.rowbytes_pdf = (size_t) ((bpp * width + 7) / 8);
525    if (bpp == 4)
526        image->info.bmp.rowbytes = image->info.bmp.rowbytes_pdf;
527    else
528        image->info.bmp.rowbytes = (size_t) ((bpp * width) / 8);
529    image->info.bmp.rowbytes_pad = (size_t) (4 * ((bpp * width + 31) / 32));
530    image->info.bmp.compression = compression;
531    image->info.bmp.skiprows = 0;
532    image->info.bmp.bitmap = NULL;
533
534    /* read whole bitmap */
535    if (image->info.bmp.compression != PDF_BMP_RGB)
536    {
537        image->info.bmp.bitmap =
538            (pdc_byte *) pdc_malloc(p->pdc, bitmapsize, fn);
539        if (!PDC_OK_FREAD(fp, image->info.bmp.bitmap, bitmapsize))
540        {
541            pdc_free(p->pdc, (void *) image->info.bmp.bitmap);
542            errcode = PDF_E_IMAGE_CORRUPT;
543            goto PDF_BMP_ERROR;
544        }
545        image->info.bmp.pos = image->info.bmp.bitmap;
546        image->info.bmp.end = image->info.bmp.bitmap + bitmapsize;
547    }
548
549    /* offset bitmap data */
550    pdc_fseek(image->fp, (pdc_long) offras, SEEK_SET);
551
552    /* put image data */
553    image->src.init = pdf_data_source_BMP_init;
554    image->src.fill = pdf_data_source_BMP_fill;
555    image->src.terminate = pdf_data_source_BMP_terminate;
556    image->src.private_data  = (void *) image;
557
558    image->use_raw = pdc_false;
559    image->in_use = pdc_true;
560
561    pdf_put_image(p, imageslot, pdc_true);
562
563    return imageslot;
564
565    PDF_BMP_ERROR:
566    {
567        const char *stemp = pdc_errprintf(p->pdc, "%s", image->filename);
568        switch (errcode)
569        {
570            case PDF_E_IMAGE_MASK1BIT13:
571            case PDF_E_BMP_VERSUNSUPP:
572            case PDF_E_BMP_COMPUNSUPP:
573            case PDF_E_IMAGE_BADMASK:
574		pdc_set_errmsg(p->pdc, errcode, stemp, 0, 0, 0);
575		break;
576
577            case PDC_E_IO_BADFORMAT:
578		pdc_set_errmsg(p->pdc, errcode, stemp, "BMP", 0, 0);
579		break;
580
581            case PDF_E_IMAGE_CORRUPT:
582		pdc_set_errmsg(p->pdc, errcode, "BMP", stemp, 0, 0);
583		break;
584
585	    case 0: 		/* error code and message already set */
586		break;
587        }
588    }
589
590    if (image->verbose)
591	pdc_error(p->pdc, -1, 0, 0, 0, 0);
592
593    return -1;
594}
595
596#endif /* PDF_BMP_SUPPORTED */
597
598