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