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