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. 45static 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. 65static 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 85static 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 92const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format); 93const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format); 94const 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// --------------------------------------------------------------- 119BTranslator * 120make_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 131BPositionIO * 132tiff_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 142tsize_t 143tiff_read_proc(thandle_t stream, tdata_t buf, tsize_t size) 144{ 145 return tiff_get_pio(stream)->Read(buf, size); 146} 147 148tsize_t 149tiff_write_proc(thandle_t stream, tdata_t buf, tsize_t size) 150{ 151 return tiff_get_pio(stream)->Write(buf, size); 152} 153 154toff_t 155tiff_seek_proc(thandle_t stream, toff_t off, int whence) 156{ 157 return tiff_get_pio(stream)->Seek(off, whence); 158} 159 160int 161tiff_close_proc(thandle_t stream) 162{ 163 tiff_get_pio(stream)->Seek(0, SEEK_SET); 164 return 0; 165} 166 167toff_t 168tiff_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 179int 180tiff_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 186void 187tiff_unmap_file_proc(thandle_t stream, tdata_t base, toff_t size) 188{ 189 return; 190} 191 192 193status_t 194identify_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 275inline void 276convert_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 292inline void 293convert_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 311inline void 312convert_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 332inline void 333convert_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 353inline void 354convert_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 376inline void 377convert_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 397inline void 398convert_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 411inline void 412convert_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 442inline void 443convert_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 480status_t 481write_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 612TIFFTranslator::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 627TIFFTranslator::~TIFFTranslator() 628{ 629} 630 631 632status_t 633TIFFTranslator::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 641status_t 642TIFFTranslator::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; 675switch (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} 695if (compressionString) 696printf("using compression: %s\n", compressionString); 697else 698printf("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 800status_t 801TIFFTranslator::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// --------------------------------------------------------------- 948status_t 949TIFFTranslator::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 965BView * 966TIFFTranslator::NewConfigView(TranslatorSettings *settings) 967{ 968 return new TIFFView(B_TRANSLATE("TIFFTranslator Settings"), 969 B_WILL_DRAW, settings); 970} 971