1 /* 2 * Copyright 2003-2009, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Wilber 7 * Stephan Aßmus <stippi@yellowbites.com> (write support) 8 */ 9 10 11 #include "TIFFTranslator.h" 12 #include "TIFFView.h" 13 14 #define TIFF_DISABLE_DEPRECATED 15 #include "tiffio.h" 16 17 #if __GNUC__ == 2 18 #define TIFF_UINT32_TYPE uint32 19 #else 20 #define TIFF_UINT32_TYPE uint32_t 21 #endif 22 23 #include <Catalog.h> 24 #include <stdio.h> 25 #include <string.h> 26 27 28 #undef B_TRANSLATION_CONTEXT 29 #define B_TRANSLATION_CONTEXT "TIFFTranslator" 30 31 32 /*! 33 How this works: 34 35 libtiff has a special version of TIFFOpen() that gets passed custom 36 functions for reading writing etc. and a handle. This handle in our case 37 is a BPositionIO object, which libtiff passes on to the functions for reading 38 writing etc. So when operations are performed on the TIFF* handle that is 39 returned by TIFFOpen(), libtiff uses the special reading writing etc 40 functions so that all stream io happens on the BPositionIO object. 41 */ 42 43 44 // The input formats that this translator supports. 45 static const translation_format sInputFormats[] = { 46 { 47 B_TRANSLATOR_BITMAP, 48 B_TRANSLATOR_BITMAP, 49 BBT_IN_QUALITY, 50 BBT_IN_CAPABILITY, 51 "image/x-be-bitmap", 52 "Be Bitmap Format (TIFFTranslator)" 53 }, 54 { 55 B_TIFF_FORMAT, 56 B_TRANSLATOR_BITMAP, 57 TIFF_IN_QUALITY, 58 TIFF_IN_CAPABILITY, 59 "image/tiff", 60 "TIFF image" 61 } 62 }; 63 64 // The output formats that this translator supports. 65 static const translation_format sOutputFormats[] = { 66 { 67 B_TRANSLATOR_BITMAP, 68 B_TRANSLATOR_BITMAP, 69 BBT_OUT_QUALITY, 70 BBT_OUT_CAPABILITY, 71 "image/x-be-bitmap", 72 "Be Bitmap Format (TIFFTranslator)" 73 }, 74 { 75 B_TIFF_FORMAT, 76 B_TRANSLATOR_BITMAP, 77 TIFF_OUT_QUALITY, 78 TIFF_OUT_CAPABILITY, 79 "image/tiff", 80 "TIFF image" 81 } 82 }; 83 84 // Default settings for the Translator 85 static const TranSetting sDefaultSettings[] = { 86 {B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false}, 87 {B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false}, 88 {TIFF_SETTING_COMPRESSION, TRAN_SETTING_INT32, COMPRESSION_LZW} 89 // Compression is LZW by default 90 }; 91 92 const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format); 93 const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format); 94 const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting); 95 96 97 // --------------------------------------------------------------- 98 // make_nth_translator 99 // 100 // Creates a TIFFTranslator object to be used by BTranslatorRoster 101 // 102 // Preconditions: 103 // 104 // Parameters: n, The translator to return. Since 105 // TIFFTranslator only publishes one 106 // translator, it only returns a 107 // TIFFTranslator if n == 0 108 // 109 // you, The image_id of the add-on that 110 // contains code (not used). 111 // 112 // flags, Has no meaning yet, should be 0. 113 // 114 // Postconditions: 115 // 116 // Returns: NULL if n is not zero, 117 // a new TIFFTranslator if n is zero 118 // --------------------------------------------------------------- 119 BTranslator * 120 make_nth_translator(int32 n, image_id you, uint32 flags, ...) 121 { 122 if (!n) 123 return new TIFFTranslator(); 124 else 125 return NULL; 126 } 127 128 129 //// libtiff Callback functions! 130 131 BPositionIO * 132 tiff_get_pio(thandle_t stream) 133 { 134 BPositionIO *pio = NULL; 135 pio = static_cast<BPositionIO *>(stream); 136 if (!pio) 137 debugger("pio is NULL"); 138 139 return pio; 140 } 141 142 tsize_t 143 tiff_read_proc(thandle_t stream, tdata_t buf, tsize_t size) 144 { 145 return tiff_get_pio(stream)->Read(buf, size); 146 } 147 148 tsize_t 149 tiff_write_proc(thandle_t stream, tdata_t buf, tsize_t size) 150 { 151 return tiff_get_pio(stream)->Write(buf, size); 152 } 153 154 toff_t 155 tiff_seek_proc(thandle_t stream, toff_t off, int whence) 156 { 157 return tiff_get_pio(stream)->Seek(off, whence); 158 } 159 160 int 161 tiff_close_proc(thandle_t stream) 162 { 163 tiff_get_pio(stream)->Seek(0, SEEK_SET); 164 return 0; 165 } 166 167 toff_t 168 tiff_size_proc(thandle_t stream) 169 { 170 BPositionIO *pio = tiff_get_pio(stream); 171 off_t cur, end; 172 cur = pio->Position(); 173 end = pio->Seek(0, SEEK_END); 174 pio->Seek(cur, SEEK_SET); 175 176 return end; 177 } 178 179 int 180 tiff_map_file_proc(thandle_t stream, tdata_t *pbase, toff_t *psize) 181 { 182 // BeOS doesn't support mmap() so just return 0 183 return 0; 184 } 185 186 void 187 tiff_unmap_file_proc(thandle_t stream, tdata_t base, toff_t size) 188 { 189 return; 190 } 191 192 193 status_t 194 identify_tiff_header(BPositionIO *inSource, BMessage *ioExtension, 195 translator_info *outInfo, uint32 outType, TIFF **poutTIFF = NULL) 196 { 197 // get TIFF handle 198 TIFF* tif = TIFFClientOpen("TIFFTranslator", "r", inSource, 199 tiff_read_proc, tiff_write_proc, tiff_seek_proc, tiff_close_proc, 200 tiff_size_proc, tiff_map_file_proc, tiff_unmap_file_proc); 201 if (!tif) 202 return B_NO_TRANSLATOR; 203 204 // count number of documents 205 int32 documentCount = 0, documentIndex = 1; 206 do { 207 documentCount++; 208 } while (TIFFReadDirectory(tif)); 209 210 if (ioExtension) { 211 // Check if a document index has been specified 212 if (ioExtension->FindInt32(DOCUMENT_INDEX, &documentIndex) != B_OK) 213 documentIndex = 1; 214 215 if (documentIndex < 1 || documentIndex > documentCount) { 216 // document index is invalid 217 fputs(B_TRANSLATE("identify_tiff_header: invalid " 218 "document index\n"), stderr); 219 return B_NO_TRANSLATOR; 220 } 221 } 222 223 // identify the document the user specified or the first document 224 // if the user did not specify which document they wanted to identify 225 if (!TIFFSetDirectory(tif, documentIndex - 1)) { 226 fputs(B_TRANSLATE("identify_tiff_header: couldn't set " 227 "directory\n"), stderr); 228 return B_NO_TRANSLATOR; 229 } 230 231 if (ioExtension) { 232 // add page count to ioExtension 233 ioExtension->RemoveName(DOCUMENT_COUNT); 234 ioExtension->AddInt32(DOCUMENT_COUNT, documentCount); 235 } 236 237 if (outInfo) { 238 outInfo->type = B_TIFF_FORMAT; 239 outInfo->group = B_TRANSLATOR_BITMAP; 240 outInfo->quality = TIFF_IN_QUALITY; 241 outInfo->capability = TIFF_IN_CAPABILITY; 242 strcpy(outInfo->MIME, "image/tiff"); 243 strlcpy(outInfo->name, B_TRANSLATE("TIFF image"), 244 sizeof(outInfo->name)); 245 } 246 247 if (!poutTIFF) { 248 // close TIFF if caller is not interested in TIFF handle 249 TIFFClose(tif); 250 } else { 251 // leave TIFF open and return handle if caller needs it 252 *poutTIFF = tif; 253 } 254 255 return B_OK; 256 } 257 258 259 // How this works: 260 // Following are a couple of functions, 261 // 262 // convert_buffer_* to convert a buffer in place to the TIFF native format 263 // 264 // convert_buffers_* to convert from one buffer to another to the TIFF 265 // native format, additionally compensating for padding bytes 266 // I don't know if libTIFF can be set up to respect padding bytes, 267 // otherwise this whole thing could be simplified a bit. 268 // 269 // Additionally, there are two functions convert_buffer() and convert_buffers() that take 270 // a color_space as one of the arguments and pick the correct worker functions from there. 271 // This way I don't write any code more than once, for easier debugging and maintainance. 272 273 274 // convert_buffer_bgra_rgba 275 inline void 276 convert_buffer_bgra_rgba(uint8* buffer, uint32 rows, uint32 width, 277 uint32 bytesPerRow) 278 { 279 for (uint32 y = 0; y < rows; y++) { 280 uint8* handle = buffer; 281 for (uint32 x = 0; x < width; x++) { 282 uint8 temp = handle[0]; 283 handle[0] = handle[2]; 284 handle[2] = temp; 285 handle += 4; 286 } 287 buffer += bytesPerRow; 288 } 289 } 290 291 // convert_buffer_argb_rgba 292 inline void 293 convert_buffer_argb_rgba(uint8* buffer, uint32 rows, uint32 width, 294 uint32 bytesPerRow) 295 { 296 for (uint32 y = 0; y < rows; y++) { 297 uint8* handle = buffer; 298 for (uint32 x = 0; x < width; x++) { 299 uint8 temp = handle[0]; 300 handle[0] = handle[1]; 301 handle[1] = handle[2]; 302 handle[2] = handle[3]; 303 handle[3] = temp; 304 handle += 4; 305 } 306 buffer += bytesPerRow; 307 } 308 } 309 310 // convert_buffers_bgra_rgba 311 inline void 312 convert_buffers_bgra_rgba(uint8* inBuffer, uint8* outBuffer, uint32 rows, 313 uint32 width, uint32 bytesPerRow) 314 { 315 for (uint32 y = 0; y < rows; y++) { 316 uint8* inHandle = inBuffer; 317 uint8* outHandle = outBuffer; 318 for (uint32 x = 0; x < width; x++) { 319 outHandle[0] = inHandle[2]; 320 outHandle[1] = inHandle[1]; 321 outHandle[2] = inHandle[0]; 322 outHandle[3] = inHandle[3]; 323 inHandle += 4; 324 outHandle += 4; 325 } 326 inBuffer += bytesPerRow; 327 outBuffer += width * 4; 328 } 329 } 330 331 // convert_buffers_argb_rgba 332 inline void 333 convert_buffers_argb_rgba(uint8* inBuffer, uint8* outBuffer, uint32 rows, 334 uint32 width, uint32 bytesPerRow) 335 { 336 for (uint32 y = 0; y < rows; y++) { 337 uint8* inHandle = inBuffer; 338 uint8* outHandle = outBuffer; 339 for (uint32 x = 0; x < width; x++) { 340 outHandle[0] = inHandle[1]; 341 outHandle[1] = inHandle[2]; 342 outHandle[2] = inHandle[3]; 343 outHandle[3] = inHandle[0]; 344 inHandle += 4; 345 outHandle += 4; 346 } 347 inBuffer += bytesPerRow; 348 outBuffer += width * 4; 349 } 350 } 351 352 // convert_buffers_bgrX_rgb 353 inline void 354 convert_buffers_bgrX_rgb(uint8* inBuffer, uint8* outBuffer, uint32 rows, 355 uint32 width, uint32 bytesPerRow, uint32 samplesPerPixel) 356 { 357 for (uint32 y = 0; y < rows; y++) { 358 uint8* inHandle = inBuffer; 359 uint8* outHandle = outBuffer; 360 for (uint32 x = 0; x < width; x++) { 361 // the usage of temp is just in case inBuffer == outBuffer 362 // (see convert_buffer() for B_RGB24) 363 uint8 temp = inHandle[0]; 364 outHandle[0] = inHandle[2]; 365 outHandle[1] = inHandle[1]; 366 outHandle[2] = temp; 367 inHandle += samplesPerPixel; 368 outHandle += 3; 369 } 370 inBuffer += bytesPerRow; 371 outBuffer += width * 3; 372 } 373 } 374 375 // convert_buffers_rgbX_rgb 376 inline void 377 convert_buffers_rgbX_rgb(uint8* inBuffer, uint8* outBuffer, uint32 rows, 378 uint32 width, uint32 bytesPerRow, uint32 samplesPerPixel) 379 { 380 for (uint32 y = 0; y < rows; y++) { 381 uint8* inHandle = inBuffer; 382 uint8* outHandle = outBuffer; 383 for (uint32 x = 0; x < width; x++) { 384 outHandle[0] = inHandle[0]; 385 outHandle[1] = inHandle[1]; 386 outHandle[2] = inHandle[2]; 387 inHandle += samplesPerPixel; 388 outHandle += 3; 389 } 390 inBuffer += bytesPerRow; 391 outBuffer += width * 3; 392 } 393 } 394 395 396 // convert_buffers_cmap 397 inline void 398 convert_buffers_cmap(uint8* inBuffer, uint8* outBuffer, uint32 rows, 399 uint32 width, uint32 bytesPerRow) 400 { 401 // compensate for bytesPerRow != width (padding bytes) 402 // this function will not be called if bytesPerRow == width, btw 403 for (uint32 y = 0; y < rows; y++) { 404 _TIFFmemcpy(outBuffer, inBuffer, width); 405 inBuffer += bytesPerRow; 406 outBuffer += width; 407 } 408 } 409 410 // convert_buffer 411 inline void 412 convert_buffer(color_space format, uint8* buffer, uint32 rows, uint32 width, 413 uint32 bytesPerRow) 414 { 415 switch (format) { 416 case B_RGBA32: 417 convert_buffer_bgra_rgba(buffer, rows, width, bytesPerRow); 418 break; 419 case B_RGBA32_BIG: 420 convert_buffer_argb_rgba(buffer, rows, width, bytesPerRow); 421 break; 422 // case B_RGB32: 423 // case B_RGB32_BIG: 424 // these two cannot be encountered, since inBufferSize != bytesPerStrip 425 // (we're stripping the unused "alpha" channel 32->24 bits) 426 case B_RGB24: 427 convert_buffers_bgrX_rgb(buffer, buffer, rows, width, bytesPerRow, 3); 428 break; 429 // case B_RGB24_BIG: 430 // buffer already has the correct format 431 break; 432 // case B_CMAP8: 433 // case B_GRAY8: 434 // buffer already has the correct format 435 break; 436 default: 437 break; 438 } 439 } 440 441 // convert_buffers 442 inline void 443 convert_buffers(color_space format, uint8* inBuffer, uint8* outBuffer, 444 uint32 rows, uint32 width, uint32 bytesPerRow) 445 { 446 switch (format) { 447 case B_RGBA32: 448 convert_buffers_bgra_rgba(inBuffer, outBuffer, rows, width, bytesPerRow); 449 break; 450 case B_RGBA32_BIG: 451 convert_buffers_argb_rgba(inBuffer, outBuffer, rows, width, bytesPerRow); 452 break; 453 case B_RGB32: 454 convert_buffers_bgrX_rgb(inBuffer, outBuffer, rows, width, bytesPerRow, 4); 455 break; 456 case B_RGB32_BIG: 457 convert_buffers_rgbX_rgb(inBuffer, outBuffer, rows, width, bytesPerRow, 4); 458 break; 459 case B_RGB24: 460 convert_buffers_bgrX_rgb(inBuffer, outBuffer, rows, width, bytesPerRow, 3); 461 break; 462 case B_RGB24_BIG: 463 convert_buffers_rgbX_rgb(inBuffer, outBuffer, rows, width, bytesPerRow, 3); 464 break; 465 case B_CMAP8: 466 case B_GRAY8: 467 convert_buffers_cmap(inBuffer, outBuffer, rows, width, bytesPerRow); 468 break; 469 default: 470 break; 471 } 472 } 473 474 // Sets up any additional TIFF fields for the color spaces it supports, 475 // determines if it needs one or two buffers to carry out any conversions, 476 // uses the various convert routines above to do the actual conversion, 477 // writes complete strips of data plus one strip of remaining data. 478 // 479 // write_tif_stream 480 status_t 481 write_tif_stream(TIFF* tif, BPositionIO* inSource, color_space format, 482 uint32 width, uint32 height, uint32 bytesPerRow, 483 uint32 rowsPerStrip, uint32 dataSize) 484 { 485 uint32 bytesPerStrip = 0; 486 487 // set up the TIFF fields about what channels we write 488 switch (format) { 489 case B_RGBA32: 490 case B_RGBA32_BIG: 491 uint16 extraSamples[1]; 492 extraSamples[0] = EXTRASAMPLE_UNASSALPHA; 493 TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, 1, extraSamples); 494 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 4); 495 // going to write rgb + alpha channels 496 bytesPerStrip = width * 4 * rowsPerStrip; 497 break; 498 case B_RGB32: 499 case B_RGB32_BIG: 500 case B_RGB24: 501 case B_RGB24_BIG: 502 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3); 503 // going to write just the rgb channels 504 bytesPerStrip = width * 3 * rowsPerStrip; 505 break; 506 case B_CMAP8: 507 case B_GRAY8: 508 bytesPerStrip = width * rowsPerStrip; 509 break; 510 default: 511 return B_BAD_VALUE; 512 } 513 514 uint32 remaining = dataSize; 515 status_t ret = B_OK; 516 // Write the information to the stream 517 uint32 inBufferSize = bytesPerRow * rowsPerStrip; 518 // allocate intermediate input buffer 519 uint8* inBuffer = (uint8*)_TIFFmalloc(inBufferSize); 520 ssize_t read, written = B_ERROR; 521 // bytesPerStrip is the size of the buffer that libtiff expects to write per strip 522 // it might be different to the size of the input buffer, 523 // if that one contains padding bytes at the end of each row 524 if (inBufferSize != bytesPerStrip) { 525 // allocate a second buffer 526 // (two buffers are needed since padding bytes have to be compensated for) 527 uint8* outBuffer = (uint8*)_TIFFmalloc(bytesPerStrip); 528 if (inBuffer && outBuffer) { 529 //printf("using two buffers\n"); 530 read = inSource->Read(inBuffer, inBufferSize); 531 uint32 stripIndex = 0; 532 while (read == (ssize_t)inBufferSize) { 533 //printf("writing bytes: %ld (strip: %ld)\n", read, stripIndex); 534 // convert the buffers (channel order) and compensate 535 // for bytesPerRow != samplesPerRow (padding bytes) 536 convert_buffers(format, inBuffer, outBuffer, 537 rowsPerStrip, width, bytesPerRow); 538 // let libtiff write the encoded strip to the BPositionIO 539 written = TIFFWriteEncodedStrip(tif, stripIndex, outBuffer, bytesPerStrip); 540 stripIndex++; 541 if (written < B_OK) 542 break; 543 remaining -= inBufferSize; 544 read = inSource->Read(inBuffer, min_c(inBufferSize, remaining)); 545 } 546 // write the rest of the remaining rows 547 if (read < (ssize_t)inBufferSize && read > 0) { 548 //printf("writing remaining bytes: %ld\n", read); 549 // convert the buffers (channel order) and compensate 550 // for bytesPerRow != samplesPerRow (padding bytes) 551 convert_buffers(format, inBuffer, outBuffer, 552 read / bytesPerRow, width, bytesPerRow); 553 // let libtiff write the encoded strip to the BPositionIO 554 written = TIFFWriteEncodedStrip(tif, stripIndex, outBuffer, read); 555 remaining -= read; 556 } 557 } else 558 ret = B_NO_MEMORY; 559 // clean up output buffer 560 if (outBuffer) 561 _TIFFfree(outBuffer); 562 } else { 563 //printf("using one buffer\n"); 564 // the input buffer is all we need, we convert it in place 565 if (inBuffer) { 566 read = inSource->Read(inBuffer, inBufferSize); 567 uint32 stripIndex = 0; 568 while (read == (ssize_t)inBufferSize) { 569 //printf("writing bytes: %ld (strip: %ld)\n", read, stripIndex); 570 // convert the buffer (channel order) 571 convert_buffer(format, inBuffer, 572 rowsPerStrip, width, bytesPerRow); 573 // let libtiff write the encoded strip to the BPositionIO 574 written = TIFFWriteEncodedStrip(tif, stripIndex, inBuffer, bytesPerStrip); 575 stripIndex++; 576 if (written < 0) 577 break; 578 remaining -= inBufferSize; 579 read = inSource->Read(inBuffer, min_c(inBufferSize, remaining)); 580 } 581 // write the rest of the remaining rows 582 if (read < (ssize_t)inBufferSize && read > 0) { 583 //printf("writing remaining bytes: %ld (strip: %ld)\n", read, stripIndex); 584 // convert the buffers (channel order) and compensate 585 // for bytesPerRow != samplesPerRow (padding bytes) 586 convert_buffer(format, inBuffer, 587 read / bytesPerRow, width, bytesPerRow); 588 // let libtiff write the encoded strip to the BPositionIO 589 written = TIFFWriteEncodedStrip(tif, stripIndex, inBuffer, read); 590 remaining -= read; 591 } 592 } else 593 ret = B_NO_MEMORY; 594 } 595 // clean up input buffer 596 if (inBuffer) 597 _TIFFfree(inBuffer); 598 // see if there was an error reading or writing the streams 599 if (remaining > 0) 600 // "written" may contain a more specific error 601 ret = written < 0 ? written : B_ERROR; 602 else 603 ret = B_OK; 604 605 return ret; 606 } 607 608 609 // #pragma mark - 610 611 612 TIFFTranslator::TIFFTranslator() 613 : BaseTranslator(B_TRANSLATE("TIFF images"), 614 B_TRANSLATE("TIFF image translator"), 615 TIFF_TRANSLATOR_VERSION, 616 sInputFormats, kNumInputFormats, 617 sOutputFormats, kNumOutputFormats, 618 "TIFFTranslator_Settings", 619 sDefaultSettings, kNumDefaultSettings, 620 B_TRANSLATOR_BITMAP, B_TIFF_FORMAT) 621 { 622 // TODO: for now! 623 TIFFSetErrorHandler(NULL); 624 } 625 626 627 TIFFTranslator::~TIFFTranslator() 628 { 629 } 630 631 632 status_t 633 TIFFTranslator::DerivedIdentify(BPositionIO *inSource, 634 const translation_format *inFormat, BMessage *ioExtension, 635 translator_info *outInfo, uint32 outType) 636 { 637 return identify_tiff_header(inSource, ioExtension, outInfo, outType); 638 } 639 640 641 status_t 642 TIFFTranslator::translate_from_bits(BPositionIO *inSource, uint32 outType, 643 BPositionIO *outDestination) 644 { 645 TranslatorBitmap bitsHeader; 646 647 uint32 compression = fSettings->SetGetInt32(TIFF_SETTING_COMPRESSION); 648 649 status_t result; 650 result = identify_bits_header(inSource, NULL, &bitsHeader); 651 if (result != B_OK) 652 return result; 653 654 // Translate B_TRANSLATOR_BITMAP to B_TIFF_FORMAT 655 if (outType == B_TIFF_FORMAT) { 656 // Set up TIFF header 657 658 // get TIFF handle 659 TIFF* tif = TIFFClientOpen("TIFFTranslator", "w", outDestination, 660 tiff_read_proc, tiff_write_proc, tiff_seek_proc, tiff_close_proc, 661 tiff_size_proc, tiff_map_file_proc, tiff_unmap_file_proc); 662 if (!tif) 663 return B_NO_TRANSLATOR; 664 665 // common fields which are independent of the bitmap format 666 uint32 width = bitsHeader.bounds.IntegerWidth() + 1; 667 uint32 height = bitsHeader.bounds.IntegerHeight() + 1; 668 uint32 dataSize = bitsHeader.dataSize; 669 uint32 bytesPerRow = bitsHeader.rowBytes; 670 671 TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width); 672 TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height); 673 TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); 674 /*const char* compressionString = NULL; 675 switch (compression) { 676 case COMPRESSION_NONE: 677 compressionString = "None"; 678 break; 679 case COMPRESSION_PACKBITS: 680 compressionString = "RLE"; 681 break; 682 case COMPRESSION_DEFLATE: 683 compressionString = "Deflate"; 684 break; 685 case COMPRESSION_LZW: 686 compressionString = "LZW"; 687 break; 688 case COMPRESSION_JPEG: 689 compressionString = "JPEG"; 690 break; 691 case COMPRESSION_JP2000: 692 compressionString = "JPEG2000"; 693 break; 694 } 695 if (compressionString) 696 printf("using compression: %s\n", compressionString); 697 else 698 printf("using unkown compression (%ld).\n", compression); 699 */ 700 TIFFSetField(tif, TIFFTAG_COMPRESSION, compression); 701 702 // TODO: some extra fields that should also get some special attention 703 TIFFSetField(tif, TIFFTAG_XRESOLUTION, 150.0); 704 TIFFSetField(tif, TIFFTAG_YRESOLUTION, 150.0); 705 TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); 706 707 // we are going to write XX row(s) of pixels (lines) per strip 708 uint32 rowsPerStrip = TIFFDefaultStripSize(tif, 0); 709 //printf("recommended rows per strip: %ld\n", TIFFDefaultStripSize(tif, 0)); 710 TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsPerStrip); 711 712 status_t ret = B_OK; 713 // set the rest of the fields according to the bitmap format 714 switch (bitsHeader.colors) { 715 716 // Output to 32-bit True Color TIFF (8 bits alpha) 717 case B_RGBA32: 718 case B_RGB32: 719 case B_RGB24: 720 case B_RGBA32_BIG: 721 case B_RGB32_BIG: 722 case B_RGB24_BIG: 723 // set the fields specific to this color space 724 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); 725 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); 726 // TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); 727 // write the tiff stream 728 ret = write_tif_stream(tif, inSource, bitsHeader.colors, 729 width, height, bytesPerRow, 730 rowsPerStrip, dataSize); 731 break; 732 /* 733 case B_CMYA32: 734 break; 735 736 // Output to 15-bit True Color TIFF 737 case B_RGB15: 738 case B_RGB15_BIG: 739 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 5); 740 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3); 741 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); 742 bytesPerStrip = width * 2 * rowsPerStrip; 743 break; 744 */ 745 // Output to 8-bit Color Mapped TIFF 32 bits per color map entry 746 case B_CMAP8: { 747 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE); 748 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); 749 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); 750 // convert the system palette to 16 bit values for libtiff 751 const color_map *map = system_colors(); 752 if (map) { 753 uint16 red[256]; 754 uint16 green[256]; 755 uint16 blue[256]; 756 for (uint32 i = 0; i < 256; i++) { 757 // scale 8 bits to 16 bits 758 red[i] = map->color_list[i].red * 256 + map->color_list[i].red; 759 green[i] = map->color_list[i].green * 256 + map->color_list[i].green; 760 blue[i] = map->color_list[i].blue * 256 + map->color_list[i].blue; 761 } 762 TIFFSetField(tif, TIFFTAG_COLORMAP, &red, &green, &blue); 763 // write the tiff stream 764 ret = write_tif_stream(tif, inSource, bitsHeader.colors, 765 width, height, bytesPerRow, 766 rowsPerStrip, dataSize); 767 } else 768 ret = B_ERROR; 769 break; 770 } 771 // Output to 8-bit Black and White TIFF 772 case B_GRAY8: 773 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); 774 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); 775 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); 776 ret = write_tif_stream(tif, inSource, bitsHeader.colors, 777 width, height, bytesPerRow, 778 rowsPerStrip, dataSize); 779 break; 780 781 /* // Output to 1-bit Black and White TIFF 782 case B_GRAY1: 783 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1); 784 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 8); 785 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); 786 bytesPerStrip = ((width + 7) / 8) * rowsPerStrip; 787 break; 788 */ 789 default: 790 ret = B_NO_TRANSLATOR; 791 } 792 // Close the handle 793 TIFFClose(tif); 794 return ret; 795 796 } else 797 return B_NO_TRANSLATOR; 798 } 799 800 status_t 801 TIFFTranslator::translate_from_tiff(BPositionIO *inSource, BMessage *ioExtension, 802 uint32 outType, BPositionIO *outDestination) 803 { 804 status_t result = B_NO_TRANSLATOR; 805 806 bool bheaderonly = false, bdataonly = false; 807 // Always write out the entire image. Some programs 808 // fail when given "headerOnly", even though they requested it. 809 // These settings are not applicable when outputting TIFFs 810 811 // variables needing cleanup 812 TIFF *ptif = NULL; 813 uint32 *praster = NULL; 814 815 status_t ret; 816 ret = identify_tiff_header(inSource, ioExtension, NULL, outType, &ptif); 817 818 if (outType == B_TIFF_FORMAT && ret == B_OK && ptif) { 819 // if translating from TIFF to TIFF, 820 // just write out the entire TIFF 821 TIFFClose(ptif); 822 translate_direct_copy(inSource, outDestination); 823 return B_OK; 824 } 825 826 while (ret == B_OK && ptif) { 827 // use while / break not for looping, but for 828 // cleaner goto like capability 829 830 ret = B_ERROR; 831 // make certain there is no looping 832 833 uint32 width = 0, height = 0; 834 if (!TIFFGetField(ptif, TIFFTAG_IMAGEWIDTH, &width)) { 835 result = B_NO_TRANSLATOR; 836 break; 837 } 838 if (!TIFFGetField(ptif, TIFFTAG_IMAGELENGTH, &height)) { 839 result = B_NO_TRANSLATOR; 840 break; 841 } 842 size_t npixels = 0; 843 npixels = width * height; 844 praster = static_cast<uint32 *>(_TIFFmalloc(npixels * 4)); 845 if (praster && TIFFReadRGBAImage(ptif, width, height, (TIFF_UINT32_TYPE*)praster, 0)) { 846 if (!bdataonly) { 847 // Construct and write Be bitmap header 848 TranslatorBitmap bitsHeader; 849 bitsHeader.magic = B_TRANSLATOR_BITMAP; 850 bitsHeader.bounds.left = 0; 851 bitsHeader.bounds.top = 0; 852 bitsHeader.bounds.right = width - 1; 853 bitsHeader.bounds.bottom = height - 1; 854 bitsHeader.rowBytes = 4 * width; 855 bitsHeader.colors = B_RGBA32; 856 bitsHeader.dataSize = bitsHeader.rowBytes * height; 857 if (swap_data(B_UINT32_TYPE, &bitsHeader, 858 sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK) { 859 result = B_ERROR; 860 break; 861 } 862 outDestination->Write(&bitsHeader, sizeof(TranslatorBitmap)); 863 } 864 865 if (!bheaderonly) { 866 // Convert raw RGBA data to B_RGBA32 colorspace 867 // and write out the results 868 uint8 *pbitsrow = new uint8[width * 4]; 869 if (!pbitsrow) { 870 result = B_NO_MEMORY; 871 break; 872 } 873 uint8 *pras8 = reinterpret_cast<uint8 *>(praster); 874 for (uint32 i = 0; i < height; i++) { 875 uint8 *pbits, *prgba; 876 pbits = pbitsrow; 877 prgba = pras8 + ((height - (i + 1)) * width * 4); 878 879 for (uint32 k = 0; k < width; k++) { 880 pbits[0] = prgba[2]; 881 pbits[1] = prgba[1]; 882 pbits[2] = prgba[0]; 883 pbits[3] = prgba[3]; 884 pbits += 4; 885 prgba += 4; 886 } 887 888 outDestination->Write(pbitsrow, width * 4); 889 } 890 delete[] pbitsrow; 891 pbitsrow = NULL; 892 } 893 894 result = B_OK; 895 break; 896 897 } // if (praster && TIFFReadRGBAImage(ptif, width, height, praster, 0)) 898 899 } // while (ret == B_OK && ptif) 900 901 if (praster) { 902 _TIFFfree(praster); 903 praster = NULL; 904 } 905 if (ptif) { 906 TIFFClose(ptif); 907 ptif = NULL; 908 } 909 910 return result; 911 } 912 913 // --------------------------------------------------------------- 914 // DerivedTranslate 915 // 916 // Translates the data in inSource to the type outType and stores 917 // the translated data in outDestination. 918 // 919 // Preconditions: 920 // 921 // Parameters: inSource, the data to be translated 922 // 923 // inInfo, hint about the data in inSource (not used) 924 // 925 // ioExtension, configuration options for the 926 // translator 927 // 928 // outType, the type to convert inSource to 929 // 930 // outDestination, where the translated data is 931 // put 932 // 933 // baseType, indicates whether inSource is in the 934 // bits format, not in the bits format or 935 // is unknown 936 // 937 // Postconditions: 938 // 939 // Returns: B_BAD_VALUE, if the options in ioExtension are bad 940 // 941 // B_NO_TRANSLATOR, if this translator doesn't understand the data 942 // 943 // B_ERROR, if there was an error allocating memory or converting 944 // data 945 // 946 // B_OK, if all went well 947 // --------------------------------------------------------------- 948 status_t 949 TIFFTranslator::DerivedTranslate(BPositionIO *inSource, 950 const translator_info *inInfo, BMessage *ioExtension, 951 uint32 outType, BPositionIO *outDestination, int32 baseType) 952 { 953 if (baseType == 1) 954 // if inSource is in bits format 955 return translate_from_bits(inSource, outType, outDestination); 956 else if (baseType == 0) 957 // if inSource is NOT in bits format 958 return translate_from_tiff(inSource, ioExtension, outType, outDestination); 959 else 960 // if BaseTranslator did not properly identify the data as 961 // bits or not bits 962 return B_NO_TRANSLATOR; 963 } 964 965 BView * 966 TIFFTranslator::NewConfigView(TranslatorSettings *settings) 967 { 968 return new TIFFView(B_TRANSLATE("TIFFTranslator Settings"), 969 B_WILL_DRAW, settings); 970 } 971