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