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