vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / translators / tiff / TIFFTranslator.cpp
blob385fc631cf7ffc737062cdcdcdb5d59f42a9f9c7
1 /*
2 * Copyright 2003-2009, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Michael Wilber
7 * Stephan Aßmus <stippi@yellowbites.com> (write support)
8 */
11 #include "TIFFTranslator.h"
12 #include "TIFFView.h"
14 #include "tiffio.h"
16 #include <Catalog.h>
17 #include <stdio.h>
18 #include <string.h>
21 #undef B_TRANSLATION_CONTEXT
22 #define B_TRANSLATION_CONTEXT "TIFFTranslator"
25 /*!
26 How this works:
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[] = {
40 B_TRANSLATOR_BITMAP,
41 B_TRANSLATOR_BITMAP,
42 BBT_IN_QUALITY,
43 BBT_IN_CAPABILITY,
44 "image/x-be-bitmap",
45 "Be Bitmap Format (TIFFTranslator)"
48 B_TIFF_FORMAT,
49 B_TRANSLATOR_BITMAP,
50 TIFF_IN_QUALITY,
51 TIFF_IN_CAPABILITY,
52 "image/tiff",
53 "TIFF image"
57 // The output formats that this translator supports.
58 static const translation_format sOutputFormats[] = {
60 B_TRANSLATOR_BITMAP,
61 B_TRANSLATOR_BITMAP,
62 BBT_OUT_QUALITY,
63 BBT_OUT_CAPABILITY,
64 "image/x-be-bitmap",
65 "Be Bitmap Format (TIFFTranslator)"
68 B_TIFF_FORMAT,
69 B_TRANSLATOR_BITMAP,
70 TIFF_OUT_QUALITY,
71 TIFF_OUT_CAPABILITY,
72 "image/tiff",
73 "TIFF image"
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
95 // Preconditions:
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.
107 // Postconditions:
109 // Returns: NULL if n is not zero,
110 // a new TIFFTranslator if n is zero
111 // ---------------------------------------------------------------
112 BTranslator *
113 make_nth_translator(int32 n, image_id you, uint32 flags, ...)
115 if (!n)
116 return new TIFFTranslator();
117 else
118 return NULL;
122 //// libtiff Callback functions!
124 BPositionIO *
125 tiff_get_pio(thandle_t stream)
127 BPositionIO *pio = NULL;
128 pio = static_cast<BPositionIO *>(stream);
129 if (!pio)
130 debugger("pio is NULL");
132 return pio;
135 tsize_t
136 tiff_read_proc(thandle_t stream, tdata_t buf, tsize_t size)
138 return tiff_get_pio(stream)->Read(buf, size);
141 tsize_t
142 tiff_write_proc(thandle_t stream, tdata_t buf, tsize_t size)
144 return tiff_get_pio(stream)->Write(buf, size);
147 toff_t
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);
157 return 0;
160 toff_t
161 tiff_size_proc(thandle_t stream)
163 BPositionIO *pio = tiff_get_pio(stream);
164 off_t cur, end;
165 cur = pio->Position();
166 end = pio->Seek(0, SEEK_END);
167 pio->Seek(cur, SEEK_SET);
169 return end;
173 tiff_map_file_proc(thandle_t stream, tdata_t *pbase, toff_t *psize)
175 // BeOS doesn't support mmap() so just return 0
176 return 0;
179 void
180 tiff_unmap_file_proc(thandle_t stream, tdata_t base, toff_t size)
182 return;
186 status_t
187 identify_tiff_header(BPositionIO *inSource, BMessage *ioExtension,
188 translator_info *outInfo, uint32 outType, TIFF **poutTIFF = NULL)
190 // get TIFF handle
191 TIFF* tif = TIFFClientOpen("TIFFTranslator", "r", inSource,
192 tiff_read_proc, tiff_write_proc, tiff_seek_proc, tiff_close_proc,
193 tiff_size_proc, tiff_map_file_proc, tiff_unmap_file_proc);
194 if (!tif)
195 return B_NO_TRANSLATOR;
197 // count number of documents
198 int32 documentCount = 0, documentIndex = 1;
199 do {
200 documentCount++;
201 } while (TIFFReadDirectory(tif));
203 if (ioExtension) {
204 // Check if a document index has been specified
205 if (ioExtension->FindInt32(DOCUMENT_INDEX, &documentIndex) != B_OK)
206 documentIndex = 1;
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 "
220 "directory\n"));
221 return B_NO_TRANSLATOR;
224 if (ioExtension) {
225 // add page count to ioExtension
226 ioExtension->RemoveName(DOCUMENT_COUNT);
227 ioExtension->AddInt32(DOCUMENT_COUNT, documentCount);
230 if (outInfo) {
231 outInfo->type = B_TIFF_FORMAT;
232 outInfo->group = B_TRANSLATOR_BITMAP;
233 outInfo->quality = TIFF_IN_QUALITY;
234 outInfo->capability = TIFF_IN_CAPABILITY;
235 strcpy(outInfo->MIME, "image/tiff");
236 snprintf(outInfo->name, sizeof(outInfo->name),
237 B_TRANSLATE("TIFF image"));
240 if (!poutTIFF) {
241 // close TIFF if caller is not interested in TIFF handle
242 TIFFClose(tif);
243 } else {
244 // leave TIFF open and return handle if caller needs it
245 *poutTIFF = tif;
248 return B_OK;
252 // How this works:
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
268 inline void
269 convert_buffer_bgra_rgba(uint8* buffer, uint32 rows, uint32 width,
270 uint32 bytesPerRow)
272 for (uint32 y = 0; y < rows; y++) {
273 uint8* handle = buffer;
274 for (uint32 x = 0; x < width; x++) {
275 uint8 temp = handle[0];
276 handle[0] = handle[2];
277 handle[2] = temp;
278 handle += 4;
280 buffer += bytesPerRow;
284 // convert_buffer_argb_rgba
285 inline void
286 convert_buffer_argb_rgba(uint8* buffer, uint32 rows, uint32 width,
287 uint32 bytesPerRow)
289 for (uint32 y = 0; y < rows; y++) {
290 uint8* handle = buffer;
291 for (uint32 x = 0; x < width; x++) {
292 uint8 temp = handle[0];
293 handle[0] = handle[1];
294 handle[1] = handle[2];
295 handle[2] = handle[3];
296 handle[3] = temp;
297 handle += 4;
299 buffer += bytesPerRow;
303 // convert_buffers_bgra_rgba
304 inline void
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];
316 inHandle += 4;
317 outHandle += 4;
319 inBuffer += bytesPerRow;
320 outBuffer += width * 4;
324 // convert_buffers_argb_rgba
325 inline void
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];
337 inHandle += 4;
338 outHandle += 4;
340 inBuffer += bytesPerRow;
341 outBuffer += width * 4;
345 // convert_buffers_bgrX_rgb
346 inline void
347 convert_buffers_bgrX_rgb(uint8* inBuffer, uint8* outBuffer, uint32 rows,
348 uint32 width, uint32 bytesPerRow, uint32 samplesPerPixel)
350 for (uint32 y = 0; y < rows; y++) {
351 uint8* inHandle = inBuffer;
352 uint8* outHandle = outBuffer;
353 for (uint32 x = 0; x < width; x++) {
354 // the usage of temp is just in case inBuffer == outBuffer
355 // (see convert_buffer() for B_RGB24)
356 uint8 temp = inHandle[0];
357 outHandle[0] = inHandle[2];
358 outHandle[1] = inHandle[1];
359 outHandle[2] = temp;
360 inHandle += samplesPerPixel;
361 outHandle += 3;
363 inBuffer += bytesPerRow;
364 outBuffer += width * 3;
368 // convert_buffers_rgbX_rgb
369 inline void
370 convert_buffers_rgbX_rgb(uint8* inBuffer, uint8* outBuffer, uint32 rows,
371 uint32 width, uint32 bytesPerRow, uint32 samplesPerPixel)
373 for (uint32 y = 0; y < rows; y++) {
374 uint8* inHandle = inBuffer;
375 uint8* outHandle = outBuffer;
376 for (uint32 x = 0; x < width; x++) {
377 outHandle[0] = inHandle[0];
378 outHandle[1] = inHandle[1];
379 outHandle[2] = inHandle[2];
380 inHandle += samplesPerPixel;
381 outHandle += 3;
383 inBuffer += bytesPerRow;
384 outBuffer += width * 3;
389 // convert_buffers_cmap
390 inline void
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;
399 outBuffer += width;
403 // convert_buffer
404 inline void
405 convert_buffer(color_space format, uint8* buffer, uint32 rows, uint32 width,
406 uint32 bytesPerRow)
408 switch (format) {
409 case B_RGBA32:
410 convert_buffer_bgra_rgba(buffer, rows, width, bytesPerRow);
411 break;
412 case B_RGBA32_BIG:
413 convert_buffer_argb_rgba(buffer, rows, width, bytesPerRow);
414 break;
415 // case B_RGB32:
416 // case B_RGB32_BIG:
417 // these two cannot be encountered, since inBufferSize != bytesPerStrip
418 // (we're stripping the unused "alpha" channel 32->24 bits)
419 case B_RGB24:
420 convert_buffers_bgrX_rgb(buffer, buffer, rows, width, bytesPerRow, 3);
421 break;
422 // case B_RGB24_BIG:
423 // buffer already has the correct format
424 break;
425 // case B_CMAP8:
426 // case B_GRAY8:
427 // buffer already has the correct format
428 break;
429 default:
430 break;
434 // convert_buffers
435 inline void
436 convert_buffers(color_space format, uint8* inBuffer, uint8* outBuffer,
437 uint32 rows, uint32 width, uint32 bytesPerRow)
439 switch (format) {
440 case B_RGBA32:
441 convert_buffers_bgra_rgba(inBuffer, outBuffer, rows, width, bytesPerRow);
442 break;
443 case B_RGBA32_BIG:
444 convert_buffers_argb_rgba(inBuffer, outBuffer, rows, width, bytesPerRow);
445 break;
446 case B_RGB32:
447 convert_buffers_bgrX_rgb(inBuffer, outBuffer, rows, width, bytesPerRow, 4);
448 break;
449 case B_RGB32_BIG:
450 convert_buffers_rgbX_rgb(inBuffer, outBuffer, rows, width, bytesPerRow, 4);
451 break;
452 case B_RGB24:
453 convert_buffers_bgrX_rgb(inBuffer, outBuffer, rows, width, bytesPerRow, 3);
454 break;
455 case B_RGB24_BIG:
456 convert_buffers_rgbX_rgb(inBuffer, outBuffer, rows, width, bytesPerRow, 3);
457 break;
458 case B_CMAP8:
459 case B_GRAY8:
460 convert_buffers_cmap(inBuffer, outBuffer, rows, width, bytesPerRow);
461 break;
462 default:
463 break;
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.
472 // write_tif_stream
473 status_t
474 write_tif_stream(TIFF* tif, BPositionIO* inSource, color_space format,
475 uint32 width, uint32 height, uint32 bytesPerRow,
476 uint32 rowsPerStrip, uint32 dataSize)
478 uint32 bytesPerStrip = 0;
480 // set up the TIFF fields about what channels we write
481 switch (format) {
482 case B_RGBA32:
483 case B_RGBA32_BIG:
484 uint16 extraSamples[1];
485 extraSamples[0] = EXTRASAMPLE_UNASSALPHA;
486 TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, 1, extraSamples);
487 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 4);
488 // going to write rgb + alpha channels
489 bytesPerStrip = width * 4 * rowsPerStrip;
490 break;
491 case B_RGB32:
492 case B_RGB32_BIG:
493 case B_RGB24:
494 case B_RGB24_BIG:
495 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
496 // going to write just the rgb channels
497 bytesPerStrip = width * 3 * rowsPerStrip;
498 break;
499 case B_CMAP8:
500 case B_GRAY8:
501 bytesPerStrip = width * rowsPerStrip;
502 break;
503 default:
504 return B_BAD_VALUE;
507 uint32 remaining = dataSize;
508 status_t ret = B_OK;
509 // Write the information to the stream
510 uint32 inBufferSize = bytesPerRow * rowsPerStrip;
511 // allocate intermediate input buffer
512 uint8* inBuffer = (uint8*)_TIFFmalloc(inBufferSize);
513 ssize_t read, written = B_ERROR;
514 // bytesPerStrip is the size of the buffer that libtiff expects to write per strip
515 // it might be different to the size of the input buffer,
516 // if that one contains padding bytes at the end of each row
517 if (inBufferSize != bytesPerStrip) {
518 // allocate a second buffer
519 // (two buffers are needed since padding bytes have to be compensated for)
520 uint8* outBuffer = (uint8*)_TIFFmalloc(bytesPerStrip);
521 if (inBuffer && outBuffer) {
522 //printf("using two buffers\n");
523 read = inSource->Read(inBuffer, inBufferSize);
524 uint32 stripIndex = 0;
525 while (read == (ssize_t)inBufferSize) {
526 //printf("writing bytes: %ld (strip: %ld)\n", read, stripIndex);
527 // convert the buffers (channel order) and compensate
528 // for bytesPerRow != samplesPerRow (padding bytes)
529 convert_buffers(format, inBuffer, outBuffer,
530 rowsPerStrip, width, bytesPerRow);
531 // let libtiff write the encoded strip to the BPositionIO
532 written = TIFFWriteEncodedStrip(tif, stripIndex, outBuffer, bytesPerStrip);
533 stripIndex++;
534 if (written < B_OK)
535 break;
536 remaining -= inBufferSize;
537 read = inSource->Read(inBuffer, min_c(inBufferSize, remaining));
539 // write the rest of the remaining rows
540 if (read < (ssize_t)inBufferSize && read > 0) {
541 //printf("writing remaining bytes: %ld\n", read);
542 // convert the buffers (channel order) and compensate
543 // for bytesPerRow != samplesPerRow (padding bytes)
544 convert_buffers(format, inBuffer, outBuffer,
545 read / bytesPerRow, width, bytesPerRow);
546 // let libtiff write the encoded strip to the BPositionIO
547 written = TIFFWriteEncodedStrip(tif, stripIndex, outBuffer, read);
548 remaining -= read;
550 } else
551 ret = B_NO_MEMORY;
552 // clean up output buffer
553 if (outBuffer)
554 _TIFFfree(outBuffer);
555 } else {
556 //printf("using one buffer\n");
557 // the input buffer is all we need, we convert it in place
558 if (inBuffer) {
559 read = inSource->Read(inBuffer, inBufferSize);
560 uint32 stripIndex = 0;
561 while (read == (ssize_t)inBufferSize) {
562 //printf("writing bytes: %ld (strip: %ld)\n", read, stripIndex);
563 // convert the buffer (channel order)
564 convert_buffer(format, inBuffer,
565 rowsPerStrip, width, bytesPerRow);
566 // let libtiff write the encoded strip to the BPositionIO
567 written = TIFFWriteEncodedStrip(tif, stripIndex, inBuffer, bytesPerStrip);
568 stripIndex++;
569 if (written < 0)
570 break;
571 remaining -= inBufferSize;
572 read = inSource->Read(inBuffer, min_c(inBufferSize, remaining));
574 // write the rest of the remaining rows
575 if (read < (ssize_t)inBufferSize && read > 0) {
576 //printf("writing remaining bytes: %ld (strip: %ld)\n", read, stripIndex);
577 // convert the buffers (channel order) and compensate
578 // for bytesPerRow != samplesPerRow (padding bytes)
579 convert_buffer(format, inBuffer,
580 read / bytesPerRow, width, bytesPerRow);
581 // let libtiff write the encoded strip to the BPositionIO
582 written = TIFFWriteEncodedStrip(tif, stripIndex, inBuffer, read);
583 remaining -= read;
585 } else
586 ret = B_NO_MEMORY;
588 // clean up input buffer
589 if (inBuffer)
590 _TIFFfree(inBuffer);
591 // see if there was an error reading or writing the streams
592 if (remaining > 0)
593 // "written" may contain a more specific error
594 ret = written < 0 ? written : B_ERROR;
595 else
596 ret = B_OK;
598 return ret;
602 // #pragma mark -
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)
615 // TODO: for now!
616 TIFFSetErrorHandler(NULL);
620 TIFFTranslator::~TIFFTranslator()
625 status_t
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);
634 status_t
635 TIFFTranslator::translate_from_bits(BPositionIO *inSource, uint32 outType,
636 BPositionIO *outDestination)
638 TranslatorBitmap bitsHeader;
640 uint32 compression = fSettings->SetGetInt32(TIFF_SETTING_COMPRESSION);
642 status_t result;
643 result = identify_bits_header(inSource, NULL, &bitsHeader);
644 if (result != B_OK)
645 return result;
647 // Translate B_TRANSLATOR_BITMAP to B_TIFF_FORMAT
648 if (outType == B_TIFF_FORMAT) {
649 // Set up TIFF header
651 // get TIFF handle
652 TIFF* tif = TIFFClientOpen("TIFFTranslator", "w", outDestination,
653 tiff_read_proc, tiff_write_proc, tiff_seek_proc, tiff_close_proc,
654 tiff_size_proc, tiff_map_file_proc, tiff_unmap_file_proc);
655 if (!tif)
656 return B_NO_TRANSLATOR;
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";
671 break;
672 case COMPRESSION_PACKBITS:
673 compressionString = "RLE";
674 break;
675 case COMPRESSION_DEFLATE:
676 compressionString = "Deflate";
677 break;
678 case COMPRESSION_LZW:
679 compressionString = "LZW";
680 break;
681 case COMPRESSION_JPEG:
682 compressionString = "JPEG";
683 break;
684 case COMPRESSION_JP2000:
685 compressionString = "JPEG2000";
686 break;
688 if (compressionString)
689 printf("using compression: %s\n", compressionString);
690 else
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);
705 status_t ret = B_OK;
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)
710 case B_RGBA32:
711 case B_RGB32:
712 case B_RGB24:
713 case B_RGBA32_BIG:
714 case B_RGB32_BIG:
715 case B_RGB24_BIG:
716 // set the fields specific to this color space
717 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
718 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
719 // TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
720 // write the tiff stream
721 ret = write_tif_stream(tif, inSource, bitsHeader.colors,
722 width, height, bytesPerRow,
723 rowsPerStrip, dataSize);
724 break;
726 case B_CMYA32:
727 break;
729 // Output to 15-bit True Color TIFF
730 case B_RGB15:
731 case B_RGB15_BIG:
732 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 5);
733 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
734 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
735 bytesPerStrip = width * 2 * rowsPerStrip;
736 break;
738 // Output to 8-bit Color Mapped TIFF 32 bits per color map entry
739 case B_CMAP8: {
740 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
741 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
742 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
743 // convert the system palette to 16 bit values for libtiff
744 const color_map *map = system_colors();
745 if (map) {
746 uint16 red[256];
747 uint16 green[256];
748 uint16 blue[256];
749 for (uint32 i = 0; i < 256; i++) {
750 // scale 8 bits to 16 bits
751 red[i] = map->color_list[i].red * 256 + map->color_list[i].red;
752 green[i] = map->color_list[i].green * 256 + map->color_list[i].green;
753 blue[i] = map->color_list[i].blue * 256 + map->color_list[i].blue;
755 TIFFSetField(tif, TIFFTAG_COLORMAP, &red, &green, &blue);
756 // write the tiff stream
757 ret = write_tif_stream(tif, inSource, bitsHeader.colors,
758 width, height, bytesPerRow,
759 rowsPerStrip, dataSize);
760 } else
761 ret = B_ERROR;
762 break;
764 // Output to 8-bit Black and White TIFF
765 case B_GRAY8:
766 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
767 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
768 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
769 ret = write_tif_stream(tif, inSource, bitsHeader.colors,
770 width, height, bytesPerRow,
771 rowsPerStrip, dataSize);
772 break;
774 /* // Output to 1-bit Black and White TIFF
775 case B_GRAY1:
776 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1);
777 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 8);
778 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
779 bytesPerStrip = ((width + 7) / 8) * rowsPerStrip;
780 break;
782 default:
783 ret = B_NO_TRANSLATOR;
785 // Close the handle
786 TIFFClose(tif);
787 return ret;
789 } else
790 return B_NO_TRANSLATOR;
793 status_t
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
805 TIFF *ptif = NULL;
806 uint32 *praster = NULL;
808 status_t ret;
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
814 TIFFClose(ptif);
815 translate_direct_copy(inSource, outDestination);
816 return B_OK;
819 while (ret == B_OK && ptif) {
820 // use while / break not for looping, but for
821 // cleaner goto like capability
823 ret = B_ERROR;
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;
829 break;
831 if (!TIFFGetField(ptif, TIFFTAG_IMAGELENGTH, &height)) {
832 result = B_NO_TRANSLATOR;
833 break;
835 size_t npixels = 0;
836 npixels = width * height;
837 praster = static_cast<uint32 *>(_TIFFmalloc(npixels * 4));
838 if (praster && TIFFReadRGBAImage(ptif, width, height, praster, 0)) {
839 if (!bdataonly) {
840 // Construct and write Be bitmap header
841 TranslatorBitmap bitsHeader;
842 bitsHeader.magic = B_TRANSLATOR_BITMAP;
843 bitsHeader.bounds.left = 0;
844 bitsHeader.bounds.top = 0;
845 bitsHeader.bounds.right = width - 1;
846 bitsHeader.bounds.bottom = height - 1;
847 bitsHeader.rowBytes = 4 * width;
848 bitsHeader.colors = B_RGBA32;
849 bitsHeader.dataSize = bitsHeader.rowBytes * height;
850 if (swap_data(B_UINT32_TYPE, &bitsHeader,
851 sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK) {
852 result = B_ERROR;
853 break;
855 outDestination->Write(&bitsHeader, sizeof(TranslatorBitmap));
858 if (!bheaderonly) {
859 // Convert raw RGBA data to B_RGBA32 colorspace
860 // and write out the results
861 uint8 *pbitsrow = new uint8[width * 4];
862 if (!pbitsrow) {
863 result = B_NO_MEMORY;
864 break;
866 uint8 *pras8 = reinterpret_cast<uint8 *>(praster);
867 for (uint32 i = 0; i < height; i++) {
868 uint8 *pbits, *prgba;
869 pbits = pbitsrow;
870 prgba = pras8 + ((height - (i + 1)) * width * 4);
872 for (uint32 k = 0; k < width; k++) {
873 pbits[0] = prgba[2];
874 pbits[1] = prgba[1];
875 pbits[2] = prgba[0];
876 pbits[3] = prgba[3];
877 pbits += 4;
878 prgba += 4;
881 outDestination->Write(pbitsrow, width * 4);
883 delete[] pbitsrow;
884 pbitsrow = NULL;
887 result = B_OK;
888 break;
890 } // if (praster && TIFFReadRGBAImage(ptif, width, height, praster, 0))
892 } // while (ret == B_OK && ptif)
894 if (praster) {
895 _TIFFfree(praster);
896 praster = NULL;
898 if (ptif) {
899 TIFFClose(ptif);
900 ptif = NULL;
903 return result;
906 // ---------------------------------------------------------------
907 // DerivedTranslate
909 // Translates the data in inSource to the type outType and stores
910 // the translated data in outDestination.
912 // Preconditions:
914 // Parameters: inSource, the data to be translated
916 // inInfo, hint about the data in inSource (not used)
918 // ioExtension, configuration options for the
919 // translator
921 // outType, the type to convert inSource to
923 // outDestination, where the translated data is
924 // put
926 // baseType, indicates whether inSource is in the
927 // bits format, not in the bits format or
928 // is unknown
930 // Postconditions:
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
937 // data
939 // B_OK, if all went well
940 // ---------------------------------------------------------------
941 status_t
942 TIFFTranslator::DerivedTranslate(BPositionIO *inSource,
943 const translator_info *inInfo, BMessage *ioExtension,
944 uint32 outType, BPositionIO *outDestination, int32 baseType)
946 if (baseType == 1)
947 // if inSource is in bits format
948 return translate_from_bits(inSource, outType, outDestination);
949 else if (baseType == 0)
950 // if inSource is NOT in bits format
951 return translate_from_tiff(inSource, ioExtension, outType, outDestination);
952 else
953 // if BaseTranslator did not properly identify the data as
954 // bits or not bits
955 return B_NO_TRANSLATOR;
958 BView *
959 TIFFTranslator::NewConfigView(TranslatorSettings *settings)
961 return new TIFFView(B_TRANSLATE("TIFFTranslator Settings"),
962 B_WILL_DRAW, settings);