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