1
/* $Header: /home/cvsroot/dvipdfmx/src/bmpimage.c,v 1.2 2004/07/27 12:08:46 hirata Exp $
3
This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
5
Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
6
the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
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, fsize, 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...");