3 This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
5 Copyright (C) 2002-2012 by Jin-Hwan Cho and Shunsaku Hirata,
6 the dvipdfmx project team.
8 Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
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.
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.
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.
41 #define DIB_FILE_HEADER_SIZE 14
42 #define DIB_CORE_HEADER_SIZE 14
43 #define DIB_INFO_HEADER_SIZE 40
45 #define DIB_COMPRESS_NONE 0
46 #define DIB_COMPRESS_RLE8 1
47 #define DIB_COMPRESS_RLE4 2
49 #define DIB_HEADER_SIZE_MAX (DIB_FILE_HEADER_SIZE+DIB_INFO_HEADER_SIZE)
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);
57 check_for_bmp (FILE *fp)
59 unsigned char sigbytes[2];
65 if (fread(sigbytes, 1, sizeof(sigbytes), fp) != sizeof(sigbytes) ||
66 sigbytes[0] != 'B' || sigbytes[1] != 'M')
75 bmp_include_image (pdf_ximage *ximage, FILE *fp)
77 pdf_obj *stream, *stream_dict, *colorspace;
79 unsigned char buf[DIB_HEADER_SIZE_MAX+4];
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;
87 pdf_ximage_init_image_info(&info);
89 stream = stream_dict = colorspace = NULL;
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...");
98 if (p[0] != 'B' || p[1] != 'M') {
99 WARN("File not starting with \'B\' \'M\'... Not a BMP file?");
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))
108 /* fsize = ULONG_LE(p); */ p += 4;
109 if (ULONG_LE(p) != 0) {
110 WARN("Not a BMP file???");
114 offset = ULONG_LE(p); p += 4;
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...");
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.");
131 bit_count = USHORT_LE(p); p += 2;
132 compression = DIB_COMPRESS_NONE;
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.");
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;
150 WARN("Unknown BMP header type.");
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);
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;
168 WARN("Unkown BMP bitCount: %ld", bit_count);
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);
178 stream = pdf_new_stream(STREAM_COMPRESS);
179 stream_dict = pdf_stream_dict(stream);
181 if (bit_count < 24) {
183 unsigned char *palette, bgrq[4];
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...");
193 palette[3*i ] = bgrq[2];
194 palette[3*i+1] = bgrq[1];
195 palette[3*i+2] = bgrq[0];
197 lookup = pdf_new_string(palette, num_palette*3);
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);
206 colorspace = pdf_new_name("DeviceRGB");
208 pdf_add_dict(stream_dict, pdf_new_name("ColorSpace"), colorspace);
210 /* Raster data of BMP is four-byte aligned. */
213 unsigned char *stream_data_ptr = NULL;
215 rowbytes = (info.width * bit_count + 7) / 8;
217 seek_absolute(fp, offset);
218 if (compression == DIB_COMPRESS_NONE) {
222 padding = (rowbytes % 4) ? 4 - (rowbytes % 4) : 0;
223 dib_rowbytes = rowbytes + padding;
224 stream_data_ptr = NEW(rowbytes*info.height + padding,
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);
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);
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);
254 pdf_release_obj(stream);
259 if (bit_count == 24) {
260 for (n = 0; n < info.width * info.height * 3; n += 3) {
262 g = stream_data_ptr[n];
263 stream_data_ptr[n ] = stream_data_ptr[n+2];
264 stream_data_ptr[n+2] = g;
269 for (n = info.height - 1; n >= 0; n--) {
270 p = stream_data_ptr + n * rowbytes;
271 pdf_add_stream(stream, p, rowbytes);
274 pdf_add_stream(stream, stream_data_ptr, rowbytes*info.height);
276 RELEASE(stream_data_ptr);
279 pdf_ximage_set_image(ximage, &info, stream);
285 read_raster_rle8 (unsigned char *data_ptr,
286 long width, long height, FILE *fp)
289 unsigned char *p, b0, b1;
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; ) {
299 b0 = get_unsigned_byte(fp);
300 b1 = get_unsigned_byte(fp);
303 p = data_ptr + v * rowbytes + h;
314 h += get_unsigned_byte(fp);
315 v += get_unsigned_byte(fp);
321 WARN("RLE decode failed...");
324 if (fread(p, 1, b1, fp) != b1)
328 get_unsigned_byte(fp);
336 WARN("RLE decode failed...");
343 /* Check for EOL and EOI marker */
345 b0 = get_unsigned_byte(fp);
346 b1 = get_unsigned_byte(fp);
348 WARN("RLE decode failed...");
350 } else if (b1 == 0x01) {
352 } else if (b1 != 0x00) {
353 WARN("RLE decode failed...");
365 read_raster_rle4 (unsigned char *data_ptr,
366 long width, long height, FILE *fp)
369 unsigned char *p, b0, b1, b;
371 int eol, eoi, i, nbytes;
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; ) {
379 b0 = get_unsigned_byte(fp);
380 b1 = get_unsigned_byte(fp);
383 p = data_ptr + v * rowbytes + (h / 2);
393 h += get_unsigned_byte(fp);
394 v += get_unsigned_byte(fp);
398 if (h + b1 > width) {
399 WARN("RLE decode failed...");
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;
410 if (fread(p, 1, nbytes, fp) != nbytes) {
417 get_unsigned_byte(fp);
423 if (h + b0 > width) {
424 WARN("RLE decode failed...");
428 *p++ = (b1 >> 4) & 0x0f;
429 b1 = ((b1 << 4) & 0xf0)|((b1 >> 4) & 0x0f);
434 memset(p, b1, nbytes);
441 /* Check for EOL and EOI marker */
443 b0 = get_unsigned_byte(fp);
444 b1 = get_unsigned_byte(fp);
446 WARN("No EOL/EOI marker. RLE decode failed...");
448 } else if (b1 == 0x01) {
450 } else if (b1 != 0x00) {
451 WARN("No EOL/EOI marker. RLE decode failed...");