1 /* 2 * Copyright 2002-2006, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Wilber <mwilber@users.berlios.de> 7 */ 8 9 #include "BMPTranslator.h" 10 11 #include <new> 12 #include <stdio.h> 13 #include <string.h> 14 15 #include "BMPView.h" 16 17 using std::nothrow; 18 19 //#define INFO(x) printf(x); 20 #define INFO(x) 21 //#define ERROR(x) printf(x); 22 #define ERROR(x) 23 24 // The input formats that this translator supports. 25 translation_format gInputFormats[] = { 26 { 27 B_TRANSLATOR_BITMAP, 28 B_TRANSLATOR_BITMAP, 29 BBT_IN_QUALITY, 30 BBT_IN_CAPABILITY, 31 "image/x-be-bitmap", 32 "Be Bitmap Format (BMPTranslator)" 33 }, 34 { 35 B_BMP_FORMAT, 36 B_TRANSLATOR_BITMAP, 37 BMP_IN_QUALITY, 38 BMP_IN_CAPABILITY, 39 "image/x-bmp", 40 "BMP image" 41 } 42 }; 43 44 // The output formats that this translator supports. 45 translation_format gOutputFormats[] = { 46 { 47 B_TRANSLATOR_BITMAP, 48 B_TRANSLATOR_BITMAP, 49 BBT_OUT_QUALITY, 50 BBT_OUT_CAPABILITY, 51 "image/x-be-bitmap", 52 "Be Bitmap Format (BMPTranslator)" 53 }, 54 { 55 B_BMP_FORMAT, 56 B_TRANSLATOR_BITMAP, 57 BMP_OUT_QUALITY, 58 BMP_OUT_CAPABILITY, 59 "image/x-bmp", 60 "BMP image" 61 } 62 }; 63 64 // Default settings for the Translator 65 TranSetting gDefaultSettings[] = { 66 {B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false}, 67 {B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false} 68 }; 69 70 // --------------------------------------------------------------- 71 // make_nth_translator 72 // 73 // Creates a BMPTranslator object to be used by BTranslatorRoster 74 // 75 // Preconditions: 76 // 77 // Parameters: n, The translator to return. Since 78 // BMPTranslator only publishes one 79 // translator, it only returns a 80 // BMPTranslator if n == 0 81 // 82 // you, The image_id of the add-on that 83 // contains code (not used). 84 // 85 // flags, Has no meaning yet, should be 0. 86 // 87 // Postconditions: 88 // 89 // Returns: NULL if n is not zero, 90 // a new BMPTranslator if n is zero 91 // --------------------------------------------------------------- 92 BTranslator * 93 make_nth_translator(int32 n, image_id you, uint32 flags, ...) 94 { 95 if (!n) 96 return new BMPTranslator(); 97 else 98 return NULL; 99 } 100 101 // --------------------------------------------------------------- 102 // Constructor 103 // 104 // Sets up the version info and the name of the translator so that 105 // these values can be returned when they are requested. 106 // 107 // Preconditions: 108 // 109 // Parameters: 110 // 111 // Postconditions: 112 // 113 // Returns: 114 // --------------------------------------------------------------- 115 BMPTranslator::BMPTranslator() 116 : BaseTranslator("BMP Images", "BMP image translator", 117 BMP_TRANSLATOR_VERSION, 118 gInputFormats, sizeof(gInputFormats) / sizeof(translation_format), 119 gOutputFormats, sizeof(gOutputFormats) / sizeof(translation_format), 120 "BMPTranslator_Settings", 121 gDefaultSettings, sizeof(gDefaultSettings) / sizeof(TranSetting), 122 B_TRANSLATOR_BITMAP, B_BMP_FORMAT) 123 { 124 } 125 126 // --------------------------------------------------------------- 127 // Destructor 128 // 129 // Does nothing 130 // 131 // Preconditions: 132 // 133 // Parameters: 134 // 135 // Postconditions: 136 // 137 // Returns: 138 // --------------------------------------------------------------- 139 BMPTranslator::~BMPTranslator() 140 { 141 } 142 143 // --------------------------------------------------------------- 144 // get_padding 145 // 146 // Returns number of bytes of padding required at the end of 147 // the row by the BMP format 148 // 149 // 150 // Preconditions: If bitsperpixel is zero, a division by zero 151 // will occur, which is bad 152 // 153 // Parameters: width, width of the row, in pixels 154 // 155 // bitsperpixel, bitdepth of the image 156 // 157 // Postconditions: 158 // 159 // Returns: 160 // --------------------------------------------------------------- 161 int32 162 get_padding(uint32 width, uint16 bitsperpixel) 163 { 164 int32 padding = 0; 165 166 if (bitsperpixel > 8) { 167 uint8 bytesPerPixel = bitsperpixel / 8; 168 padding = (width * bytesPerPixel) % 4; 169 } else { 170 uint8 pixelsPerByte = 8 / bitsperpixel; 171 if (!(width % pixelsPerByte)) 172 padding = (width / pixelsPerByte) % 4; 173 else 174 padding = ((width + pixelsPerByte - 175 (width % pixelsPerByte)) / 176 pixelsPerByte) % 4; 177 } 178 179 if (padding) 180 padding = 4 - padding; 181 182 return padding; 183 } 184 185 // --------------------------------------------------------------- 186 // get_rowbytes 187 // 188 // Returns number of bytes required to store a row of BMP pixels 189 // with a width of width and a bit depth of bitsperpixel. 190 // 191 // 192 // Preconditions: If bitsperpixel is zero, a division by zero 193 // will occur, which is bad 194 // 195 // Parameters: width, width of the row, in pixels 196 // 197 // bitsperpixel, bitdepth of the image 198 // 199 // Postconditions: 200 // 201 // Returns: 202 // --------------------------------------------------------------- 203 int32 204 get_rowbytes(uint32 width, uint16 bitsperpixel) 205 { 206 int32 rowbytes = 0; 207 int32 padding = get_padding(width, bitsperpixel); 208 209 if (bitsperpixel > 8) { 210 uint8 bytesPerPixel = bitsperpixel / 8; 211 rowbytes = (width * bytesPerPixel) + padding; 212 } else { 213 uint8 pixelsPerByte = 8 / bitsperpixel; 214 rowbytes = (width / pixelsPerByte) + 215 ((width % pixelsPerByte) ? 1 : 0) + padding; 216 } 217 218 return rowbytes; 219 } 220 221 // --------------------------------------------------------------- 222 // identify_bmp_header 223 // 224 // Determines if the data in inSource is in the MS or OS/2 BMP 225 // format. If it is, it returns info about the data in inSource 226 // to outInfo, pfileheader, pmsheader, pfrommsformat and os2skip. 227 // 228 // Preconditions: 229 // 230 // Parameters: inSource, The source of the image data 231 // 232 // outInfo, Information about the translator 233 // is copied here 234 // 235 // amtread, Amount of data read from inSource 236 // before this function was called 237 // 238 // read, Pointer to the data that was read 239 // in before this function was called 240 // 241 // pfileheader, File header info for the BMP is 242 // copied here after it is read from 243 // the file. 244 // 245 // pmsheader, BMP header info read in from the 246 // BMP file 247 // 248 // pfrommsformat, Set to true if BMP data is BMP 249 // format, false if BMP data is OS/2 250 // format. 251 // 252 // pos2skip, If data is in OS/2 format, the number 253 // of bytes to skip between the header 254 // data and image data is stored here 255 // 256 // Postconditions: 257 // 258 // Returns: B_NO_TRANSLATOR, if the data does not look like 259 // BMP format data 260 // 261 // B_ERROR, if the header data could not be converted to host 262 // format 263 // 264 // B_OK, if the data looks like bits data and no errors were 265 // encountered 266 // --------------------------------------------------------------- 267 status_t 268 identify_bmp_header(BPositionIO *inSource, translator_info *outInfo, 269 BMPFileHeader *pfileheader = NULL, MSInfoHeader *pmsheader = NULL, 270 bool *pfrommsformat = NULL, off_t *pos2skip = NULL) 271 { 272 // read in the fileHeader 273 uint8 buf[40]; 274 BMPFileHeader fileHeader; 275 ssize_t size = 14; 276 if (inSource->Read(buf, size) != size) 277 return B_NO_TRANSLATOR; 278 279 // check BMP magic number 280 const uint16 kBmpMagic = B_HOST_TO_LENDIAN_INT16('MB'); 281 uint16 sourceMagic; 282 memcpy(&sourceMagic, buf, sizeof(uint16)); 283 if (sourceMagic != kBmpMagic) 284 return B_NO_TRANSLATOR; 285 286 // convert fileHeader to host byte order 287 memcpy(&fileHeader.magic, buf, 2); 288 memcpy(&fileHeader.fileSize, buf + 2, 4); 289 memcpy(&fileHeader.reserved, buf + 6, 4); 290 memcpy(&fileHeader.dataOffset, buf + 10, 4); 291 if (swap_data(B_UINT16_TYPE, &fileHeader.magic, sizeof(uint16), 292 B_SWAP_LENDIAN_TO_HOST) != B_OK) 293 return B_ERROR; 294 if (swap_data(B_UINT32_TYPE, 295 (reinterpret_cast<uint8 *> (&fileHeader)) + 2, 12, 296 B_SWAP_LENDIAN_TO_HOST) != B_OK) 297 return B_ERROR; 298 299 if (fileHeader.reserved != 0) 300 return B_NO_TRANSLATOR; 301 302 uint32 headersize = 0; 303 if (inSource->Read(&headersize, 4) != 4) 304 return B_NO_TRANSLATOR; 305 if (swap_data(B_UINT32_TYPE, &headersize, 4, 306 B_SWAP_LENDIAN_TO_HOST) != B_OK) 307 return B_ERROR; 308 309 if (headersize == sizeof(MSInfoHeader)) { 310 // MS format 311 312 if (fileHeader.dataOffset < 54) 313 return B_NO_TRANSLATOR; 314 315 MSInfoHeader msheader; 316 msheader.size = headersize; 317 if (inSource->Read( 318 reinterpret_cast<uint8 *> (&msheader) + 4, 36) != 36) 319 return B_NO_TRANSLATOR; 320 321 // convert msheader to host byte order 322 if (swap_data(B_UINT32_TYPE, 323 reinterpret_cast<uint8 *> (&msheader) + 4, 36, 324 B_SWAP_LENDIAN_TO_HOST) != B_OK) 325 return B_ERROR; 326 327 // check if msheader is valid 328 if (msheader.width == 0 || msheader.height == 0) 329 return B_NO_TRANSLATOR; 330 if (msheader.planes != 1) 331 return B_NO_TRANSLATOR; 332 if ((msheader.bitsperpixel != 1 || 333 msheader.compression != BMP_NO_COMPRESS) && 334 (msheader.bitsperpixel != 4 || 335 msheader.compression != BMP_NO_COMPRESS) && 336 (msheader.bitsperpixel != 4 || 337 msheader.compression != BMP_RLE4_COMPRESS) && 338 (msheader.bitsperpixel != 8 || 339 msheader.compression != BMP_NO_COMPRESS) && 340 (msheader.bitsperpixel != 8 || 341 msheader.compression != BMP_RLE8_COMPRESS) && 342 (msheader.bitsperpixel != 24 || 343 msheader.compression != BMP_NO_COMPRESS) && 344 (msheader.bitsperpixel != 32 || 345 msheader.compression != BMP_NO_COMPRESS)) 346 return B_NO_TRANSLATOR; 347 if (!msheader.imagesize && msheader.compression) 348 return B_NO_TRANSLATOR; 349 if (msheader.colorsimportant > msheader.colorsused) 350 return B_NO_TRANSLATOR; 351 352 if (outInfo) { 353 outInfo->type = B_BMP_FORMAT; 354 outInfo->group = B_TRANSLATOR_BITMAP; 355 outInfo->quality = BMP_IN_QUALITY; 356 outInfo->capability = BMP_IN_CAPABILITY; 357 sprintf(outInfo->name, "BMP image (MS format, %d bits", 358 msheader.bitsperpixel); 359 if (msheader.compression) 360 strcat(outInfo->name, ", RLE)"); 361 else 362 strcat(outInfo->name, ")"); 363 strcpy(outInfo->MIME, "image/x-bmp"); 364 } 365 366 if (pfileheader) { 367 pfileheader->magic = fileHeader.magic; 368 pfileheader->fileSize = fileHeader.fileSize; 369 pfileheader->reserved = fileHeader.reserved; 370 pfileheader->dataOffset = fileHeader.dataOffset; 371 } 372 if (pmsheader) { 373 pmsheader->size = msheader.size; 374 pmsheader->width = msheader.width; 375 pmsheader->height = abs((int32)msheader.height); 376 // TODO: negative height means the BMP is up side down 377 // -> support this... 378 pmsheader->planes = msheader.planes; 379 pmsheader->bitsperpixel = msheader.bitsperpixel; 380 pmsheader->compression = msheader.compression; 381 pmsheader->imagesize = msheader.imagesize; 382 pmsheader->xpixperm = msheader.xpixperm; 383 pmsheader->ypixperm = msheader.ypixperm; 384 pmsheader->colorsused = msheader.colorsused; 385 pmsheader->colorsimportant = msheader.colorsimportant; 386 } 387 if (pfrommsformat) 388 (*pfrommsformat) = true; 389 390 return B_OK; 391 392 } else if (headersize == sizeof(OS2InfoHeader)) { 393 // OS/2 format 394 395 if (fileHeader.dataOffset < 26) 396 return B_NO_TRANSLATOR; 397 398 OS2InfoHeader os2header; 399 os2header.size = headersize; 400 if (inSource->Read( 401 reinterpret_cast<uint8 *> (&os2header) + 4, 8) != 8) 402 return B_NO_TRANSLATOR; 403 404 // convert msheader to host byte order 405 if (swap_data(B_UINT32_TYPE, 406 reinterpret_cast<uint8 *> (&os2header) + 4, 8, 407 B_SWAP_LENDIAN_TO_HOST) != B_OK) 408 return B_ERROR; 409 410 // check if msheader is valid 411 if (os2header.width == 0 || os2header.height == 0) 412 return B_NO_TRANSLATOR; 413 if (os2header.planes != 1) 414 return B_NO_TRANSLATOR; 415 if (os2header.bitsperpixel != 1 && 416 os2header.bitsperpixel != 4 && 417 os2header.bitsperpixel != 8 && 418 os2header.bitsperpixel != 24) 419 return B_NO_TRANSLATOR; 420 421 if (outInfo) { 422 outInfo->type = B_BMP_FORMAT; 423 outInfo->group = B_TRANSLATOR_BITMAP; 424 outInfo->quality = BMP_IN_QUALITY; 425 outInfo->capability = BMP_IN_CAPABILITY; 426 sprintf(outInfo->name, "BMP image (OS/2 format, %d bits)", 427 os2header.bitsperpixel); 428 strcpy(outInfo->MIME, "image/x-bmp"); 429 } 430 if (pfileheader && pmsheader) { 431 pfileheader->magic = 'MB'; 432 pfileheader->fileSize = 0; 433 pfileheader->reserved = 0; 434 pfileheader->dataOffset = 0; 435 436 pmsheader->size = 40; 437 pmsheader->width = os2header.width; 438 pmsheader->height = os2header.height; 439 pmsheader->planes = 1; 440 pmsheader->bitsperpixel = os2header.bitsperpixel; 441 pmsheader->compression = BMP_NO_COMPRESS; 442 pmsheader->imagesize = 0; 443 pmsheader->xpixperm = 2835; // 72 dpi horizontal 444 pmsheader->ypixperm = 2835; // 72 dpi vertical 445 pmsheader->colorsused = 0; 446 pmsheader->colorsimportant = 0; 447 448 // determine fileSize / imagesize 449 switch (pmsheader->bitsperpixel) { 450 case 24: 451 if (pos2skip && fileHeader.dataOffset > 26) 452 (*pos2skip) = fileHeader.dataOffset - 26; 453 454 pfileheader->dataOffset = 54; 455 pmsheader->imagesize = get_rowbytes(pmsheader->width, 456 pmsheader->bitsperpixel) * pmsheader->height; 457 pfileheader->fileSize = pfileheader->dataOffset + 458 pmsheader->imagesize; 459 460 break; 461 462 case 8: 463 case 4: 464 case 1: 465 { 466 uint16 ncolors = 1 << pmsheader->bitsperpixel; 467 pmsheader->colorsused = ncolors; 468 pmsheader->colorsimportant = ncolors; 469 if (pos2skip && fileHeader.dataOffset > 470 static_cast<uint32> (26 + (ncolors * 3))) 471 (*pos2skip) = fileHeader.dataOffset - 472 (26 + (ncolors * 3)); 473 474 pfileheader->dataOffset = 54 + (ncolors * 4); 475 pmsheader->imagesize = get_rowbytes(pmsheader->width, 476 pmsheader->bitsperpixel) * pmsheader->height; 477 pfileheader->fileSize = pfileheader->dataOffset + 478 pmsheader->imagesize; 479 480 break; 481 } 482 483 default: 484 break; 485 } 486 } 487 if (pfrommsformat) 488 (*pfrommsformat) = false; 489 490 return B_OK; 491 492 } else 493 return B_NO_TRANSLATOR; 494 } 495 496 // --------------------------------------------------------------- 497 // DerivedIdentify 498 // 499 // Examines the data from inSource and determines if it is in a 500 // format that this translator knows how to work with. 501 // 502 // Preconditions: 503 // 504 // Parameters: inSource, where the data to examine is 505 // 506 // inFormat, a hint about the data in inSource, 507 // it is ignored since it is only a hint 508 // 509 // ioExtension, configuration settings for the 510 // translator 511 // 512 // outInfo, information about what data is in 513 // inSource and how well this translator 514 // can handle that data is stored here 515 // 516 // outType, The format that the user wants 517 // the data in inSource to be 518 // converted to 519 // 520 // Postconditions: 521 // 522 // Returns: B_NO_TRANSLATOR, if this translator can't handle 523 // the data in inSource 524 // 525 // B_ERROR, if there was an error converting the data to the host 526 // format 527 // 528 // B_BAD_VALUE, if the settings in ioExtension are bad 529 // 530 // B_OK, if this translator understand the data and there were 531 // no errors found 532 // --------------------------------------------------------------- 533 status_t 534 BMPTranslator::DerivedIdentify(BPositionIO *inSource, 535 const translation_format *inFormat, BMessage *ioExtension, 536 translator_info *outInfo, uint32 outType) 537 { 538 return identify_bmp_header(inSource, outInfo); 539 } 540 541 // --------------------------------------------------------------- 542 // translate_from_bits_to_bmp24 543 // 544 // Converts various varieties of the Be Bitmap format ('bits') to 545 // the MS BMP 24-bit format. 546 // 547 // Preconditions: 548 // 549 // Parameters: inSource, contains the bits data to convert 550 // 551 // outDestination, where the BMP data will be written 552 // 553 // fromspace, the format of the data in inSource 554 // 555 // msheader, contains information about the BMP 556 // dimensions and filesize 557 // 558 // Postconditions: 559 // 560 // Returns: B_ERROR, if memory couldn't be allocated or another 561 // error occured 562 // 563 // B_OK, if no errors occurred 564 // --------------------------------------------------------------- 565 status_t 566 translate_from_bits_to_bmp24(BPositionIO *inSource, 567 BPositionIO *outDestination, color_space fromspace, MSInfoHeader &msheader) 568 { 569 // TODO: WHOHA! big switch statement for the innermost loop! 570 // make a loop per colorspace and put the switch outside!!! 571 // remove memcpy() to copy 3 bytes 572 int32 bitsBytesPerPixel = 0; 573 switch (fromspace) { 574 case B_RGB32: 575 case B_RGB32_BIG: 576 case B_RGBA32: 577 case B_RGBA32_BIG: 578 case B_CMY32: 579 case B_CMYA32: 580 case B_CMYK32: 581 bitsBytesPerPixel = 4; 582 break; 583 584 case B_RGB24: 585 case B_RGB24_BIG: 586 case B_CMY24: 587 bitsBytesPerPixel = 3; 588 break; 589 590 case B_RGB16: 591 case B_RGB16_BIG: 592 case B_RGBA15: 593 case B_RGBA15_BIG: 594 case B_RGB15: 595 case B_RGB15_BIG: 596 bitsBytesPerPixel = 2; 597 break; 598 599 case B_CMAP8: 600 case B_GRAY8: 601 bitsBytesPerPixel = 1; 602 break; 603 604 default: 605 return B_ERROR; 606 } 607 int32 bitsRowBytes = msheader.width * bitsBytesPerPixel; 608 int32 padding = get_padding(msheader.width, msheader.bitsperpixel); 609 int32 bmpRowBytes = 610 get_rowbytes(msheader.width, msheader.bitsperpixel); 611 uint32 bmppixrow = 0; 612 off_t bitsoffset = ((msheader.height - 1) * bitsRowBytes); 613 inSource->Seek(bitsoffset, SEEK_CUR); 614 uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes]; 615 if (!bmpRowData) 616 return B_NO_MEMORY; 617 uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes]; 618 if (!bitsRowData) { 619 delete[] bmpRowData; 620 return B_NO_MEMORY; 621 } 622 memset(bmpRowData + (bmpRowBytes - padding), 0, padding); 623 ssize_t rd = inSource->Read(bitsRowData, bitsRowBytes); 624 const color_map *pmap = NULL; 625 if (fromspace == B_CMAP8) { 626 pmap = system_colors(); 627 if (!pmap) 628 return B_ERROR; 629 } 630 while (rd == static_cast<ssize_t>(bitsRowBytes)) { 631 632 for (uint32 i = 0; i < msheader.width; i++) { 633 uint8 *bitspixel, *bmppixel; 634 uint16 val; 635 switch (fromspace) { 636 case B_RGB32: 637 case B_RGBA32: 638 case B_RGB24: 639 memcpy(bmpRowData + (i * 3), 640 bitsRowData + (i * bitsBytesPerPixel), 3); 641 break; 642 643 case B_RGB16: 644 case B_RGB16_BIG: 645 bitspixel = bitsRowData + (i * bitsBytesPerPixel); 646 bmppixel = bmpRowData + (i * 3); 647 if (fromspace == B_RGB16) 648 val = bitspixel[0] + (bitspixel[1] << 8); 649 else 650 val = bitspixel[1] + (bitspixel[0] << 8); 651 bmppixel[0] = 652 ((val & 0x1f) << 3) | ((val & 0x1f) >> 2); 653 bmppixel[1] = 654 ((val & 0x7e0) >> 3) | ((val & 0x7e0) >> 9); 655 bmppixel[2] = 656 ((val & 0xf800) >> 8) | ((val & 0xf800) >> 13); 657 break; 658 659 case B_RGB15: 660 case B_RGB15_BIG: 661 case B_RGBA15: 662 case B_RGBA15_BIG: 663 // NOTE: the alpha data for B_RGBA15* is not used 664 bitspixel = bitsRowData + (i * bitsBytesPerPixel); 665 bmppixel = bmpRowData + (i * 3); 666 if (fromspace == B_RGB15 || fromspace == B_RGBA15) 667 val = bitspixel[0] + (bitspixel[1] << 8); 668 else 669 val = bitspixel[1] + (bitspixel[0] << 8); 670 bmppixel[0] = 671 ((val & 0x1f) << 3) | ((val & 0x1f) >> 2); 672 bmppixel[1] = 673 ((val & 0x3e0) >> 2) | ((val & 0x3e0) >> 7); 674 bmppixel[2] = 675 ((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12); 676 break; 677 678 case B_RGB32_BIG: 679 case B_RGBA32_BIG: 680 bitspixel = bitsRowData + (i * bitsBytesPerPixel); 681 bmppixel = bmpRowData + (i * 3); 682 bmppixel[0] = bitspixel[3]; 683 bmppixel[1] = bitspixel[2]; 684 bmppixel[2] = bitspixel[1]; 685 break; 686 687 case B_RGB24_BIG: 688 bitspixel = bitsRowData + (i * bitsBytesPerPixel); 689 bmppixel = bmpRowData + (i * 3); 690 bmppixel[0] = bitspixel[2]; 691 bmppixel[1] = bitspixel[1]; 692 bmppixel[2] = bitspixel[0]; 693 break; 694 695 case B_CMAP8: 696 bitspixel = bitsRowData + (i * bitsBytesPerPixel); 697 bmppixel = bmpRowData + (i * 3); 698 rgb_color c = pmap->color_list[bitspixel[0]]; 699 bmppixel[0] = c.blue; 700 bmppixel[1] = c.green; 701 bmppixel[2] = c.red; 702 break; 703 704 case B_GRAY8: 705 bitspixel = bitsRowData + (i * bitsBytesPerPixel); 706 bmppixel = bmpRowData + (i * 3); 707 bmppixel[0] = bitspixel[0]; 708 bmppixel[1] = bitspixel[0]; 709 bmppixel[2] = bitspixel[0]; 710 break; 711 712 case B_CMYK32: 713 { 714 bitspixel = bitsRowData + (i * bitsBytesPerPixel); 715 bmppixel = bmpRowData + (i * 3); 716 717 int32 comp = 255 - bitspixel[2] - bitspixel[3]; 718 bmppixel[0] = (comp < 0) ? 0 : comp; 719 720 comp = 255 - bitspixel[1] - bitspixel[3]; 721 bmppixel[1] = (comp < 0) ? 0 : comp; 722 723 comp = 255 - bitspixel[0] - bitspixel[3]; 724 bmppixel[2] = (comp < 0) ? 0 : comp; 725 break; 726 } 727 728 case B_CMY32: 729 case B_CMYA32: 730 case B_CMY24: 731 bitspixel = bitsRowData + (i * bitsBytesPerPixel); 732 bmppixel = bmpRowData + (i * 3); 733 bmppixel[0] = 255 - bitspixel[2]; 734 bmppixel[1] = 255 - bitspixel[1]; 735 bmppixel[2] = 255 - bitspixel[0]; 736 break; 737 738 default: 739 break; 740 } // switch (fromspace) 741 } // for for (uint32 i = 0; i < msheader.width; i++) 742 743 outDestination->Write(bmpRowData, bmpRowBytes); 744 bmppixrow++; 745 // if I've read all of the pixel data, break 746 // out of the loop so I don't try to read 747 // non-pixel data 748 if (bmppixrow == msheader.height) 749 break; 750 751 inSource->Seek(bitsRowBytes * -2, SEEK_CUR); 752 rd = inSource->Read(bitsRowData, bitsRowBytes); 753 } // while (rd == bitsRowBytes) 754 755 delete[] bmpRowData; 756 delete[] bitsRowData; 757 758 return B_OK; 759 } 760 761 // --------------------------------------------------------------- 762 // translate_from_bits8_to_bmp8 763 // 764 // Converts 8-bit Be Bitmaps ('bits') to the MS 8-bit BMP format 765 // 766 // Preconditions: 767 // 768 // Parameters: inSource, contains the bits data to convert 769 // 770 // outDestination, where the BMP data will be written 771 // 772 // bitsRowBytes, number of bytes in one row of 773 // bits data 774 // 775 // msheader, contains information about the BMP 776 // dimensions and filesize 777 // 778 // Postconditions: 779 // 780 // Returns: B_ERROR, if memory couldn't be allocated or another 781 // error occured 782 // 783 // B_OK, if no errors occurred 784 // --------------------------------------------------------------- 785 status_t 786 translate_from_bits8_to_bmp8(BPositionIO *inSource, 787 BPositionIO *outDestination, int32 bitsRowBytes, MSInfoHeader &msheader) 788 { 789 int32 padding = get_padding(msheader.width, msheader.bitsperpixel); 790 int32 bmpRowBytes = 791 get_rowbytes(msheader.width, msheader.bitsperpixel); 792 uint32 bmppixrow = 0; 793 off_t bitsoffset = ((msheader.height - 1) * bitsRowBytes); 794 inSource->Seek(bitsoffset, SEEK_CUR); 795 uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes]; 796 if (!bmpRowData) 797 return B_NO_MEMORY; 798 uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes]; 799 if (!bitsRowData) { 800 delete[] bmpRowData; 801 return B_NO_MEMORY; 802 } 803 memset(bmpRowData + (bmpRowBytes - padding), 0, padding); 804 ssize_t rd = inSource->Read(bitsRowData, bitsRowBytes); 805 while (rd == bitsRowBytes) { 806 memcpy(bmpRowData, bitsRowData, msheader.width); 807 outDestination->Write(bmpRowData, bmpRowBytes); 808 bmppixrow++; 809 // if I've read all of the pixel data, break 810 // out of the loop so I don't try to read 811 // non-pixel data 812 if (bmppixrow == msheader.height) 813 break; 814 815 inSource->Seek(bitsRowBytes * -2, SEEK_CUR); 816 rd = inSource->Read(bitsRowData, bitsRowBytes); 817 } // while (rd == bitsRowBytes) 818 819 delete[] bmpRowData; 820 delete[] bitsRowData; 821 822 return B_OK; 823 } 824 825 // --------------------------------------------------------------- 826 // translate_from_bits1_to_bmp1 827 // 828 // Converts 1-bit Be Bitmaps ('bits') to the MS 1-bit BMP format 829 // 830 // Preconditions: 831 // 832 // Parameters: inSource, contains the bits data to convert 833 // 834 // outDestination, where the BMP data will be written 835 // 836 // bitsRowBytes, number of bytes in one row of 837 // bits data 838 // 839 // msheader, contains information about the BMP 840 // dimensions and filesize 841 // 842 // Postconditions: 843 // 844 // Returns: B_ERROR, if memory couldn't be allocated or another 845 // error occured 846 // 847 // B_OK, if no errors occurred 848 // --------------------------------------------------------------- 849 status_t 850 translate_from_bits1_to_bmp1(BPositionIO *inSource, 851 BPositionIO *outDestination, int32 bitsRowBytes, MSInfoHeader &msheader) 852 { 853 uint8 pixelsPerByte = 8 / msheader.bitsperpixel; 854 int32 bmpRowBytes = 855 get_rowbytes(msheader.width, msheader.bitsperpixel); 856 uint32 bmppixrow = 0; 857 off_t bitsoffset = ((msheader.height - 1) * bitsRowBytes); 858 inSource->Seek(bitsoffset, SEEK_CUR); 859 uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes]; 860 if (!bmpRowData) 861 return B_NO_MEMORY; 862 uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes]; 863 if (!bitsRowData) { 864 delete[] bmpRowData; 865 return B_NO_MEMORY; 866 } 867 ssize_t rd = inSource->Read(bitsRowData, bitsRowBytes); 868 while (rd == bitsRowBytes) { 869 uint32 bmppixcol = 0; 870 memset(bmpRowData, 0, bmpRowBytes); 871 for (int32 i = 0; (bmppixcol < msheader.width) && 872 (i < bitsRowBytes); i++) { 873 // process each byte in the row 874 uint8 pixels = bitsRowData[i]; 875 for (uint8 compbit = 128; (bmppixcol < msheader.width) && 876 compbit; compbit >>= 1) { 877 // for each bit in the current byte, convert to a BMP palette 878 // index and store that in the bmpRowData 879 uint8 index; 880 if (pixels & compbit) 881 // 1 == black 882 index = 1; 883 else 884 // 0 == white 885 index = 0; 886 bmpRowData[bmppixcol / pixelsPerByte] |= 887 index << (7 - (bmppixcol % pixelsPerByte)); 888 bmppixcol++; 889 } 890 } 891 892 outDestination->Write(bmpRowData, bmpRowBytes); 893 bmppixrow++; 894 // if I've read all of the pixel data, break 895 // out of the loop so I don't try to read 896 // non-pixel data 897 if (bmppixrow == msheader.height) 898 break; 899 900 inSource->Seek(bitsRowBytes * -2, SEEK_CUR); 901 rd = inSource->Read(bitsRowData, bitsRowBytes); 902 } // while (rd == bitsRowBytes) 903 904 delete[] bmpRowData; 905 delete[] bitsRowData; 906 907 return B_OK; 908 } 909 910 // --------------------------------------------------------------- 911 // write_bmp_headers 912 // 913 // Writes the MS BMP headers (fileHeader and msheader) 914 // to outDestination. 915 // 916 // Preconditions: 917 // 918 // Parameters: outDestination, where the headers are written to 919 // 920 // fileHeader, BMP file header data 921 // 922 // msheader, BMP info header data 923 // 924 // Postconditions: 925 // 926 // Returns: B_ERROR, if something went wrong 927 // 928 // B_OK, if there were no problems writing out the headers 929 // --------------------------------------------------------------- 930 status_t 931 write_bmp_headers(BPositionIO *outDestination, BMPFileHeader &fileHeader, 932 MSInfoHeader &msheader) 933 { 934 uint8 bmpheaders[54]; 935 memcpy(bmpheaders, &fileHeader.magic, sizeof(uint16)); 936 memcpy(bmpheaders + 2, &fileHeader.fileSize, sizeof(uint32)); 937 memcpy(bmpheaders + 6, &fileHeader.reserved, sizeof(uint32)); 938 memcpy(bmpheaders + 10, &fileHeader.dataOffset, sizeof(uint32)); 939 memcpy(bmpheaders + 14, &msheader, sizeof(msheader)); 940 if (swap_data(B_UINT16_TYPE, bmpheaders, 2, 941 B_SWAP_HOST_TO_LENDIAN) != B_OK) 942 return B_ERROR; 943 if (swap_data(B_UINT32_TYPE, bmpheaders + 2, 12, 944 B_SWAP_HOST_TO_LENDIAN) != B_OK) 945 return B_ERROR; 946 if (swap_data(B_UINT32_TYPE, bmpheaders + 14, 947 sizeof(MSInfoHeader), B_SWAP_HOST_TO_LENDIAN) != B_OK) 948 return B_ERROR; 949 if (outDestination->Write(bmpheaders, 54) != 54) 950 return B_ERROR; 951 952 return B_OK; 953 } 954 955 // --------------------------------------------------------------- 956 // translate_from_bits 957 // 958 // Convert the data in inSource from the Be Bitmap format ('bits') 959 // to the format specified in outType (either bits or BMP). 960 // 961 // Preconditions: 962 // 963 // Parameters: inSource, the bits data to translate 964 // 965 // outType, the type of data to convert to 966 // 967 // outDestination, where the output is written to 968 // 969 // Postconditions: 970 // 971 // Returns: B_NO_TRANSLATOR, if the data is not in a supported 972 // format 973 // 974 // B_ERROR, if there was an error allocating memory or some other 975 // error 976 // 977 // B_OK, if successfully translated the data from the bits format 978 // --------------------------------------------------------------- 979 status_t 980 BMPTranslator::translate_from_bits(BPositionIO *inSource, uint32 outType, 981 BPositionIO *outDestination) 982 { 983 bool bheaderonly, bdataonly; 984 bheaderonly = bdataonly = false; 985 986 TranslatorBitmap bitsHeader; 987 status_t result; 988 result = identify_bits_header(inSource, NULL, &bitsHeader); 989 if (result != B_OK) 990 return result; 991 992 // Translate B_TRANSLATOR_BITMAP to B_BMP_FORMAT 993 if (outType == B_BMP_FORMAT) { 994 // Set up BMP header 995 BMPFileHeader fileHeader; 996 fileHeader.magic = 'MB'; 997 fileHeader.reserved = 0; 998 999 MSInfoHeader msheader; 1000 msheader.size = 40; 1001 msheader.width = 1002 static_cast<uint32> (bitsHeader.bounds.Width() + 1); 1003 msheader.height = 1004 static_cast<uint32> (bitsHeader.bounds.Height() + 1); 1005 msheader.planes = 1; 1006 msheader.xpixperm = 2835; // 72 dpi horizontal 1007 msheader.ypixperm = 2835; // 72 dpi vertical 1008 msheader.colorsused = 0; 1009 msheader.colorsimportant = 0; 1010 1011 // determine fileSize / imagesize 1012 switch (bitsHeader.colors) { 1013 case B_RGB32: 1014 case B_RGB32_BIG: 1015 case B_RGBA32: 1016 case B_RGBA32_BIG: 1017 case B_RGB24: 1018 case B_RGB24_BIG: 1019 case B_RGB16: 1020 case B_RGB16_BIG: 1021 case B_RGB15: 1022 case B_RGB15_BIG: 1023 case B_RGBA15: 1024 case B_RGBA15_BIG: 1025 case B_CMYK32: 1026 case B_CMY32: 1027 case B_CMYA32: 1028 case B_CMY24: 1029 1030 fileHeader.dataOffset = 54; 1031 msheader.bitsperpixel = 24; 1032 msheader.compression = BMP_NO_COMPRESS; 1033 msheader.imagesize = get_rowbytes(msheader.width, 24) * 1034 msheader.height; 1035 fileHeader.fileSize = fileHeader.dataOffset + 1036 msheader.imagesize; 1037 1038 break; 1039 1040 case B_CMAP8: 1041 case B_GRAY8: 1042 1043 msheader.colorsused = 256; 1044 msheader.colorsimportant = 256; 1045 fileHeader.dataOffset = 54 + (4 * 256); 1046 msheader.bitsperpixel = 8; 1047 msheader.compression = BMP_NO_COMPRESS; 1048 msheader.imagesize = get_rowbytes(msheader.width, 1049 msheader.bitsperpixel) * msheader.height; 1050 fileHeader.fileSize = fileHeader.dataOffset + 1051 msheader.imagesize; 1052 1053 break; 1054 1055 case B_GRAY1: 1056 1057 msheader.colorsused = 2; 1058 msheader.colorsimportant = 2; 1059 fileHeader.dataOffset = 62; 1060 msheader.bitsperpixel = 1; 1061 msheader.compression = BMP_NO_COMPRESS; 1062 msheader.imagesize = get_rowbytes(msheader.width, 1063 msheader.bitsperpixel) * msheader.height; 1064 fileHeader.fileSize = fileHeader.dataOffset + 1065 msheader.imagesize; 1066 1067 break; 1068 1069 default: 1070 return B_NO_TRANSLATOR; 1071 } 1072 1073 // write out the BMP headers 1074 if (bheaderonly || (!bheaderonly && !bdataonly)) { 1075 result = write_bmp_headers(outDestination, fileHeader, msheader); 1076 if (result != B_OK) 1077 return result; 1078 } 1079 if (bheaderonly) 1080 // if user only wants the header, bail out 1081 // before the data is written 1082 return result; 1083 1084 // write out the BMP pixel data 1085 switch (bitsHeader.colors) { 1086 case B_RGB32: 1087 case B_RGB32_BIG: 1088 case B_RGBA32: 1089 case B_RGBA32_BIG: 1090 case B_RGB24: 1091 case B_RGB24_BIG: 1092 case B_RGB16: 1093 case B_RGB16_BIG: 1094 case B_RGB15: 1095 case B_RGB15_BIG: 1096 case B_RGBA15: 1097 case B_RGBA15_BIG: 1098 case B_CMYK32: 1099 case B_CMY32: 1100 case B_CMYA32: 1101 case B_CMY24: 1102 return translate_from_bits_to_bmp24(inSource, outDestination, 1103 bitsHeader.colors, msheader); 1104 1105 case B_CMAP8: 1106 case B_GRAY8: 1107 { 1108 // write palette to BMP file 1109 uint8 pal[1024]; 1110 uint8* palHandle = pal; 1111 if (bitsHeader.colors == B_CMAP8) { 1112 // write system palette 1113 const color_map *pmap = system_colors(); 1114 if (!pmap) 1115 return B_ERROR; 1116 for (int32 i = 0; i < 256; i++) { 1117 rgb_color c = pmap->color_list[i]; 1118 palHandle[0] = c.blue; 1119 palHandle[1] = c.green; 1120 palHandle[2] = c.red; 1121 palHandle[3] = c.alpha; 1122 palHandle += 4; 1123 } 1124 } else { 1125 // write gray palette 1126 for (int32 i = 0; i < 256; i++) { 1127 palHandle[0] = i; 1128 palHandle[1] = i; 1129 palHandle[2] = i; 1130 palHandle[3] = 255; 1131 palHandle += 4; 1132 } 1133 } 1134 ssize_t written = outDestination->Write(pal, 1024); 1135 if (written < 0) 1136 return written; 1137 if (written != 1024) 1138 return B_ERROR; 1139 1140 return translate_from_bits8_to_bmp8(inSource, outDestination, 1141 bitsHeader.rowBytes, msheader); 1142 } 1143 1144 case B_GRAY1: 1145 { 1146 // write monochrome palette to the BMP file 1147 const uint32 monopal[] = { 0x00ffffff, 0x00000000 }; 1148 ssize_t written = outDestination->Write(monopal, 8); 1149 if (written < 0) 1150 return written; 1151 if (written != 8) 1152 return B_ERROR; 1153 1154 return translate_from_bits1_to_bmp1(inSource, outDestination, 1155 bitsHeader.rowBytes, msheader); 1156 } 1157 1158 default: 1159 return B_NO_TRANSLATOR; 1160 } 1161 } else 1162 return B_NO_TRANSLATOR; 1163 } 1164 1165 // --------------------------------------------------------------- 1166 // translate_from_bmpnpal_to_bits 1167 // 1168 // Translates a non-palette BMP from inSource to the B_RGB32 1169 // bits format. 1170 // 1171 // Preconditions: 1172 // 1173 // Parameters: inSource, the BMP data to be translated 1174 // 1175 // outDestination, where the bits data will be written to 1176 // 1177 // msheader, header information about the BMP to be written 1178 // 1179 // Postconditions: 1180 // 1181 // Returns: B_ERROR, if there is an error allocating memory 1182 // 1183 // B_OK, if all went well 1184 // --------------------------------------------------------------- 1185 status_t 1186 translate_from_bmpnpal_to_bits(BPositionIO *inSource, 1187 BPositionIO *outDestination, MSInfoHeader &msheader) 1188 { 1189 int32 bitsRowBytes = msheader.width * 4; 1190 int32 bmpBytesPerPixel = msheader.bitsperpixel / 8; 1191 int32 bmpRowBytes = 1192 get_rowbytes(msheader.width, msheader.bitsperpixel); 1193 1194 // Setup outDestination so that it can be written to 1195 // from the end of the file to the beginning instead of 1196 // the other way around 1197 off_t bitsFileSize = (bitsRowBytes * msheader.height) + 1198 sizeof(TranslatorBitmap); 1199 if (outDestination->SetSize(bitsFileSize) != B_OK) { 1200 // This call should work for BFile and BMallocIO objects, 1201 // but may not work for other BPositionIO based types 1202 ERROR("BMPTranslator::translate_from_bmpnpal_to_bits() - failed to SetSize()\n"); 1203 return B_ERROR; 1204 } 1205 off_t bitsoffset = (msheader.height - 1) * bitsRowBytes; 1206 outDestination->Seek(bitsoffset, SEEK_CUR); 1207 1208 // allocate row buffers 1209 uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes]; 1210 if (!bmpRowData) 1211 return B_NO_MEMORY; 1212 uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes]; 1213 if (!bitsRowData) { 1214 delete[] bmpRowData; 1215 return B_NO_MEMORY; 1216 } 1217 1218 // perform the actual translation 1219 if (bmpBytesPerPixel != 4) { 1220 // clean out buffer so that we don't have to write 1221 // alpha for each row 1222 memset(bitsRowData, 0xff, bitsRowBytes); 1223 } 1224 1225 status_t ret = B_OK; 1226 1227 for (uint32 y = 0; y < msheader.height; y++) { 1228 ssize_t read = inSource->Read(bmpRowData, bmpRowBytes); 1229 if (read != bmpRowBytes) { 1230 // break on read error 1231 if (read >= 0) 1232 ret = B_ERROR; 1233 else 1234 ret = read; 1235 break; 1236 } 1237 1238 if (bmpBytesPerPixel == 4) { 1239 memcpy(bitsRowData, bmpRowData, bmpRowBytes); 1240 } else { 1241 uint8 *pBitsPixel = bitsRowData; 1242 uint8 *pBmpPixel = bmpRowData; 1243 for (uint32 i = 0; i < msheader.width; i++) { 1244 pBitsPixel[0] = pBmpPixel[0]; 1245 pBitsPixel[1] = pBmpPixel[1]; 1246 pBitsPixel[2] = pBmpPixel[2]; 1247 pBitsPixel += 4; 1248 pBmpPixel += bmpBytesPerPixel; 1249 } 1250 } 1251 // write row and seek backward by two rows 1252 ssize_t written = outDestination->Write(bitsRowData, bitsRowBytes); 1253 outDestination->Seek(bitsRowBytes * -2, SEEK_CUR); 1254 1255 if (written != bitsRowBytes) { 1256 // break on write error 1257 if (written >= 0) 1258 ret = B_ERROR; 1259 else 1260 ret = read; 1261 break; 1262 } 1263 } 1264 1265 delete[] bmpRowData; 1266 delete[] bitsRowData; 1267 1268 return ret; 1269 } 1270 1271 // --------------------------------------------------------------- 1272 // translate_from_bmppal_to_bits 1273 // 1274 // Translates an uncompressed, palette BMP from inSource to 1275 // the B_RGB32 bits format. 1276 // 1277 // Preconditions: 1278 // 1279 // Parameters: inSource, the BMP data to be translated 1280 // 1281 // outDestination, where the bits data will be written to 1282 // 1283 // msheader, header information about the BMP to be written 1284 // 1285 // palette, BMP palette for the BMP image 1286 // 1287 // frommsformat, true if BMP in inSource is in MS format, 1288 // false if it is in OS/2 format 1289 // 1290 // Postconditions: 1291 // 1292 // Returns: B_NO_MEMORY, if there is an error allocating memory 1293 // 1294 // B_OK, if all went well 1295 // --------------------------------------------------------------- 1296 status_t 1297 translate_from_bmppal_to_bits(BPositionIO *inSource, 1298 BPositionIO *outDestination, MSInfoHeader &msheader, 1299 const uint8 *palette, bool frommsformat) 1300 { 1301 uint16 pixelsPerByte = 8 / msheader.bitsperpixel; 1302 uint16 bitsPerPixel = msheader.bitsperpixel; 1303 uint8 palBytesPerPixel; 1304 if (frommsformat) 1305 palBytesPerPixel = 4; 1306 else 1307 palBytesPerPixel = 3; 1308 1309 uint8 mask = 1; 1310 mask = (mask << bitsPerPixel) - 1; 1311 1312 int32 bmpRowBytes = 1313 get_rowbytes(msheader.width, msheader.bitsperpixel); 1314 uint32 bmppixrow = 0; 1315 1316 // Setup outDestination so that it can be written to 1317 // from the end of the file to the beginning instead of 1318 // the other way around 1319 int32 bitsRowBytes = msheader.width * 4; 1320 off_t bitsFileSize = (bitsRowBytes * msheader.height) + 1321 sizeof(TranslatorBitmap); 1322 if (outDestination->SetSize(bitsFileSize) != B_OK) 1323 // This call should work for BFile and BMallocIO objects, 1324 // but may not work for other BPositionIO based types 1325 return B_ERROR; 1326 off_t bitsoffset = ((msheader.height - 1) * bitsRowBytes); 1327 outDestination->Seek(bitsoffset, SEEK_CUR); 1328 1329 // allocate row buffers 1330 uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes]; 1331 if (!bmpRowData) 1332 return B_NO_MEMORY; 1333 uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes]; 1334 if (!bitsRowData) { 1335 delete[] bmpRowData; 1336 return B_NO_MEMORY; 1337 } 1338 memset(bitsRowData, 0xff, bitsRowBytes); 1339 ssize_t rd = inSource->Read(bmpRowData, bmpRowBytes); 1340 while (rd == static_cast<ssize_t>(bmpRowBytes)) { 1341 for (uint32 i = 0; i < msheader.width; i++) { 1342 uint8 indices = (bmpRowData + (i / pixelsPerByte))[0]; 1343 uint8 index; 1344 index = (indices >> 1345 (bitsPerPixel * ((pixelsPerByte - 1) - 1346 (i % pixelsPerByte)))) & mask; 1347 memcpy(bitsRowData + (i * 4), 1348 palette + (index * palBytesPerPixel), 3); 1349 } 1350 1351 outDestination->Write(bitsRowData, bitsRowBytes); 1352 bmppixrow++; 1353 // if I've read all of the pixel data, break 1354 // out of the loop so I don't try to read 1355 // non-pixel data 1356 if (bmppixrow == msheader.height) 1357 break; 1358 1359 outDestination->Seek(bitsRowBytes * -2, SEEK_CUR); 1360 rd = inSource->Read(bmpRowData, bmpRowBytes); 1361 } 1362 1363 delete[] bmpRowData; 1364 delete[] bitsRowData; 1365 1366 return B_OK; 1367 } 1368 1369 1370 // --------------------------------------------------------------- 1371 // pixelcpy 1372 // 1373 // Copies count 32-bit pixels with a color value of pixel to dest. 1374 // 1375 // Preconditions: 1376 // 1377 // Parameters: dest, where the pixel data will be copied to 1378 // 1379 // pixel, the 32-bit color value to copy to dest 1380 // count times 1381 // 1382 // count, the number of times pixel is copied to 1383 // dest 1384 // 1385 // Postconditions: 1386 // 1387 // Returns: 1388 // --------------------------------------------------------------- 1389 void 1390 pixelcpy(uint8 *dest, uint32 pixel, uint32 count) 1391 { 1392 for (uint32 i = 0; i < count; i++) { 1393 memcpy(dest, &pixel, 3); 1394 dest += 4; 1395 } 1396 } 1397 1398 // --------------------------------------------------------------- 1399 // translate_from_bmppalr_to_bits 1400 // 1401 // Translates an RLE compressed, palette BMP from inSource to 1402 // the B_RGB32 bits format. Currently, this code is not as 1403 // memory effcient as it could be. It assumes that the BMP 1404 // from inSource is relatively small. 1405 // 1406 // Preconditions: 1407 // 1408 // Parameters: inSource, the BMP data to be translated 1409 // 1410 // outDestination, where the bits data will be written to 1411 // 1412 // datasize, number of bytes of data needed for the bits output 1413 // 1414 // msheader, header information about the BMP to be written 1415 // 1416 // palette, BMP palette for data in inSource 1417 // 1418 // Postconditions: 1419 // 1420 // Returns: B_ERROR, if there is an error allocating memory 1421 // 1422 // B_OK, if all went well 1423 // --------------------------------------------------------------- 1424 status_t 1425 translate_from_bmppalr_to_bits(BPositionIO *inSource, 1426 BPositionIO *outDestination, int32 datasize, MSInfoHeader &msheader, 1427 const uint8 *palette) 1428 { 1429 uint16 pixelsPerByte = 8 / msheader.bitsperpixel; 1430 uint16 bitsPerPixel = msheader.bitsperpixel; 1431 uint8 mask = (1 << bitsPerPixel) - 1; 1432 1433 uint8 count, indices, index; 1434 // Setup outDestination so that it can be written to 1435 // from the end of the file to the beginning instead of 1436 // the other way around 1437 int32 bitsRowBytes = msheader.width * 4; 1438 off_t bitsFileSize = (bitsRowBytes * msheader.height) + 1439 sizeof(TranslatorBitmap); 1440 if (outDestination->SetSize(bitsFileSize) != B_OK) 1441 // This call should work for BFile and BMallocIO objects, 1442 // but may not work for other BPositionIO based types 1443 return B_ERROR; 1444 uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes]; 1445 if (!bitsRowData) 1446 return B_NO_MEMORY; 1447 memset(bitsRowData, 0xff, bitsRowBytes); 1448 uint32 bmppixcol = 0, bmppixrow = 0; 1449 uint32 defaultcolor = *(uint32*)palette; 1450 // set bits output to last row in the image 1451 off_t bitsoffset = ((msheader.height - (bmppixrow + 1)) * bitsRowBytes) + 1452 (bmppixcol * 4); 1453 outDestination->Seek(bitsoffset, SEEK_CUR); 1454 ssize_t rd = inSource->Read(&count, 1); 1455 while (rd > 0) { 1456 // repeated color 1457 if (count) { 1458 // abort if all of the pixels in the row 1459 // have already been drawn to 1460 if (bmppixcol == msheader.width) { 1461 rd = -1; 1462 break; 1463 } 1464 // if count is greater than the number of 1465 // pixels remaining in the current row, 1466 // only process the correct number of pixels 1467 // remaining in the row 1468 if (count + bmppixcol > msheader.width) 1469 count = msheader.width - bmppixcol; 1470 1471 rd = inSource->Read(&indices, 1); 1472 if (rd != 1) { 1473 rd = -1; 1474 break; 1475 } 1476 for (uint8 i = 0; i < count; i++) { 1477 index = (indices >> (bitsPerPixel * ((pixelsPerByte - 1) - 1478 (i % pixelsPerByte)))) & mask; 1479 memcpy(bitsRowData + (bmppixcol*4), palette + (index*4), 3); 1480 bmppixcol++; 1481 } 1482 // special code 1483 } else { 1484 uint8 code; 1485 rd = inSource->Read(&code, 1); 1486 if (rd != 1) { 1487 rd = -1; 1488 break; 1489 } 1490 switch (code) { 1491 // end of line 1492 case 0: 1493 // if there are columns remaing on this 1494 // line, set them to the color at index zero 1495 if (bmppixcol < msheader.width) 1496 pixelcpy(bitsRowData + (bmppixcol * 4), 1497 defaultcolor, msheader.width - bmppixcol); 1498 outDestination->Write(bitsRowData, bitsRowBytes); 1499 bmppixcol = 0; 1500 bmppixrow++; 1501 if (bmppixrow < msheader.height) 1502 outDestination->Seek(bitsRowBytes * -2, SEEK_CUR); 1503 break; 1504 1505 // end of bitmap 1506 case 1: 1507 // if at the end of a row 1508 if (bmppixcol == msheader.width) { 1509 outDestination->Write(bitsRowData, bitsRowBytes); 1510 bmppixcol = 0; 1511 bmppixrow++; 1512 if (bmppixrow < msheader.height) 1513 outDestination->Seek(bitsRowBytes * -2, SEEK_CUR); 1514 } 1515 1516 while (bmppixrow < msheader.height) { 1517 pixelcpy(bitsRowData + (bmppixcol * 4), defaultcolor, 1518 msheader.width - bmppixcol); 1519 outDestination->Write(bitsRowData, bitsRowBytes); 1520 bmppixcol = 0; 1521 bmppixrow++; 1522 if (bmppixrow < msheader.height) 1523 outDestination->Seek(bitsRowBytes * -2, SEEK_CUR); 1524 } 1525 rd = 0; 1526 // break out of while loop 1527 break; 1528 1529 // delta, skip several rows and/or columns and 1530 // fill the skipped pixels with the default color 1531 case 2: 1532 { 1533 uint8 da[2], lastcol, dx, dy; 1534 rd = inSource->Read(da, 2); 1535 if (rd != 2) { 1536 rd = -1; 1537 break; 1538 } 1539 dx = da[0]; 1540 dy = da[1]; 1541 1542 // abort if dx or dy is too large 1543 if ((dx + bmppixcol >= msheader.width) || 1544 (dy + bmppixrow >= msheader.height)) { 1545 rd = -1; 1546 break; 1547 } 1548 1549 lastcol = bmppixcol; 1550 1551 // set all pixels to the first entry in 1552 // the palette, for the number of rows skipped 1553 while (dy > 0) { 1554 pixelcpy(bitsRowData + (bmppixcol * 4), defaultcolor, 1555 msheader.width - bmppixcol); 1556 outDestination->Write(bitsRowData, bitsRowBytes); 1557 bmppixcol = 0; 1558 bmppixrow++; 1559 dy--; 1560 outDestination->Seek(bitsRowBytes * -2, SEEK_CUR); 1561 } 1562 1563 if (bmppixcol < static_cast<uint32>(lastcol + dx)) { 1564 pixelcpy(bitsRowData + (bmppixcol * 4), defaultcolor, 1565 dx + lastcol - bmppixcol); 1566 bmppixcol = dx + lastcol; 1567 } 1568 1569 break; 1570 } 1571 1572 // code >= 3 1573 // read code uncompressed indices 1574 default: 1575 // abort if all of the pixels in the row 1576 // have already been drawn to 1577 if (bmppixcol == msheader.width) { 1578 rd = -1; 1579 break; 1580 } 1581 // if code is greater than the number of 1582 // pixels remaining in the current row, 1583 // only process the correct number of pixels 1584 // remaining in the row 1585 if (code + bmppixcol > msheader.width) 1586 code = msheader.width - bmppixcol; 1587 1588 uint8 uncomp[256]; 1589 int32 padding; 1590 if (!(code % pixelsPerByte)) 1591 padding = (code / pixelsPerByte) % 2; 1592 else 1593 padding = ((code + pixelsPerByte - 1594 (code % pixelsPerByte)) / pixelsPerByte) % 2; 1595 int32 uncompBytes = (code / pixelsPerByte) + 1596 ((code % pixelsPerByte) ? 1 : 0) + padding; 1597 rd = inSource->Read(uncomp, uncompBytes); 1598 if (rd != uncompBytes) { 1599 rd = -1; 1600 break; 1601 } 1602 for (uint8 i = 0; i < code; i++) { 1603 indices = (uncomp + (i / pixelsPerByte))[0]; 1604 index = (indices >> 1605 (bitsPerPixel * ((pixelsPerByte - 1) - 1606 (i % pixelsPerByte)))) & mask; 1607 memcpy(bitsRowData + (bmppixcol * 4), 1608 palette + (index * 4), 3); 1609 bmppixcol++; 1610 } 1611 1612 break; 1613 } 1614 } 1615 if (rd > 0) 1616 rd = inSource->Read(&count, 1); 1617 } 1618 1619 delete[] bitsRowData; 1620 1621 if (!rd) 1622 return B_OK; 1623 else 1624 return B_NO_TRANSLATOR; 1625 } 1626 1627 // --------------------------------------------------------------- 1628 // translate_from_bmp 1629 // 1630 // Convert the data in inSource from the BMP format 1631 // to the format specified in outType (either bits or BMP). 1632 // 1633 // Preconditions: 1634 // 1635 // Parameters: inSource, the bits data to translate 1636 // 1637 // outType, the type of data to convert to 1638 // 1639 // outDestination, where the output is written to 1640 // 1641 // Postconditions: 1642 // 1643 // Returns: B_NO_TRANSLATOR, if the data is not in a supported 1644 // format 1645 // 1646 // B_ERROR, if there was an error allocating memory or some other 1647 // error 1648 // 1649 // B_OK, if successfully translated the data from the bits format 1650 // --------------------------------------------------------------- 1651 status_t 1652 BMPTranslator::translate_from_bmp(BPositionIO *inSource, uint32 outType, 1653 BPositionIO *outDestination) 1654 { 1655 bool bheaderonly, bdataonly; 1656 bheaderonly = bdataonly = false; 1657 1658 BMPFileHeader fileHeader; 1659 MSInfoHeader msheader; 1660 bool frommsformat; 1661 off_t os2skip = 0; 1662 1663 status_t result; 1664 result = identify_bmp_header(inSource, NULL, &fileHeader, &msheader, 1665 &frommsformat, &os2skip); 1666 if (result != B_OK) { 1667 INFO("BMPTranslator::translate_from_bmp() - identify_bmp_header failed\n"); 1668 return result; 1669 } 1670 1671 // if the user wants to translate a BMP to a BMP, easy enough :) 1672 if (outType == B_BMP_FORMAT) { 1673 // write out the BMP headers 1674 if (bheaderonly || (!bheaderonly && !bdataonly)) { 1675 result = write_bmp_headers(outDestination, fileHeader, msheader); 1676 if (result != B_OK) 1677 return result; 1678 } 1679 if (bheaderonly) 1680 // if the user only wants the header, 1681 // bail before it is written 1682 return result; 1683 1684 uint8 buf[1024]; 1685 ssize_t rd; 1686 uint32 rdtotal = 54; 1687 if (!frommsformat && (msheader.bitsperpixel == 1 || 1688 msheader.bitsperpixel == 4 || msheader.bitsperpixel == 8)) { 1689 // if OS/2 paletted format, convert palette to MS format 1690 uint16 ncolors = 1 << msheader.bitsperpixel; 1691 rd = inSource->Read(buf, ncolors * 3); 1692 if (rd != ncolors * 3) 1693 return B_NO_TRANSLATOR; 1694 uint8 mspalent[4] = {0, 0, 0, 0}; 1695 for (uint16 i = 0; i < ncolors; i++) { 1696 memcpy(mspalent, buf + (i * 3), 3); 1697 outDestination->Write(mspalent, 4); 1698 } 1699 rdtotal = fileHeader.dataOffset; 1700 } 1701 // if there is junk between the OS/2 headers and 1702 // the actual data, skip it 1703 if (!frommsformat && os2skip) 1704 inSource->Seek(os2skip, SEEK_CUR); 1705 1706 rd = min(1024, fileHeader.fileSize - rdtotal); 1707 rd = inSource->Read(buf, rd); 1708 while (rd > 0) { 1709 outDestination->Write(buf, rd); 1710 rdtotal += rd; 1711 rd = min(1024, fileHeader.fileSize - rdtotal); 1712 rd = inSource->Read(buf, rd); 1713 } 1714 if (rd == 0) 1715 return B_OK; 1716 else 1717 return B_ERROR; 1718 1719 // if translating a BMP to a Be Bitmap 1720 } else if (outType == B_TRANSLATOR_BITMAP) { 1721 TranslatorBitmap bitsHeader; 1722 bitsHeader.magic = B_TRANSLATOR_BITMAP; 1723 bitsHeader.bounds.left = 0; 1724 bitsHeader.bounds.top = 0; 1725 bitsHeader.bounds.right = msheader.width - 1; 1726 bitsHeader.bounds.bottom = msheader.height - 1; 1727 1728 // read in palette and/or skip non-BMP data 1729 uint8 bmppalette[1024]; 1730 off_t nskip = 0; 1731 if (msheader.bitsperpixel == 1 || 1732 msheader.bitsperpixel == 4 || 1733 msheader.bitsperpixel == 8) { 1734 1735 uint8 palBytesPerPixel; 1736 if (frommsformat) 1737 palBytesPerPixel = 4; 1738 else 1739 palBytesPerPixel = 3; 1740 1741 if (!msheader.colorsused) 1742 msheader.colorsused = 1 << msheader.bitsperpixel; 1743 1744 if (inSource->Read(bmppalette, msheader.colorsused * 1745 palBytesPerPixel) != 1746 (off_t) msheader.colorsused * palBytesPerPixel) 1747 return B_NO_TRANSLATOR; 1748 1749 // skip over non-BMP data 1750 if (frommsformat) { 1751 if (fileHeader.dataOffset > (msheader.colorsused * 1752 palBytesPerPixel) + 54) 1753 nskip = fileHeader.dataOffset - 1754 ((msheader.colorsused * palBytesPerPixel) + 54); 1755 } else 1756 nskip = os2skip; 1757 } else if (fileHeader.dataOffset > 54) 1758 // skip over non-BMP data 1759 nskip = fileHeader.dataOffset - 54; 1760 1761 if (nskip > 0 && inSource->Seek(nskip, SEEK_CUR) < 0) 1762 return B_NO_TRANSLATOR; 1763 1764 bitsHeader.rowBytes = msheader.width * 4; 1765 bitsHeader.colors = B_RGB32; 1766 int32 datasize = bitsHeader.rowBytes * msheader.height; 1767 bitsHeader.dataSize = datasize; 1768 1769 // write out Be's Bitmap header 1770 if (bheaderonly || (!bheaderonly && !bdataonly)) { 1771 if (swap_data(B_UINT32_TYPE, &bitsHeader, 1772 sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK) 1773 return B_ERROR; 1774 outDestination->Write(&bitsHeader, sizeof(TranslatorBitmap)); 1775 } 1776 if (bheaderonly) 1777 // if the user only wants the header, 1778 // bail before the data is written 1779 return B_OK; 1780 1781 // write out the actual image data 1782 switch (msheader.bitsperpixel) { 1783 case 32: 1784 case 24: 1785 return translate_from_bmpnpal_to_bits(inSource, 1786 outDestination, msheader); 1787 1788 case 8: 1789 // 8 bit BMP with NO compression 1790 if (msheader.compression == BMP_NO_COMPRESS) 1791 return translate_from_bmppal_to_bits(inSource, 1792 outDestination, msheader, bmppalette, frommsformat); 1793 1794 // 8 bit RLE compressed BMP 1795 else if (msheader.compression == BMP_RLE8_COMPRESS) 1796 return translate_from_bmppalr_to_bits(inSource, 1797 outDestination, datasize, msheader, bmppalette); 1798 else 1799 return B_NO_TRANSLATOR; 1800 1801 case 4: 1802 // 4 bit BMP with NO compression 1803 if (!msheader.compression) 1804 return translate_from_bmppal_to_bits(inSource, 1805 outDestination, msheader, bmppalette, frommsformat); 1806 1807 // 4 bit RLE compressed BMP 1808 else if (msheader.compression == BMP_RLE4_COMPRESS) 1809 return translate_from_bmppalr_to_bits(inSource, 1810 outDestination, datasize, msheader, bmppalette); 1811 else 1812 return B_NO_TRANSLATOR; 1813 1814 case 1: 1815 return translate_from_bmppal_to_bits(inSource, 1816 outDestination, msheader, bmppalette, frommsformat); 1817 1818 default: 1819 return B_NO_TRANSLATOR; 1820 } 1821 1822 } else 1823 return B_NO_TRANSLATOR; 1824 } 1825 1826 // --------------------------------------------------------------- 1827 // DerivedTranslate 1828 // 1829 // Translates the data in inSource to the type outType and stores 1830 // the translated data in outDestination. 1831 // 1832 // Preconditions: 1833 // 1834 // Parameters: inSource, the data to be translated 1835 // 1836 // inInfo, hint about the data in inSource (not used) 1837 // 1838 // ioExtension, configuration options for the 1839 // translator 1840 // 1841 // outType, the type to convert inSource to 1842 // 1843 // outDestination, where the translated data is 1844 // put 1845 // 1846 // baseType, indicates whether inSource is in the 1847 // bits format, not in the bits format or 1848 // is unknown 1849 // 1850 // Postconditions: 1851 // 1852 // Returns: B_BAD_VALUE, if the options in ioExtension are bad 1853 // 1854 // B_NO_TRANSLATOR, if this translator doesn't understand the data 1855 // 1856 // B_ERROR, if there was an error allocating memory or converting 1857 // data 1858 // 1859 // B_OK, if all went well 1860 // --------------------------------------------------------------- 1861 status_t 1862 BMPTranslator::DerivedTranslate(BPositionIO *inSource, 1863 const translator_info *inInfo, BMessage *ioExtension, 1864 uint32 outType, BPositionIO *outDestination, int32 baseType) 1865 { 1866 if (baseType == 1) 1867 // if inSource is in bits format 1868 return translate_from_bits(inSource, outType, outDestination); 1869 else if (baseType == 0) 1870 // if inSource is NOT in bits format 1871 return translate_from_bmp(inSource, outType, outDestination); 1872 else 1873 return B_NO_TRANSLATOR; 1874 } 1875 1876 BView * 1877 BMPTranslator::NewConfigView(TranslatorSettings *settings) 1878 { 1879 return new BMPView(BRect(0, 0, 225, 175), "BMPTranslator Settings", 1880 B_FOLLOW_ALL, B_WILL_DRAW, settings); 1881 } 1882