OSDN Git Service

ef23e70a3a44a624ff66173a62f143bd29000261
[putex/putex.git] / src / dvipdfmx-pu / src / bmpimage.c
1 /*  
2
3     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
4
5     Copyright (C) 2002-2012 by Jin-Hwan Cho and Shunsaku Hirata,
6     the dvipdfmx project team.
7     
8     Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
9
10     This program is free software; you can redistribute it and/or modify
11     it under the terms of the GNU General Public License as published by
12     the Free Software Foundation; either version 2 of the License, or
13     (at your option) any later version.
14     
15     This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     GNU General Public License for more details.
19     
20     You should have received a copy of the GNU General Public License
21     along with this program; if not, write to the Free Software
22     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
23 */
24
25 #if HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 /*
30  * BMP SUPPORT:
31  */
32
33 #include "system.h"
34 #include "error.h"
35 #include "mem.h"
36
37 #include "pdfobj.h"
38
39 #include "bmpimage.h"
40
41 #define DIB_FILE_HEADER_SIZE 14
42 #define DIB_CORE_HEADER_SIZE 14
43 #define DIB_INFO_HEADER_SIZE 40
44
45 #define DIB_COMPRESS_NONE 0
46 #define DIB_COMPRESS_RLE8 1
47 #define DIB_COMPRESS_RLE4 2
48
49 #define DIB_HEADER_SIZE_MAX (DIB_FILE_HEADER_SIZE+DIB_INFO_HEADER_SIZE)
50
51 static long read_raster_rle8 (unsigned char *data_ptr,
52                               long width, long height, FILE *fp);
53 static long read_raster_rle4 (unsigned char *data_ptr,
54                               long width, long height, FILE *fp);
55
56 int
57 check_for_bmp (FILE *fp)
58 {
59  unsigned char sigbytes[2];
60
61   if (!fp)
62     return 0;
63
64   rewind(fp);
65   if (fread(sigbytes, 1, sizeof(sigbytes), fp) != sizeof(sigbytes) ||
66       sigbytes[0] != 'B' || sigbytes[1] != 'M')
67     return 0;
68   else
69     return 1;
70   
71   return 0;
72 }
73
74 int
75 bmp_include_image (pdf_ximage *ximage, FILE *fp)
76 {
77   pdf_obj *stream, *stream_dict, *colorspace;
78   ximage_info info;
79   unsigned char  buf[DIB_HEADER_SIZE_MAX+4];
80   unsigned char *p;
81   long offset, hsize, compression;
82   long psize; /* Bytes per palette color: 3 for OS2, 4 for Win */
83   unsigned short bit_count; /* Bits per pix */
84   int  num_palette, flip;
85   int  i;
86
87   pdf_ximage_init_image_info(&info);
88
89   stream = stream_dict = colorspace = NULL;
90   p = buf;
91
92   rewind(fp);
93   if (fread(buf, 1, DIB_FILE_HEADER_SIZE + 4, fp)
94       != DIB_FILE_HEADER_SIZE + 4) {
95     WARN("Could not read BMP file header...");
96   }
97
98   if (p[0] != 'B' || p[1] != 'M') {
99     WARN("File not starting with \'B\' \'M\'... Not a BMP file?");
100     return -1;
101   }
102   p += 2;
103
104 #define ULONG_LE(b)  ((b)[0] + ((b)[1] << 8) +\
105                       ((b)[2] << 16) + ((b)[3] << 24))
106 #define USHORT_LE(b) ((b)[0] + ((b)[1] << 8))
107
108   /* fsize  = ULONG_LE(p); */ p += 4;
109   if (ULONG_LE(p) != 0) {
110     WARN("Not a BMP file???");
111     return -1;
112   }
113   p += 4;
114   offset = ULONG_LE(p); p += 4;
115
116   /* info header */
117   hsize  = ULONG_LE(p); p += 4;
118   if (fread(p, sizeof(char), hsize - 4, fp) != hsize - 4) {
119     WARN("Could not read BMP file header...");
120     return -1;
121   }
122   flip = 1;
123   if (hsize == DIB_CORE_HEADER_SIZE) {
124     info.width  = USHORT_LE(p); p += 2;
125     info.height = USHORT_LE(p); p += 2;
126     if (USHORT_LE(p) != 1) {
127       WARN("Unknown bcPlanes value in BMP COREHEADER.");
128       return -1;
129     }
130     p += 2;
131     bit_count   = USHORT_LE(p); p += 2;
132     compression = DIB_COMPRESS_NONE;
133     psize = 3;
134   } else if (hsize == DIB_INFO_HEADER_SIZE) {
135     info.width  = ULONG_LE(p);  p += 4;
136     info.height = ULONG_LE(p);  p += 4;
137     if (USHORT_LE(p) != 1) {
138       WARN("Unknown biPlanes value in BMP INFOHEADER.");
139       return -1;
140     }
141     p += 2;
142     bit_count   = USHORT_LE(p); p += 2;
143     compression = ULONG_LE(p);  p += 4;
144     if (info.height < 0) {
145       info.height = -info.height;
146       flip = 0;
147     }
148     psize = 4;
149   } else {
150     WARN("Unknown BMP header type.");
151     return -1;
152   }
153
154   if (bit_count < 24) {
155     if (bit_count != 1 &&
156         bit_count != 4 && bit_count != 8) {
157       WARN("Unsupported palette size: %ld", bit_count);
158       return -1;
159     }
160     num_palette = (offset - hsize - DIB_FILE_HEADER_SIZE) / psize;
161     info.bits_per_component = bit_count;
162     info.num_components = 1;
163   } else if (bit_count == 24) { /* full color */
164     num_palette = 1; /* dummy */
165     info.bits_per_component = 8;
166     info.num_components = 3;
167   } else {
168     WARN("Unkown BMP bitCount: %ld", bit_count);
169     return -1;
170   }
171
172   if (info.width == 0 || info.height == 0 || num_palette < 1) {
173     WARN("Invalid BMP file: width=%ld, height=%ld, #palette=%d",
174          info.width, info.height, num_palette);
175     return -1;
176   }
177
178   stream      = pdf_new_stream(STREAM_COMPRESS);
179   stream_dict = pdf_stream_dict(stream);
180
181   if (bit_count < 24) {
182     pdf_obj *lookup;
183     unsigned char *palette, bgrq[4];
184
185     palette = NEW(num_palette*3+1, unsigned char);
186     for (i = 0; i < num_palette; i++) {
187       if (fread(bgrq, 1,  psize, fp) != psize) {
188         WARN("Reading file failed...");
189         RELEASE(palette);
190         return -1;
191       }
192       /* BGR data */
193       palette[3*i  ] = bgrq[2];
194       palette[3*i+1] = bgrq[1];
195       palette[3*i+2] = bgrq[0];
196     }
197     lookup = pdf_new_string(palette, num_palette*3);
198     RELEASE(palette);
199
200     colorspace = pdf_new_array();
201     pdf_add_array(colorspace, pdf_new_name("Indexed"));
202     pdf_add_array(colorspace, pdf_new_name("DeviceRGB"));
203     pdf_add_array(colorspace, pdf_new_number(num_palette-1));
204     pdf_add_array(colorspace, lookup);
205   } else {
206     colorspace = pdf_new_name("DeviceRGB");
207   }
208   pdf_add_dict(stream_dict, pdf_new_name("ColorSpace"), colorspace);
209
210   /* Raster data of BMP is four-byte aligned. */
211   {
212     long rowbytes, n;
213     unsigned char *stream_data_ptr = NULL;
214
215     rowbytes = (info.width * bit_count + 7) / 8;
216
217     seek_absolute(fp, offset);
218     if (compression == DIB_COMPRESS_NONE) {
219       long dib_rowbytes;
220       int  padding;
221
222       padding = (rowbytes % 4) ? 4 - (rowbytes % 4) : 0;
223       dib_rowbytes = rowbytes + padding;
224       stream_data_ptr = NEW(rowbytes*info.height + padding,
225                             unsigned char);
226       for (n = 0; n < info.height; n++) {
227         p = stream_data_ptr + n * rowbytes;
228         if (fread(p, 1, dib_rowbytes, fp) != dib_rowbytes) {
229           WARN("Reading BMP raster data failed...");
230           pdf_release_obj(stream);
231           RELEASE(stream_data_ptr);
232           return -1;
233         }
234       }
235     } else if (compression == DIB_COMPRESS_RLE8) {
236       stream_data_ptr = NEW(rowbytes*info.height, unsigned char);
237       if (read_raster_rle8(stream_data_ptr,
238                            info.width, info.height, fp) < 0) {
239         WARN("Reading BMP raster data failed...");
240         pdf_release_obj(stream);
241         RELEASE(stream_data_ptr);
242         return -1;
243       }
244     } else if (compression == DIB_COMPRESS_RLE4) {
245       stream_data_ptr = NEW(rowbytes*info.height, unsigned char);
246       if (read_raster_rle4(stream_data_ptr,
247                            info.width, info.height, fp) < 0) {
248         WARN("Reading BMP raster data failed...");
249         pdf_release_obj(stream);
250         RELEASE(stream_data_ptr);
251         return -1;
252       }
253     } else {
254       pdf_release_obj(stream);
255       return -1;
256     }
257
258     /* gbr --> rgb */
259     if (bit_count == 24) {
260       for (n = 0; n < info.width * info.height * 3; n += 3) {
261         unsigned char g;
262         g = stream_data_ptr[n];
263         stream_data_ptr[n  ] = stream_data_ptr[n+2];
264         stream_data_ptr[n+2] = g;
265       }
266     }
267
268     if (flip) {
269       for (n = info.height - 1; n >= 0; n--) {
270         p = stream_data_ptr + n * rowbytes;
271         pdf_add_stream(stream, p, rowbytes);
272       }
273     } else {
274       pdf_add_stream(stream, stream_data_ptr, rowbytes*info.height);
275     }
276     RELEASE(stream_data_ptr);
277   }
278
279   pdf_ximage_set_image(ximage, &info, stream);
280
281   return 0;
282 }
283
284 static long
285 read_raster_rle8 (unsigned char *data_ptr,
286                   long width, long height, FILE *fp)
287 {
288   long count = 0;
289   unsigned char *p, b0, b1;
290   long h, v, rowbytes;
291   int  eol, eoi;
292
293   p = data_ptr;
294   rowbytes = width;
295   memset(data_ptr, 0, rowbytes*height);
296   for (v = 0, eoi = 0; v < height && !eoi; v++) {
297     for (h = 0, eol = 0; h < width && !eol; ) {
298
299       b0 = get_unsigned_byte(fp);
300       b1 = get_unsigned_byte(fp);
301       count += 2;
302
303       p = data_ptr + v * rowbytes + h;
304
305       if (b0 == 0x00) {
306         switch (b1) {
307         case 0x00: /* EOL */
308           eol = 1;
309           break;
310         case 0x01: /* EOI */
311           eoi = 1;
312           break;
313         case 0x02:
314           h += get_unsigned_byte(fp);
315           v += get_unsigned_byte(fp);
316           count += 2;
317           break;
318         default:
319           h += b1;
320           if (h > width) {
321             WARN("RLE decode failed...");
322             return -1;
323           }
324           if (fread(p, 1, b1, fp) != b1)
325             return -1;
326           count += b1;
327           if (b1 % 2) {
328             get_unsigned_byte(fp);
329             count++;
330           }
331           break;
332         }
333       } else {
334         h += b0;
335         if (h > width) {
336           WARN("RLE decode failed...");
337           return -1;
338         }
339         memset(p, b1, b0);
340       }
341     }
342
343     /* Check for EOL and EOI marker */
344     if (!eol && !eoi) {
345       b0 = get_unsigned_byte(fp);
346       b1 = get_unsigned_byte(fp);
347       if (b0 != 0x00) {
348         WARN("RLE decode failed...");
349         return -1;
350       } else if (b1 == 0x01) {
351         eoi = 1;
352       } else if (b1 != 0x00) {
353         WARN("RLE decode failed...");
354         return -1;
355       }
356     }
357
358     /* next row ... */
359   }
360
361   return count;
362 }
363
364 static long
365 read_raster_rle4 (unsigned char *data_ptr,
366                   long width, long height, FILE *fp)
367 {
368   long count = 0;
369   unsigned char *p, b0, b1, b;
370   long h, v, rowbytes;
371   int  eol, eoi, i, nbytes;
372
373   p = data_ptr;
374   rowbytes = (width + 1) / 2;
375   memset(data_ptr, 0, rowbytes*height);
376   for (v = 0, eoi = 0; v < height && !eoi; v++) {
377     for (h = 0, eol = 0; h < width && !eol; ) {
378
379       b0 = get_unsigned_byte(fp);
380       b1 = get_unsigned_byte(fp);
381       count += 2;
382
383       p  = data_ptr + v * rowbytes + (h / 2);
384       if (b0 == 0x00) {
385         switch (b1) {
386         case 0x00: /* EOL */
387           eol = 1;
388           break;
389         case 0x01: /* EOI */
390           eoi = 1;
391           break;
392         case 0x02:
393           h += get_unsigned_byte(fp);
394           v += get_unsigned_byte(fp);
395           count += 2;
396           break;
397         default:
398           if (h + b1 > width) {
399             WARN("RLE decode failed...");
400             return -1;
401           }
402           nbytes = (b1 + 1)/2;
403           if (h % 2) { /* starting at hi-nib */
404             for (i = 0; i < nbytes; i++) {
405               b = get_unsigned_byte(fp);
406               *p++ |= (b >> 4) & 0x0f;
407               *p    = (b << 4) & 0xf0;
408             }
409           } else {
410             if (fread(p, 1, nbytes, fp) != nbytes) {
411               return -1;
412             }
413           }
414           h     += b1;
415           count += nbytes;
416           if (nbytes % 2) {
417             get_unsigned_byte(fp);
418             count++;
419           }
420           break;
421         }
422       } else {
423         if (h + b0 > width) {
424           WARN("RLE decode failed...");
425           return -1;
426         }
427         if (h % 2) {
428           *p++ = (b1 >> 4) & 0x0f;
429           b1   = ((b1 << 4) & 0xf0)|((b1 >> 4) & 0x0f);
430           b0--;
431           h++;
432         }
433         nbytes = (b0 + 1)/2;
434         memset(p, b1, nbytes);
435         h += b0;
436         if (h % 2)
437           p[nbytes-1] &= 0xf0;
438       }
439     }
440
441     /* Check for EOL and EOI marker */
442     if (!eol && !eoi) {
443       b0 = get_unsigned_byte(fp);
444       b1 = get_unsigned_byte(fp);
445       if (b0 != 0x00) {
446         WARN("No EOL/EOI marker. RLE decode failed...");
447         return -1;
448       } else if (b1 == 0x01) {
449         eoi = 1;
450       } else if (b1 != 0x00) {
451         WARN("No EOL/EOI marker. RLE decode failed...");
452         return -1;
453       }
454     }
455
456     /* next row ... */
457   }
458
459   return count;
460 }