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