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