2 * Copyright 2003-2009, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
7 * Stephan Aßmus <stippi@yellowbites.com> (write support)
11 #include "TIFFTranslator.h"
21 #undef B_TRANSLATION_CONTEXT
22 #define B_TRANSLATION_CONTEXT "TIFFTranslator"
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.
37 // The input formats that this translator supports.
38 static const translation_format sInputFormats
[] = {
45 "Be Bitmap Format (TIFFTranslator)"
57 // The output formats that this translator supports.
58 static const translation_format sOutputFormats
[] = {
65 "Be Bitmap Format (TIFFTranslator)"
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
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
);
90 // ---------------------------------------------------------------
91 // make_nth_translator
93 // Creates a TIFFTranslator object to be used by BTranslatorRoster
97 // Parameters: n, The translator to return. Since
98 // TIFFTranslator only publishes one
99 // translator, it only returns a
100 // TIFFTranslator if n == 0
102 // you, The image_id of the add-on that
103 // contains code (not used).
105 // flags, Has no meaning yet, should be 0.
109 // Returns: NULL if n is not zero,
110 // a new TIFFTranslator if n is zero
111 // ---------------------------------------------------------------
113 make_nth_translator(int32 n
, image_id you
, uint32 flags
, ...)
116 return new TIFFTranslator();
122 //// libtiff Callback functions!
125 tiff_get_pio(thandle_t stream
)
127 BPositionIO
*pio
= NULL
;
128 pio
= static_cast<BPositionIO
*>(stream
);
130 debugger("pio is NULL");
136 tiff_read_proc(thandle_t stream
, tdata_t buf
, tsize_t size
)
138 return tiff_get_pio(stream
)->Read(buf
, size
);
142 tiff_write_proc(thandle_t stream
, tdata_t buf
, tsize_t size
)
144 return tiff_get_pio(stream
)->Write(buf
, size
);
148 tiff_seek_proc(thandle_t stream
, toff_t off
, int whence
)
150 return tiff_get_pio(stream
)->Seek(off
, whence
);
154 tiff_close_proc(thandle_t stream
)
156 tiff_get_pio(stream
)->Seek(0, SEEK_SET
);
161 tiff_size_proc(thandle_t stream
)
163 BPositionIO
*pio
= tiff_get_pio(stream
);
165 cur
= pio
->Position();
166 end
= pio
->Seek(0, SEEK_END
);
167 pio
->Seek(cur
, SEEK_SET
);
173 tiff_map_file_proc(thandle_t stream
, tdata_t
*pbase
, toff_t
*psize
)
175 // BeOS doesn't support mmap() so just return 0
180 tiff_unmap_file_proc(thandle_t stream
, tdata_t base
, toff_t size
)
187 identify_tiff_header(BPositionIO
*inSource
, BMessage
*ioExtension
,
188 translator_info
*outInfo
, uint32 outType
, TIFF
**poutTIFF
= NULL
)
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
);
195 return B_NO_TRANSLATOR
;
197 // count number of documents
198 int32 documentCount
= 0, documentIndex
= 1;
201 } while (TIFFReadDirectory(tif
));
204 // Check if a document index has been specified
205 if (ioExtension
->FindInt32(DOCUMENT_INDEX
, &documentIndex
) != B_OK
)
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
;
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 "
221 return B_NO_TRANSLATOR
;
225 // add page count to ioExtension
226 ioExtension
->RemoveName(DOCUMENT_COUNT
);
227 ioExtension
->AddInt32(DOCUMENT_COUNT
, documentCount
);
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"));
241 // close TIFF if caller is not interested in TIFF handle
244 // leave TIFF open and return handle if caller needs it
253 // Following are a couple of functions,
255 // convert_buffer_* to convert a buffer in place to the TIFF native format
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.
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.
267 // convert_buffer_bgra_rgba
269 convert_buffer_bgra_rgba(uint8
* buffer
, uint32 rows
, uint32 width
,
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];
280 buffer
+= bytesPerRow
;
284 // convert_buffer_argb_rgba
286 convert_buffer_argb_rgba(uint8
* buffer
, uint32 rows
, uint32 width
,
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];
299 buffer
+= bytesPerRow
;
303 // convert_buffers_bgra_rgba
305 convert_buffers_bgra_rgba(uint8
* inBuffer
, uint8
* outBuffer
, uint32 rows
,
306 uint32 width
, uint32 bytesPerRow
)
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];
319 inBuffer
+= bytesPerRow
;
320 outBuffer
+= width
* 4;
324 // convert_buffers_argb_rgba
326 convert_buffers_argb_rgba(uint8
* inBuffer
, uint8
* outBuffer
, uint32 rows
,
327 uint32 width
, uint32 bytesPerRow
)
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];
340 inBuffer
+= bytesPerRow
;
341 outBuffer
+= width
* 4;
345 // convert_buffers_bgrX_rgb
347 convert_buffers_bgrX_rgb(uint8
* inBuffer
, uint8
* outBuffer
, uint32 rows
,
348 uint32 width
, uint32 bytesPerRow
, uint32 samplesPerPixel
)
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];
360 inHandle
+= samplesPerPixel
;
363 inBuffer
+= bytesPerRow
;
364 outBuffer
+= width
* 3;
368 // convert_buffers_rgbX_rgb
370 convert_buffers_rgbX_rgb(uint8
* inBuffer
, uint8
* outBuffer
, uint32 rows
,
371 uint32 width
, uint32 bytesPerRow
, uint32 samplesPerPixel
)
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
;
383 inBuffer
+= bytesPerRow
;
384 outBuffer
+= width
* 3;
389 // convert_buffers_cmap
391 convert_buffers_cmap(uint8
* inBuffer
, uint8
* outBuffer
, uint32 rows
,
392 uint32 width
, uint32 bytesPerRow
)
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
;
405 convert_buffer(color_space format
, uint8
* buffer
, uint32 rows
, uint32 width
,
410 convert_buffer_bgra_rgba(buffer
, rows
, width
, bytesPerRow
);
413 convert_buffer_argb_rgba(buffer
, rows
, width
, bytesPerRow
);
417 // these two cannot be encountered, since inBufferSize != bytesPerStrip
418 // (we're stripping the unused "alpha" channel 32->24 bits)
420 convert_buffers_bgrX_rgb(buffer
, buffer
, rows
, width
, bytesPerRow
, 3);
423 // buffer already has the correct format
427 // buffer already has the correct format
436 convert_buffers(color_space format
, uint8
* inBuffer
, uint8
* outBuffer
,
437 uint32 rows
, uint32 width
, uint32 bytesPerRow
)
441 convert_buffers_bgra_rgba(inBuffer
, outBuffer
, rows
, width
, bytesPerRow
);
444 convert_buffers_argb_rgba(inBuffer
, outBuffer
, rows
, width
, bytesPerRow
);
447 convert_buffers_bgrX_rgb(inBuffer
, outBuffer
, rows
, width
, bytesPerRow
, 4);
450 convert_buffers_rgbX_rgb(inBuffer
, outBuffer
, rows
, width
, bytesPerRow
, 4);
453 convert_buffers_bgrX_rgb(inBuffer
, outBuffer
, rows
, width
, bytesPerRow
, 3);
456 convert_buffers_rgbX_rgb(inBuffer
, outBuffer
, rows
, width
, bytesPerRow
, 3);
460 convert_buffers_cmap(inBuffer
, outBuffer
, rows
, width
, bytesPerRow
);
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.
474 write_tif_stream(TIFF
* tif
, BPositionIO
* inSource
, color_space format
,
475 uint32 width
, uint32 height
, uint32 bytesPerRow
,
476 uint32 rowsPerStrip
, uint32 dataSize
)
478 uint32 bytesPerStrip
= 0;
480 // set up the TIFF fields about what channels we write
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
;
495 TIFFSetField(tif
, TIFFTAG_SAMPLESPERPIXEL
, 3);
496 // going to write just the rgb channels
497 bytesPerStrip
= width
* 3 * rowsPerStrip
;
501 bytesPerStrip
= width
* rowsPerStrip
;
507 uint32 remaining
= dataSize
;
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
);
536 remaining
-= inBufferSize
;
537 read
= inSource
->Read(inBuffer
, min_c(inBufferSize
, remaining
));
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
);
552 // clean up output buffer
554 _TIFFfree(outBuffer
);
556 //printf("using one buffer\n");
557 // the input buffer is all we need, we convert it in place
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
);
571 remaining
-= inBufferSize
;
572 read
= inSource
->Read(inBuffer
, min_c(inBufferSize
, remaining
));
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
);
588 // clean up input buffer
591 // see if there was an error reading or writing the streams
593 // "written" may contain a more specific error
594 ret
= written
< 0 ? written
: B_ERROR
;
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
)
616 TIFFSetErrorHandler(NULL
);
620 TIFFTranslator::~TIFFTranslator()
626 TIFFTranslator::DerivedIdentify(BPositionIO
*inSource
,
627 const translation_format
*inFormat
, BMessage
*ioExtension
,
628 translator_info
*outInfo
, uint32 outType
)
630 return identify_tiff_header(inSource
, ioExtension
, outInfo
, outType
);
635 TIFFTranslator::translate_from_bits(BPositionIO
*inSource
, uint32 outType
,
636 BPositionIO
*outDestination
)
638 TranslatorBitmap bitsHeader
;
640 uint32 compression
= fSettings
->SetGetInt32(TIFF_SETTING_COMPRESSION
);
643 result
= identify_bits_header(inSource
, NULL
, &bitsHeader
);
647 // Translate B_TRANSLATOR_BITMAP to B_TIFF_FORMAT
648 if (outType
== B_TIFF_FORMAT
) {
649 // Set up TIFF header
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
);
656 return B_NO_TRANSLATOR
;
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
;
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";
672 case COMPRESSION_PACKBITS:
673 compressionString = "RLE";
675 case COMPRESSION_DEFLATE:
676 compressionString = "Deflate";
678 case COMPRESSION_LZW:
679 compressionString = "LZW";
681 case COMPRESSION_JPEG:
682 compressionString = "JPEG";
684 case COMPRESSION_JP2000:
685 compressionString = "JPEG2000";
688 if (compressionString)
689 printf("using compression: %s\n", compressionString);
691 printf("using unkown compression (%ld).\n", compression);
693 TIFFSetField(tif
, TIFFTAG_COMPRESSION
, compression
);
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
);
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
);
706 // set the rest of the fields according to the bitmap format
707 switch (bitsHeader
.colors
) {
709 // Output to 32-bit True Color TIFF (8 bits alpha)
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
);
729 // Output to 15-bit True Color TIFF
732 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 5);
733 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
734 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
735 bytesPerStrip = width * 2 * rowsPerStrip;
738 // Output to 8-bit Color Mapped TIFF 32 bits per color map entry
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();
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
;
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
);
764 // Output to 8-bit Black and White TIFF
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
);
774 /* // Output to 1-bit Black and White TIFF
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;
783 ret
= B_NO_TRANSLATOR
;
790 return B_NO_TRANSLATOR
;
794 TIFFTranslator::translate_from_tiff(BPositionIO
*inSource
, BMessage
*ioExtension
,
795 uint32 outType
, BPositionIO
*outDestination
)
797 status_t result
= B_NO_TRANSLATOR
;
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
804 // variables needing cleanup
806 uint32
*praster
= NULL
;
809 ret
= identify_tiff_header(inSource
, ioExtension
, NULL
, outType
, &ptif
);
811 if (outType
== B_TIFF_FORMAT
&& ret
== B_OK
&& ptif
) {
812 // if translating from TIFF to TIFF,
813 // just write out the entire TIFF
815 translate_direct_copy(inSource
, outDestination
);
819 while (ret
== B_OK
&& ptif
) {
820 // use while / break not for looping, but for
821 // cleaner goto like capability
824 // make certain there is no looping
826 uint32 width
= 0, height
= 0;
827 if (!TIFFGetField(ptif
, TIFFTAG_IMAGEWIDTH
, &width
)) {
828 result
= B_NO_TRANSLATOR
;
831 if (!TIFFGetField(ptif
, TIFFTAG_IMAGELENGTH
, &height
)) {
832 result
= B_NO_TRANSLATOR
;
836 npixels
= width
* height
;
837 praster
= static_cast<uint32
*>(_TIFFmalloc(npixels
* 4));
838 if (praster
&& TIFFReadRGBAImage(ptif
, width
, height
, praster
, 0)) {
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
) {
855 outDestination
->Write(&bitsHeader
, sizeof(TranslatorBitmap
));
859 // Convert raw RGBA data to B_RGBA32 colorspace
860 // and write out the results
861 uint8
*pbitsrow
= new uint8
[width
* 4];
863 result
= B_NO_MEMORY
;
866 uint8
*pras8
= reinterpret_cast<uint8
*>(praster
);
867 for (uint32 i
= 0; i
< height
; i
++) {
868 uint8
*pbits
, *prgba
;
870 prgba
= pras8
+ ((height
- (i
+ 1)) * width
* 4);
872 for (uint32 k
= 0; k
< width
; k
++) {
881 outDestination
->Write(pbitsrow
, width
* 4);
890 } // if (praster && TIFFReadRGBAImage(ptif, width, height, praster, 0))
892 } // while (ret == B_OK && ptif)
906 // ---------------------------------------------------------------
909 // Translates the data in inSource to the type outType and stores
910 // the translated data in outDestination.
914 // Parameters: inSource, the data to be translated
916 // inInfo, hint about the data in inSource (not used)
918 // ioExtension, configuration options for the
921 // outType, the type to convert inSource to
923 // outDestination, where the translated data is
926 // baseType, indicates whether inSource is in the
927 // bits format, not in the bits format or
932 // Returns: B_BAD_VALUE, if the options in ioExtension are bad
934 // B_NO_TRANSLATOR, if this translator doesn't understand the data
936 // B_ERROR, if there was an error allocating memory or converting
939 // B_OK, if all went well
940 // ---------------------------------------------------------------
942 TIFFTranslator::DerivedTranslate(BPositionIO
*inSource
,
943 const translator_info
*inInfo
, BMessage
*ioExtension
,
944 uint32 outType
, BPositionIO
*outDestination
, int32 baseType
)
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
);
953 // if BaseTranslator did not properly identify the data as
955 return B_NO_TRANSLATOR
;
959 TIFFTranslator::NewConfigView(TranslatorSettings
*settings
)
961 return new TIFFView(B_TRANSLATE("TIFFTranslator Settings"),
962 B_WILL_DRAW
, settings
);