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