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