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