xref: /haiku/src/add-ons/translators/bmp/BMPTranslator.cpp (revision cec6d794428b86df22e5b1bec0d5af2d7b541a4a)
1 /*
2  * Copyright 2002-2009, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Wilber <mwilber@users.berlios.de>
7  */
8 
9 #include "BMPTranslator.h"
10 
11 #include <algorithm>
12 #include <new>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #include <Catalog.h>
18 
19 #include "BMPView.h"
20 
21 
22 using std::nothrow;
23 using std::min;
24 
25 
26 //#define INFO(x) printf(x);
27 #define INFO(x)
28 //#define ERROR(x) printf(x);
29 #define ERROR(x)
30 
31 #undef B_TRANSLATION_CONTEXT
32 #define B_TRANSLATION_CONTEXT "BMPTranslator"
33 
34 
35 // The input formats that this translator supports.
36 static const translation_format sInputFormats[] = {
37 	{
38 		B_TRANSLATOR_BITMAP,
39 		B_TRANSLATOR_BITMAP,
40 		BBT_IN_QUALITY,
41 		BBT_IN_CAPABILITY,
42 		"image/x-be-bitmap",
43 		"Be Bitmap Format (BMPTranslator)"
44 	},
45 	{
46 		B_BMP_FORMAT,
47 		B_TRANSLATOR_BITMAP,
48 		BMP_IN_QUALITY,
49 		BMP_IN_CAPABILITY,
50 		"image/bmp",
51 		"BMP image"
52 	}
53 };
54 
55 // The output formats that this translator supports.
56 static const translation_format sOutputFormats[] = {
57 	{
58 		B_TRANSLATOR_BITMAP,
59 		B_TRANSLATOR_BITMAP,
60 		BBT_OUT_QUALITY,
61 		BBT_OUT_CAPABILITY,
62 		"image/x-be-bitmap",
63 		"Be Bitmap Format (BMPTranslator)"
64 	},
65 	{
66 		B_BMP_FORMAT,
67 		B_TRANSLATOR_BITMAP,
68 		BMP_OUT_QUALITY,
69 		BMP_OUT_CAPABILITY,
70 		"image/bmp",
71 		"BMP image"
72 	}
73 };
74 
75 // Default settings for the Translator
76 static const TranSetting sDefaultSettings[] = {
77 	{B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false},
78 	{B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false}
79 };
80 
81 const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format);
82 const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format);
83 const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting);
84 
85 
86 // ---------------------------------------------------------------
87 // make_nth_translator
88 //
89 // Creates a BMPTranslator object to be used by BTranslatorRoster
90 //
91 // Preconditions:
92 //
93 // Parameters: n,		The translator to return. Since
94 //						BMPTranslator only publishes one
95 //						translator, it only returns a
96 //						BMPTranslator if n == 0
97 //
98 //             you, 	The image_id of the add-on that
99 //						contains code (not used).
100 //
101 //             flags,	Has no meaning yet, should be 0.
102 //
103 // Postconditions:
104 //
105 // Returns: NULL if n is not zero,
106 //          a new BMPTranslator if n is zero
107 // ---------------------------------------------------------------
108 BTranslator *
make_nth_translator(int32 n,image_id you,uint32 flags,...)109 make_nth_translator(int32 n, image_id you, uint32 flags, ...)
110 {
111 	if (!n)
112 		return new BMPTranslator();
113 	else
114 		return NULL;
115 }
116 
117 // ---------------------------------------------------------------
118 // Constructor
119 //
120 // Sets up the version info and the name of the translator so that
121 // these values can be returned when they are requested.
122 //
123 // Preconditions:
124 //
125 // Parameters:
126 //
127 // Postconditions:
128 //
129 // Returns:
130 // ---------------------------------------------------------------
BMPTranslator()131 BMPTranslator::BMPTranslator()
132 	: BaseTranslator(B_TRANSLATE("BMP images"),
133 		B_TRANSLATE("BMP image translator"),
134 		BMP_TRANSLATOR_VERSION,
135 		sInputFormats, kNumInputFormats,
136 		sOutputFormats, kNumOutputFormats,
137 		"BMPTranslator_Settings",
138 		sDefaultSettings, kNumDefaultSettings,
139 		B_TRANSLATOR_BITMAP, B_BMP_FORMAT)
140 {
141 }
142 
143 // ---------------------------------------------------------------
144 // Destructor
145 //
146 // Does nothing
147 //
148 // Preconditions:
149 //
150 // Parameters:
151 //
152 // Postconditions:
153 //
154 // Returns:
155 // ---------------------------------------------------------------
~BMPTranslator()156 BMPTranslator::~BMPTranslator()
157 {
158 }
159 
160 // ---------------------------------------------------------------
161 // get_padding
162 //
163 // Returns number of bytes of padding required at the end of
164 // the row by the BMP format
165 //
166 //
167 // Preconditions: If bitsperpixel is zero, a division by zero
168 //                will occur, which is bad
169 //
170 // Parameters:	width, width of the row, in pixels
171 //
172 //				bitsperpixel, bitdepth of the image
173 //
174 // Postconditions:
175 //
176 // Returns:
177 // ---------------------------------------------------------------
178 int32
get_padding(uint32 width,uint16 bitsperpixel)179 get_padding(uint32 width, uint16 bitsperpixel)
180 {
181 	int32 padding = 0;
182 
183 	if (bitsperpixel > 8) {
184 		uint8 bytesPerPixel = bitsperpixel / 8;
185 		padding = (width * bytesPerPixel) % 4;
186 	} else {
187 		uint8 pixelsPerByte = 8 / bitsperpixel;
188 		if (!(width % pixelsPerByte))
189 			padding = (width / pixelsPerByte) % 4;
190 		else
191 			padding = ((width + pixelsPerByte -
192 				(width % pixelsPerByte)) /
193 					pixelsPerByte) % 4;
194 	}
195 
196 	if (padding)
197 		padding = 4 - padding;
198 
199 	return padding;
200 }
201 
202 // ---------------------------------------------------------------
203 // get_rowbytes
204 //
205 // Returns number of bytes required to store a row of BMP pixels
206 // with a width of width and a bit depth of bitsperpixel.
207 //
208 //
209 // Preconditions: If bitsperpixel is zero, a division by zero
210 //                will occur, which is bad
211 //
212 // Parameters:	width, width of the row, in pixels
213 //
214 //				bitsperpixel, bitdepth of the image
215 //
216 // Postconditions:
217 //
218 // Returns:
219 // ---------------------------------------------------------------
220 int32
get_rowbytes(uint32 width,uint16 bitsperpixel)221 get_rowbytes(uint32 width, uint16 bitsperpixel)
222 {
223 	int32 rowbytes = 0;
224 	int32 padding = get_padding(width, bitsperpixel);
225 
226 	if (bitsperpixel > 8) {
227 		uint8 bytesPerPixel = bitsperpixel / 8;
228 		rowbytes = (width * bytesPerPixel) + padding;
229 	} else {
230 		uint8 pixelsPerByte = 8 / bitsperpixel;
231 		rowbytes = (width / pixelsPerByte) +
232 			((width % pixelsPerByte) ? 1 : 0) + padding;
233 	}
234 
235 	return rowbytes;
236 }
237 
238 // ---------------------------------------------------------------
239 // identify_bmp_header
240 //
241 // Determines if the data in inSource is in the MS or OS/2 BMP
242 // format. If it is, it returns info about the data in inSource
243 // to outInfo, pfileheader, pmsheader, pfrommsformat and os2skip.
244 //
245 // Preconditions:
246 //
247 // Parameters:	inSource,	The source of the image data
248 //
249 //				outInfo,	Information about the translator
250 //							is copied here
251 //
252 //				amtread,	Amount of data read from inSource
253 //							before this function was called
254 //
255 //				read,		Pointer to the data that was read
256 // 							in before this function was called
257 //
258 //				pfileheader,	File header info for the BMP is
259 //								copied here after it is read from
260 //								the file.
261 //
262 //				pmsheader,		BMP header info read in from the
263 //								BMP file
264 //
265 //				pfrommsformat,	Set to true if BMP data is BMP
266 //								format, false if BMP data is OS/2
267 //								format.
268 //
269 //				pos2skip,	If data is in OS/2 format, the number
270 //							of bytes to skip between the header
271 //							data and image data is stored here
272 //
273 // Postconditions:
274 //
275 // Returns: B_NO_TRANSLATOR,	if the data does not look like
276 //								BMP format data
277 //
278 // B_ERROR,	if the header data could not be converted to host
279 //			format
280 //
281 // B_OK,	if the data looks like bits data and no errors were
282 //			encountered
283 // ---------------------------------------------------------------
284 status_t
identify_bmp_header(BPositionIO * inSource,translator_info * outInfo,BMPFileHeader * pfileheader=NULL,MSInfoHeader * pmsheader=NULL,bool * pfrommsformat=NULL,off_t * pos2skip=NULL)285 identify_bmp_header(BPositionIO *inSource, translator_info *outInfo,
286 	BMPFileHeader *pfileheader = NULL, MSInfoHeader *pmsheader = NULL,
287 	bool *pfrommsformat = NULL, off_t *pos2skip = NULL)
288 {
289 	// read in the fileHeader
290 	uint8 buf[40];
291 	BMPFileHeader fileHeader;
292 	ssize_t size = 14;
293 	if (inSource->Read(buf, size) != size)
294 		return B_NO_TRANSLATOR;
295 
296 	// check BMP magic number
297 	const uint16 kBmpMagic = B_HOST_TO_LENDIAN_INT16('MB');
298 	uint16 sourceMagic;
299 	memcpy(&sourceMagic, buf, sizeof(uint16));
300 	if (sourceMagic != kBmpMagic)
301 		return B_NO_TRANSLATOR;
302 
303 	// convert fileHeader to host byte order
304 	memcpy(&fileHeader.magic, buf, 2);
305 	memcpy(&fileHeader.fileSize, buf + 2, 4);
306 	memcpy(&fileHeader.reserved, buf + 6, 4);
307 	memcpy(&fileHeader.dataOffset, buf + 10, 4);
308 	if (swap_data(B_UINT16_TYPE, &fileHeader.magic, sizeof(uint16),
309 		B_SWAP_LENDIAN_TO_HOST) != B_OK)
310 		return B_ERROR;
311 	if (swap_data(B_UINT32_TYPE,
312 		(reinterpret_cast<uint8 *> (&fileHeader)) + 2, 12,
313 		B_SWAP_LENDIAN_TO_HOST) != B_OK)
314 		return B_ERROR;
315 
316 	if (fileHeader.reserved != 0)
317 		return B_NO_TRANSLATOR;
318 
319 	uint32 headersize = 0;
320 	if (inSource->Read(&headersize, 4) != 4)
321 		return B_NO_TRANSLATOR;
322 	if (swap_data(B_UINT32_TYPE, &headersize, 4,
323 		B_SWAP_LENDIAN_TO_HOST) != B_OK)
324 		return B_ERROR;
325 
326 	if (headersize == sizeof(MSInfoHeader)) {
327 		// MS format
328 
329 		if (fileHeader.dataOffset < 54)
330 			return B_NO_TRANSLATOR;
331 
332 		MSInfoHeader msheader;
333 		msheader.size = headersize;
334 		if (inSource->Read(
335 			reinterpret_cast<uint8 *> (&msheader) + 4, 36) != 36)
336 			return B_NO_TRANSLATOR;
337 
338 		// convert msheader to host byte order
339 		if (swap_data(B_UINT32_TYPE,
340 			reinterpret_cast<uint8 *> (&msheader) + 4, 36,
341 			B_SWAP_LENDIAN_TO_HOST) != B_OK)
342 			return B_ERROR;
343 
344 		// check if msheader is valid
345 		if (msheader.width == 0 || msheader.height == 0)
346 			return B_NO_TRANSLATOR;
347 		if (msheader.planes != 1)
348 			return B_NO_TRANSLATOR;
349 		if ((msheader.bitsperpixel != 1 ||
350 				msheader.compression != BMP_NO_COMPRESS) &&
351 			(msheader.bitsperpixel != 4 ||
352 				msheader.compression != BMP_NO_COMPRESS) &&
353 			(msheader.bitsperpixel != 4 ||
354 				msheader.compression != BMP_RLE4_COMPRESS) &&
355 			(msheader.bitsperpixel != 8 ||
356 				msheader.compression != BMP_NO_COMPRESS) &&
357 			(msheader.bitsperpixel != 8 ||
358 				msheader.compression != BMP_RLE8_COMPRESS) &&
359 			(msheader.bitsperpixel != 24 ||
360 				msheader.compression != BMP_NO_COMPRESS) &&
361 			(msheader.bitsperpixel != 32 ||
362 				msheader.compression != BMP_NO_COMPRESS))
363 			return B_NO_TRANSLATOR;
364 		if (!msheader.imagesize && msheader.compression)
365 			return B_NO_TRANSLATOR;
366 		if (msheader.colorsimportant > msheader.colorsused)
367 			return B_NO_TRANSLATOR;
368 
369 		if (outInfo) {
370 			outInfo->type = B_BMP_FORMAT;
371 			outInfo->group = B_TRANSLATOR_BITMAP;
372 			outInfo->quality = BMP_IN_QUALITY;
373 			outInfo->capability = BMP_IN_CAPABILITY;
374 			sprintf(outInfo->name,
375 				B_TRANSLATE_COMMENT("BMP image (MS format, %d bits",
376 				"Ignore missing closing round bracket"),
377 				msheader.bitsperpixel);
378 			if (msheader.compression)
379 				strcat(outInfo->name, ", RLE)");
380 			else
381 				strcat(outInfo->name, ")");
382 			strcpy(outInfo->MIME, "image/x-bmp");
383 		}
384 
385 		if (pfileheader) {
386 			pfileheader->magic = fileHeader.magic;
387 			pfileheader->fileSize = fileHeader.fileSize;
388 			pfileheader->reserved = fileHeader.reserved;
389 			pfileheader->dataOffset = fileHeader.dataOffset;
390 		}
391 		if (pmsheader) {
392 			pmsheader->size = msheader.size;
393 			pmsheader->width = abs(msheader.width);
394 			pmsheader->height = msheader.height;
395 			pmsheader->planes = msheader.planes;
396 			pmsheader->bitsperpixel = msheader.bitsperpixel;
397 			pmsheader->compression = msheader.compression;
398 			pmsheader->imagesize = msheader.imagesize;
399 			pmsheader->xpixperm = msheader.xpixperm;
400 			pmsheader->ypixperm = msheader.ypixperm;
401 			pmsheader->colorsused = msheader.colorsused;
402 			pmsheader->colorsimportant = msheader.colorsimportant;
403 		}
404 		if (pfrommsformat)
405 			(*pfrommsformat) = true;
406 
407 		return B_OK;
408 
409 	} else if (headersize == sizeof(OS2InfoHeader)) {
410 		// OS/2 format
411 
412 		if (fileHeader.dataOffset < 26)
413 			return B_NO_TRANSLATOR;
414 
415 		OS2InfoHeader os2header;
416 		os2header.size = headersize;
417 		if (inSource->Read(
418 			reinterpret_cast<uint8 *> (&os2header) + 4, 8) != 8)
419 			return B_NO_TRANSLATOR;
420 
421 		// convert msheader to host byte order
422 		if (swap_data(B_UINT32_TYPE,
423 			reinterpret_cast<uint8 *> (&os2header) + 4, 8,
424 			B_SWAP_LENDIAN_TO_HOST) != B_OK)
425 			return B_ERROR;
426 
427 		// check if msheader is valid
428 		if (os2header.width == 0 || os2header.height == 0)
429 			return B_NO_TRANSLATOR;
430 		if (os2header.planes != 1)
431 			return B_NO_TRANSLATOR;
432 		if (os2header.bitsperpixel != 1 &&
433 			os2header.bitsperpixel != 4 &&
434 			os2header.bitsperpixel != 8 &&
435 			os2header.bitsperpixel != 24)
436 			return B_NO_TRANSLATOR;
437 
438 		if (outInfo) {
439 			outInfo->type = B_BMP_FORMAT;
440 			outInfo->group = B_TRANSLATOR_BITMAP;
441 			outInfo->quality = BMP_IN_QUALITY;
442 			outInfo->capability = BMP_IN_CAPABILITY;
443 			sprintf(outInfo->name, B_TRANSLATE("BMP image (OS/2 format, "
444 				"%d bits)"), os2header.bitsperpixel);
445 			strcpy(outInfo->MIME, "image/x-bmp");
446 		}
447 		if (pfileheader && pmsheader) {
448 			pfileheader->magic = 'MB';
449 			pfileheader->fileSize = 0;
450 			pfileheader->reserved = 0;
451 			pfileheader->dataOffset = 0;
452 
453 			pmsheader->size = 40;
454 			pmsheader->width = os2header.width;
455 			pmsheader->height = os2header.height;
456 			pmsheader->planes = 1;
457 			pmsheader->bitsperpixel = os2header.bitsperpixel;
458 			pmsheader->compression = BMP_NO_COMPRESS;
459 			pmsheader->imagesize = 0;
460 			pmsheader->xpixperm = 2835; // 72 dpi horizontal
461 			pmsheader->ypixperm = 2835; // 72 dpi vertical
462 			pmsheader->colorsused = 0;
463 			pmsheader->colorsimportant = 0;
464 
465 			// determine fileSize / imagesize
466 			switch (pmsheader->bitsperpixel) {
467 				case 24:
468 					if (pos2skip && fileHeader.dataOffset > 26)
469 						(*pos2skip) = fileHeader.dataOffset - 26;
470 
471 					pfileheader->dataOffset = 54;
472 					pmsheader->imagesize = get_rowbytes(pmsheader->width,
473 						pmsheader->bitsperpixel) * abs(pmsheader->height);
474 					pfileheader->fileSize = pfileheader->dataOffset +
475 						pmsheader->imagesize;
476 
477 					break;
478 
479 				case 8:
480 				case 4:
481 				case 1:
482 				{
483 					uint16 ncolors = 1 << pmsheader->bitsperpixel;
484 					pmsheader->colorsused = ncolors;
485 					pmsheader->colorsimportant = ncolors;
486 					if (pos2skip && fileHeader.dataOffset >
487 						static_cast<uint32> (26 + (ncolors * 3)))
488 							(*pos2skip) = fileHeader.dataOffset -
489 								(26 + (ncolors * 3));
490 
491 					pfileheader->dataOffset = 54 + (ncolors * 4);
492 					pmsheader->imagesize = get_rowbytes(pmsheader->width,
493 						pmsheader->bitsperpixel) * abs(pmsheader->height);
494 					pfileheader->fileSize = pfileheader->dataOffset +
495 						pmsheader->imagesize;
496 
497 					break;
498 				}
499 
500 				default:
501 					break;
502 			}
503 		}
504 		if (pfrommsformat)
505 			(*pfrommsformat) = false;
506 
507 		return B_OK;
508 
509 	} else
510 		return B_NO_TRANSLATOR;
511 }
512 
513 // ---------------------------------------------------------------
514 // DerivedIdentify
515 //
516 // Examines the data from inSource and determines if it is in a
517 // format that this translator knows how to work with.
518 //
519 // Preconditions:
520 //
521 // Parameters:	inSource,	where the data to examine is
522 //
523 //				inFormat,	a hint about the data in inSource,
524 //							it is ignored since it is only a hint
525 //
526 //				ioExtension,	configuration settings for the
527 //								translator
528 //
529 //				outInfo,	information about what data is in
530 //							inSource and how well this translator
531 //							can handle that data is stored here
532 //
533 //				outType,	The format that the user wants
534 //							the data in inSource to be
535 //							converted to
536 //
537 // Postconditions:
538 //
539 // Returns: B_NO_TRANSLATOR,	if this translator can't handle
540 //								the data in inSource
541 //
542 // B_ERROR,	if there was an error converting the data to the host
543 //			format
544 //
545 // B_BAD_VALUE, if the settings in ioExtension are bad
546 //
547 // B_OK,	if this translator understand the data and there were
548 //			no errors found
549 // ---------------------------------------------------------------
550 status_t
DerivedIdentify(BPositionIO * inSource,const translation_format * inFormat,BMessage * ioExtension,translator_info * outInfo,uint32 outType)551 BMPTranslator::DerivedIdentify(BPositionIO *inSource,
552 	const translation_format *inFormat, BMessage *ioExtension,
553 	translator_info *outInfo, uint32 outType)
554 {
555 	return identify_bmp_header(inSource, outInfo);
556 }
557 
558 // ---------------------------------------------------------------
559 // translate_from_bits_to_bmp24
560 //
561 // Converts various varieties of the Be Bitmap format ('bits') to
562 // the MS BMP 24-bit format.
563 //
564 // Preconditions:
565 //
566 // Parameters:	inSource,	contains the bits data to convert
567 //
568 //				outDestination,	where the BMP data will be written
569 //
570 //				fromspace,	the format of the data in inSource
571 //
572 //				msheader,	contains information about the BMP
573 //							dimensions and filesize
574 //
575 // Postconditions:
576 //
577 // Returns: B_ERROR,	if memory couldn't be allocated or another
578 //						error occured
579 //
580 // B_OK,	if no errors occurred
581 // ---------------------------------------------------------------
582 status_t
translate_from_bits_to_bmp24(BPositionIO * inSource,BPositionIO * outDestination,color_space fromspace,MSInfoHeader & msheader)583 translate_from_bits_to_bmp24(BPositionIO *inSource,
584 BPositionIO *outDestination, color_space fromspace, MSInfoHeader &msheader)
585 {
586 	// TODO: WHOHA! big switch statement for the innermost loop!
587 	// make a loop per colorspace and put the switch outside!!!
588 	// remove memcpy() to copy 3 bytes
589 	int32 bitsBytesPerPixel = 0;
590 	switch (fromspace) {
591 		case B_RGB32:
592 		case B_RGB32_BIG:
593 		case B_RGBA32:
594 		case B_RGBA32_BIG:
595 		case B_CMY32:
596 		case B_CMYA32:
597 		case B_CMYK32:
598 			bitsBytesPerPixel = 4;
599 			break;
600 
601 		case B_RGB24:
602 		case B_RGB24_BIG:
603 		case B_CMY24:
604 			bitsBytesPerPixel = 3;
605 			break;
606 
607 		case B_RGB16:
608 		case B_RGB16_BIG:
609 		case B_RGBA15:
610 		case B_RGBA15_BIG:
611 		case B_RGB15:
612 		case B_RGB15_BIG:
613 			bitsBytesPerPixel = 2;
614 			break;
615 
616 		case B_CMAP8:
617 		case B_GRAY8:
618 			bitsBytesPerPixel = 1;
619 			break;
620 
621 		default:
622 			return B_ERROR;
623 	}
624 	int32 bitsRowBytes = msheader.width * bitsBytesPerPixel;
625 	int32 padding = get_padding(msheader.width, msheader.bitsperpixel);
626 	int32 bmpRowBytes =
627 		get_rowbytes(msheader.width, msheader.bitsperpixel);
628 	int32 bmppixrow = 0;
629 	if (msheader.height > 0)
630 		inSource->Seek((msheader.height - 1) * bitsRowBytes, SEEK_CUR);
631 	uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes];
632 	if (!bmpRowData)
633 		return B_NO_MEMORY;
634 	uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes];
635 	if (!bitsRowData) {
636 		delete[] bmpRowData;
637 		return B_NO_MEMORY;
638 	}
639 	memset(bmpRowData + (bmpRowBytes - padding), 0, padding);
640 	ssize_t rd = inSource->Read(bitsRowData, bitsRowBytes);
641 	const color_map *pmap = NULL;
642 	if (fromspace == B_CMAP8) {
643 		pmap = system_colors();
644 		if (!pmap) {
645 			delete [] bmpRowData;
646 			delete [] bitsRowData;
647 			return B_ERROR;
648 		}
649 	}
650 	while (rd == static_cast<ssize_t>(bitsRowBytes)) {
651 		for (int32 i = 0; i < msheader.width; i++) {
652 			uint8 *bitspixel, *bmppixel;
653 			uint16 val;
654 			switch (fromspace) {
655 				case B_RGB32:
656 				case B_RGBA32:
657 				case B_RGB24:
658 					memcpy(bmpRowData + (i * 3),
659 						bitsRowData + (i * bitsBytesPerPixel), 3);
660 					break;
661 
662 				case B_RGB16:
663 				case B_RGB16_BIG:
664 					bitspixel = bitsRowData + (i * bitsBytesPerPixel);
665 					bmppixel = bmpRowData + (i * 3);
666 					if (fromspace == B_RGB16)
667 						val = bitspixel[0] + (bitspixel[1] << 8);
668 					else
669 						val = bitspixel[1] + (bitspixel[0] << 8);
670 					bmppixel[0] =
671 						((val & 0x1f) << 3) | ((val & 0x1f) >> 2);
672 					bmppixel[1] =
673 						((val & 0x7e0) >> 3) | ((val & 0x7e0) >> 9);
674 					bmppixel[2] =
675 						((val & 0xf800) >> 8) | ((val & 0xf800) >> 13);
676 					break;
677 
678 				case B_RGB15:
679 				case B_RGB15_BIG:
680 				case B_RGBA15:
681 				case B_RGBA15_BIG:
682 					// NOTE: the alpha data for B_RGBA15* is not used
683 					bitspixel = bitsRowData + (i * bitsBytesPerPixel);
684 					bmppixel = bmpRowData + (i * 3);
685 					if (fromspace == B_RGB15 || fromspace == B_RGBA15)
686 						val = bitspixel[0] + (bitspixel[1] << 8);
687 					else
688 						val = bitspixel[1] + (bitspixel[0] << 8);
689 					bmppixel[0] =
690 						((val & 0x1f) << 3) | ((val & 0x1f) >> 2);
691 					bmppixel[1] =
692 						((val & 0x3e0) >> 2) | ((val & 0x3e0) >> 7);
693 					bmppixel[2] =
694 						((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12);
695 					break;
696 
697 				case B_RGB32_BIG:
698 				case B_RGBA32_BIG:
699 					bitspixel = bitsRowData + (i * bitsBytesPerPixel);
700 					bmppixel = bmpRowData + (i * 3);
701 					bmppixel[0] = bitspixel[3];
702 					bmppixel[1] = bitspixel[2];
703 					bmppixel[2] = bitspixel[1];
704 					break;
705 
706 				case B_RGB24_BIG:
707 					bitspixel = bitsRowData + (i * bitsBytesPerPixel);
708 					bmppixel = bmpRowData + (i * 3);
709 					bmppixel[0] = bitspixel[2];
710 					bmppixel[1] = bitspixel[1];
711 					bmppixel[2] = bitspixel[0];
712 					break;
713 
714 				case B_CMAP8:
715 				{
716 					bitspixel = bitsRowData + (i * bitsBytesPerPixel);
717 					bmppixel = bmpRowData + (i * 3);
718 					rgb_color c = pmap->color_list[bitspixel[0]];
719 					bmppixel[0] = c.blue;
720 					bmppixel[1] = c.green;
721 					bmppixel[2] = c.red;
722 					break;
723 				}
724 
725 				case B_GRAY8:
726 					bitspixel = bitsRowData + (i * bitsBytesPerPixel);
727 					bmppixel = bmpRowData + (i * 3);
728 					bmppixel[0] = bitspixel[0];
729 					bmppixel[1] = bitspixel[0];
730 					bmppixel[2] = bitspixel[0];
731 					break;
732 
733 				case B_CMYK32:
734 				{
735 					bitspixel = bitsRowData + (i * bitsBytesPerPixel);
736 					bmppixel = bmpRowData + (i * 3);
737 
738 					int32 comp = 255 - bitspixel[2] - bitspixel[3];
739 					bmppixel[0] = (comp < 0) ? 0 : comp;
740 
741 					comp = 255 - bitspixel[1] - bitspixel[3];
742 					bmppixel[1] = (comp < 0) ? 0 : comp;
743 
744 					comp = 255 - bitspixel[0] - bitspixel[3];
745 					bmppixel[2] = (comp < 0) ? 0 : comp;
746 					break;
747 				}
748 
749 				case B_CMY32:
750 				case B_CMYA32:
751 				case B_CMY24:
752 					bitspixel = bitsRowData + (i * bitsBytesPerPixel);
753 					bmppixel = bmpRowData + (i * 3);
754 					bmppixel[0] = 255 - bitspixel[2];
755 					bmppixel[1] = 255 - bitspixel[1];
756 					bmppixel[2] = 255 - bitspixel[0];
757 					break;
758 
759 				default:
760 					break;
761 			} // switch (fromspace)
762 		} // for for (uint32 i = 0; i < msheader.width; i++)
763 
764 		outDestination->Write(bmpRowData, bmpRowBytes);
765 		bmppixrow++;
766 		// if I've read all of the pixel data, break
767 		// out of the loop so I don't try to read
768 		// non-pixel data
769 		if (bmppixrow == abs(msheader.height))
770 			break;
771 
772 		if (msheader.height > 0)
773 			inSource->Seek(bitsRowBytes * -2, SEEK_CUR);
774 		rd = inSource->Read(bitsRowData, bitsRowBytes);
775 	} // while (rd == bitsRowBytes)
776 
777 	delete[] bmpRowData;
778 	delete[] bitsRowData;
779 
780 	return B_OK;
781 }
782 
783 // ---------------------------------------------------------------
784 // translate_from_bits8_to_bmp8
785 //
786 // Converts 8-bit Be Bitmaps ('bits') to the MS 8-bit BMP format
787 //
788 // Preconditions:
789 //
790 // Parameters:	inSource,	contains the bits data to convert
791 //
792 //				outDestination,	where the BMP data will be written
793 //
794 //				bitsRowBytes,	number of bytes in one row of
795 //								bits data
796 //
797 //				msheader,	contains information about the BMP
798 //							dimensions and filesize
799 //
800 // Postconditions:
801 //
802 // Returns: B_ERROR,	if memory couldn't be allocated or another
803 //						error occured
804 //
805 // B_OK,	if no errors occurred
806 // ---------------------------------------------------------------
807 status_t
translate_from_bits8_to_bmp8(BPositionIO * inSource,BPositionIO * outDestination,int32 bitsRowBytes,MSInfoHeader & msheader)808 translate_from_bits8_to_bmp8(BPositionIO *inSource,
809 	BPositionIO *outDestination, int32 bitsRowBytes, MSInfoHeader &msheader)
810 {
811 	int32 padding = get_padding(msheader.width, msheader.bitsperpixel);
812 	int32 bmpRowBytes =
813 		get_rowbytes(msheader.width, msheader.bitsperpixel);
814 	int32 bmppixrow = 0;
815 	if (msheader.height > 0)
816 		inSource->Seek((msheader.height - 1) * bitsRowBytes, SEEK_CUR);
817 	uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes];
818 	if (!bmpRowData)
819 		return B_NO_MEMORY;
820 	uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes];
821 	if (!bitsRowData) {
822 		delete[] bmpRowData;
823 		return B_NO_MEMORY;
824 	}
825 	memset(bmpRowData + (bmpRowBytes - padding), 0, padding);
826 	ssize_t rd = inSource->Read(bitsRowData, bitsRowBytes);
827 	while (rd == bitsRowBytes) {
828 		memcpy(bmpRowData, bitsRowData, msheader.width);
829 		outDestination->Write(bmpRowData, bmpRowBytes);
830 		bmppixrow++;
831 		// if I've read all of the pixel data, break
832 		// out of the loop so I don't try to read
833 		// non-pixel data
834 		if (bmppixrow == abs(msheader.height))
835 			break;
836 
837 		if (msheader.height > 0)
838 			inSource->Seek(bitsRowBytes * -2, SEEK_CUR);
839 		rd = inSource->Read(bitsRowData, bitsRowBytes);
840 	} // while (rd == bitsRowBytes)
841 
842 	delete[] bmpRowData;
843 	delete[] bitsRowData;
844 
845 	return B_OK;
846 }
847 
848 // ---------------------------------------------------------------
849 // translate_from_bits1_to_bmp1
850 //
851 // Converts 1-bit Be Bitmaps ('bits') to the MS 1-bit BMP format
852 //
853 // Preconditions:
854 //
855 // Parameters:	inSource,	contains the bits data to convert
856 //
857 //				outDestination,	where the BMP data will be written
858 //
859 //				bitsRowBytes,	number of bytes in one row of
860 //								bits data
861 //
862 //				msheader,	contains information about the BMP
863 //							dimensions and filesize
864 //
865 // Postconditions:
866 //
867 // Returns: B_ERROR,	if memory couldn't be allocated or another
868 //						error occured
869 //
870 // B_OK,	if no errors occurred
871 // ---------------------------------------------------------------
872 status_t
translate_from_bits1_to_bmp1(BPositionIO * inSource,BPositionIO * outDestination,int32 bitsRowBytes,MSInfoHeader & msheader)873 translate_from_bits1_to_bmp1(BPositionIO *inSource,
874 	BPositionIO *outDestination, int32 bitsRowBytes, MSInfoHeader &msheader)
875 {
876 	uint8 pixelsPerByte = 8 / msheader.bitsperpixel;
877 	int32 bmpRowBytes =
878 		get_rowbytes(msheader.width, msheader.bitsperpixel);
879 	int32 bmppixrow = 0;
880 	if (msheader.height > 0)
881 		inSource->Seek((msheader.height - 1) * bitsRowBytes, SEEK_CUR);
882 	uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes];
883 	if (!bmpRowData)
884 		return B_NO_MEMORY;
885 	uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes];
886 	if (!bitsRowData) {
887 		delete[] bmpRowData;
888 		return B_NO_MEMORY;
889 	}
890 	ssize_t rd = inSource->Read(bitsRowData, bitsRowBytes);
891 	while (rd == bitsRowBytes) {
892 		int32 bmppixcol = 0;
893 		memset(bmpRowData, 0, bmpRowBytes);
894 		for (int32 i = 0; (bmppixcol < msheader.width) &&
895 			(i < bitsRowBytes); i++) {
896 			// process each byte in the row
897 			uint8 pixels = bitsRowData[i];
898 			for (uint8 compbit = 128; (bmppixcol < msheader.width) &&
899 				compbit; compbit >>= 1) {
900 				// for each bit in the current byte, convert to a BMP palette
901 				// index and store that in the bmpRowData
902 				uint8 index;
903 				if (pixels & compbit)
904 					// 1 == black
905 					index = 1;
906 				else
907 					// 0 == white
908 					index = 0;
909 				bmpRowData[bmppixcol / pixelsPerByte] |=
910 					index << (7 - (bmppixcol % pixelsPerByte));
911 				bmppixcol++;
912 			}
913 		}
914 
915 		outDestination->Write(bmpRowData, bmpRowBytes);
916 		bmppixrow++;
917 		// if I've read all of the pixel data, break
918 		// out of the loop so I don't try to read
919 		// non-pixel data
920 		if (bmppixrow == abs(msheader.height))
921 			break;
922 
923 		if (msheader.height > 0)
924 			inSource->Seek(bitsRowBytes * -2, SEEK_CUR);
925 		rd = inSource->Read(bitsRowData, bitsRowBytes);
926 	} // while (rd == bitsRowBytes)
927 
928 	delete[] bmpRowData;
929 	delete[] bitsRowData;
930 
931 	return B_OK;
932 }
933 
934 // ---------------------------------------------------------------
935 // write_bmp_headers
936 //
937 // Writes the MS BMP headers (fileHeader and msheader)
938 // to outDestination.
939 //
940 // Preconditions:
941 //
942 // Parameters:	outDestination,	where the headers are written to
943 //
944 // 				fileHeader, BMP file header data
945 //
946 //				msheader, BMP info header data
947 //
948 // Postconditions:
949 //
950 // Returns: B_ERROR, if something went wrong
951 //
952 // B_OK, if there were no problems writing out the headers
953 // ---------------------------------------------------------------
954 status_t
write_bmp_headers(BPositionIO * outDestination,BMPFileHeader & fileHeader,MSInfoHeader & msheader)955 write_bmp_headers(BPositionIO *outDestination, BMPFileHeader &fileHeader,
956 	MSInfoHeader &msheader)
957 {
958 	uint8 bmpheaders[54];
959 	memcpy(bmpheaders, &fileHeader.magic, sizeof(uint16));
960 	memcpy(bmpheaders + 2, &fileHeader.fileSize, sizeof(uint32));
961 	memcpy(bmpheaders + 6, &fileHeader.reserved, sizeof(uint32));
962 	memcpy(bmpheaders + 10, &fileHeader.dataOffset, sizeof(uint32));
963 	memcpy(bmpheaders + 14, &msheader, sizeof(msheader));
964 	if (swap_data(B_UINT16_TYPE, bmpheaders, 2,
965 		B_SWAP_HOST_TO_LENDIAN) != B_OK)
966 		return B_ERROR;
967 	if (swap_data(B_UINT32_TYPE, bmpheaders + 2, 12,
968 		B_SWAP_HOST_TO_LENDIAN) != B_OK)
969 		return B_ERROR;
970 	if (swap_data(B_UINT32_TYPE, bmpheaders + 14,
971 		sizeof(MSInfoHeader), B_SWAP_HOST_TO_LENDIAN) != B_OK)
972 		return B_ERROR;
973 	if (outDestination->Write(bmpheaders, 54) != 54)
974 		return B_ERROR;
975 
976 	return B_OK;
977 }
978 
979 // ---------------------------------------------------------------
980 // translate_from_bits
981 //
982 // Convert the data in inSource from the Be Bitmap format ('bits')
983 // to the format specified in outType (either bits or BMP).
984 //
985 // Preconditions:
986 //
987 // Parameters:	inSource,	the bits data to translate
988 //
989 //				outType,	the type of data to convert to
990 //
991 //				outDestination,	where the output is written to
992 //
993 // Postconditions:
994 //
995 // Returns: B_NO_TRANSLATOR,	if the data is not in a supported
996 //								format
997 //
998 // B_ERROR, if there was an error allocating memory or some other
999 //			error
1000 //
1001 // B_OK, if successfully translated the data from the bits format
1002 // ---------------------------------------------------------------
1003 status_t
translate_from_bits(BPositionIO * inSource,uint32 outType,BPositionIO * outDestination)1004 BMPTranslator::translate_from_bits(BPositionIO *inSource, uint32 outType,
1005 	BPositionIO *outDestination)
1006 {
1007 	bool bheaderonly, bdataonly;
1008 	bheaderonly = bdataonly = false;
1009 
1010 	TranslatorBitmap bitsHeader;
1011 	status_t result;
1012 	result = identify_bits_header(inSource, NULL, &bitsHeader);
1013 	if (result != B_OK)
1014 		return result;
1015 
1016 	// Translate B_TRANSLATOR_BITMAP to B_BMP_FORMAT
1017 	if (outType == B_BMP_FORMAT) {
1018 		// Set up BMP header
1019 		BMPFileHeader fileHeader;
1020 		fileHeader.magic = 'MB';
1021 		fileHeader.reserved = 0;
1022 
1023 		MSInfoHeader msheader;
1024 		msheader.size = 40;
1025 		msheader.width =
1026 			static_cast<uint32> (bitsHeader.bounds.Width() + 1);
1027 		msheader.height =
1028 			static_cast<int32> (bitsHeader.bounds.Height() + 1);
1029 		msheader.planes = 1;
1030 		msheader.xpixperm = 2835; // 72 dpi horizontal
1031 		msheader.ypixperm = 2835; // 72 dpi vertical
1032 		msheader.colorsused = 0;
1033 		msheader.colorsimportant = 0;
1034 
1035 		// determine fileSize / imagesize
1036 		switch (bitsHeader.colors) {
1037 			case B_RGB32:
1038 			case B_RGB32_BIG:
1039 			case B_RGBA32:
1040 			case B_RGBA32_BIG:
1041 			case B_RGB24:
1042 			case B_RGB24_BIG:
1043 			case B_RGB16:
1044 			case B_RGB16_BIG:
1045 			case B_RGB15:
1046 			case B_RGB15_BIG:
1047 			case B_RGBA15:
1048 			case B_RGBA15_BIG:
1049 			case B_CMYK32:
1050 			case B_CMY32:
1051 			case B_CMYA32:
1052 			case B_CMY24:
1053 
1054 				fileHeader.dataOffset = 54;
1055 				msheader.bitsperpixel = 24;
1056 				msheader.compression = BMP_NO_COMPRESS;
1057 				msheader.imagesize = get_rowbytes(msheader.width, 24) *
1058 					msheader.height;
1059 				fileHeader.fileSize = fileHeader.dataOffset +
1060 					msheader.imagesize;
1061 
1062 				break;
1063 
1064 			case B_CMAP8:
1065 			case B_GRAY8:
1066 
1067 				msheader.colorsused = 256;
1068 				msheader.colorsimportant = 256;
1069 				fileHeader.dataOffset = 54 + (4 * 256);
1070 				msheader.bitsperpixel = 8;
1071 				msheader.compression = BMP_NO_COMPRESS;
1072 				msheader.imagesize = get_rowbytes(msheader.width,
1073 					msheader.bitsperpixel) * msheader.height;
1074 				fileHeader.fileSize = fileHeader.dataOffset +
1075 					msheader.imagesize;
1076 
1077 				break;
1078 
1079 			case B_GRAY1:
1080 
1081 				msheader.colorsused = 2;
1082 				msheader.colorsimportant = 2;
1083 				fileHeader.dataOffset = 62;
1084 				msheader.bitsperpixel = 1;
1085 				msheader.compression = BMP_NO_COMPRESS;
1086 				msheader.imagesize = get_rowbytes(msheader.width,
1087 					msheader.bitsperpixel) * msheader.height;
1088 				fileHeader.fileSize = fileHeader.dataOffset +
1089 					msheader.imagesize;
1090 
1091 				break;
1092 
1093 			default:
1094 				return B_NO_TRANSLATOR;
1095 		}
1096 
1097 		// write out the BMP headers
1098 		if (bheaderonly || (!bheaderonly && !bdataonly)) {
1099 			result = write_bmp_headers(outDestination, fileHeader, msheader);
1100 			if (result != B_OK)
1101 				return result;
1102 		}
1103 		if (bheaderonly)
1104 			// if user only wants the header, bail out
1105 			// before the data is written
1106 			return result;
1107 
1108 		// write out the BMP pixel data
1109 		switch (bitsHeader.colors) {
1110 			case B_RGB32:
1111 			case B_RGB32_BIG:
1112 			case B_RGBA32:
1113 			case B_RGBA32_BIG:
1114 			case B_RGB24:
1115 			case B_RGB24_BIG:
1116 			case B_RGB16:
1117 			case B_RGB16_BIG:
1118 			case B_RGB15:
1119 			case B_RGB15_BIG:
1120 			case B_RGBA15:
1121 			case B_RGBA15_BIG:
1122 			case B_CMYK32:
1123 			case B_CMY32:
1124 			case B_CMYA32:
1125 			case B_CMY24:
1126 				return translate_from_bits_to_bmp24(inSource, outDestination,
1127 					bitsHeader.colors, msheader);
1128 
1129 			case B_CMAP8:
1130 			case B_GRAY8:
1131 			{
1132 				// write palette to BMP file
1133 				uint8 pal[1024];
1134 				uint8* palHandle = pal;
1135 				if (bitsHeader.colors == B_CMAP8) {
1136 					// write system palette
1137 					const color_map *pmap = system_colors();
1138 					if (!pmap)
1139 						return B_ERROR;
1140 					for (int32 i = 0; i < 256; i++) {
1141 						rgb_color c = pmap->color_list[i];
1142 						palHandle[0] = c.blue;
1143 						palHandle[1] = c.green;
1144 						palHandle[2] = c.red;
1145 						palHandle[3] = c.alpha;
1146 						palHandle += 4;
1147 					}
1148 				} else {
1149 					// write gray palette
1150 					for (int32 i = 0; i < 256; i++) {
1151 						palHandle[0] = i;
1152 						palHandle[1] = i;
1153 						palHandle[2] = i;
1154 						palHandle[3] = 255;
1155 						palHandle += 4;
1156 					}
1157 				}
1158 				ssize_t written = outDestination->Write(pal, 1024);
1159 				if (written < 0)
1160 					return written;
1161 				if (written != 1024)
1162 					return B_ERROR;
1163 
1164 				return translate_from_bits8_to_bmp8(inSource, outDestination,
1165 					bitsHeader.rowBytes, msheader);
1166 			}
1167 
1168 			case B_GRAY1:
1169 			{
1170 				// write monochrome palette to the BMP file
1171 				const uint32 monopal[] = { 0x00ffffff, 0x00000000 };
1172 				ssize_t written = outDestination->Write(monopal, 8);
1173 				if (written < 0)
1174 					return written;
1175 				if (written != 8)
1176 					return B_ERROR;
1177 
1178 				return translate_from_bits1_to_bmp1(inSource, outDestination,
1179 					bitsHeader.rowBytes, msheader);
1180 			}
1181 
1182 			default:
1183 				return B_NO_TRANSLATOR;
1184 		}
1185 	} else
1186 		return B_NO_TRANSLATOR;
1187 }
1188 
1189 // ---------------------------------------------------------------
1190 // translate_from_bmpnpal_to_bits
1191 //
1192 // Translates a non-palette BMP from inSource to the B_RGB32
1193 // bits format.
1194 //
1195 // Preconditions:
1196 //
1197 // Parameters: inSource,	the BMP data to be translated
1198 //
1199 // outDestination,	where the bits data will be written to
1200 //
1201 // msheader,	header information about the BMP to be written
1202 //
1203 // Postconditions:
1204 //
1205 // Returns: B_ERROR, if there is an error allocating memory
1206 //
1207 // B_OK, if all went well
1208 // ---------------------------------------------------------------
1209 status_t
translate_from_bmpnpal_to_bits(BPositionIO * inSource,BPositionIO * outDestination,MSInfoHeader & msheader)1210 translate_from_bmpnpal_to_bits(BPositionIO *inSource,
1211 	BPositionIO *outDestination, MSInfoHeader &msheader)
1212 {
1213 	int32 bitsRowBytes = msheader.width * 4;
1214 	int32 bmpBytesPerPixel = msheader.bitsperpixel / 8;
1215 	int32 bmpRowBytes =
1216 		get_rowbytes(msheader.width, msheader.bitsperpixel);
1217 
1218 	// Setup outDestination so that it can be written to
1219 	// from the end of the file to the beginning instead of
1220 	// the other way around
1221 	off_t bitsFileSize = (bitsRowBytes * abs(msheader.height)) +
1222 		sizeof(TranslatorBitmap);
1223 	if (outDestination->SetSize(bitsFileSize) != B_OK) {
1224 		// This call should work for BFile and BMallocIO objects,
1225 		// but may not work for other BPositionIO based types
1226 		ERROR("BMPTranslator::translate_from_bmpnpal_to_bits() - "
1227 			"failed to SetSize()\n");
1228 		return B_ERROR;
1229 	}
1230 	if (msheader.height > 0)
1231 		outDestination->Seek((msheader.height - 1) * bitsRowBytes, SEEK_CUR);
1232 
1233 	// allocate row buffers
1234 	uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes];
1235 	if (!bmpRowData)
1236 		return B_NO_MEMORY;
1237 	uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes];
1238 	if (!bitsRowData) {
1239 		delete[] bmpRowData;
1240 		return B_NO_MEMORY;
1241 	}
1242 
1243 	// perform the actual translation
1244 	if (bmpBytesPerPixel != 4) {
1245 		// clean out buffer so that we don't have to write
1246 		// alpha for each row
1247 		memset(bitsRowData, 0xff, bitsRowBytes);
1248 	}
1249 
1250 	status_t ret = B_OK;
1251 
1252 	uint32 rowCount = abs(msheader.height);
1253 	for (uint32 y = 0; y < rowCount; y++) {
1254 		ssize_t read = inSource->Read(bmpRowData, bmpRowBytes);
1255 		if (read != bmpRowBytes) {
1256 			// break on read error
1257 			if (read >= 0)
1258 				ret = B_ERROR;
1259 			else
1260 				ret = read;
1261 			break;
1262 		}
1263 
1264 		if (bmpBytesPerPixel == 4) {
1265 			memcpy(bitsRowData, bmpRowData, bmpRowBytes);
1266 		} else {
1267 			uint8 *pBitsPixel = bitsRowData;
1268 			uint8 *pBmpPixel = bmpRowData;
1269 			for (int32 i = 0; i < msheader.width; i++) {
1270 				pBitsPixel[0] = pBmpPixel[0];
1271 				pBitsPixel[1] = pBmpPixel[1];
1272 				pBitsPixel[2] = pBmpPixel[2];
1273 				pBitsPixel += 4;
1274 				pBmpPixel += bmpBytesPerPixel;
1275 			}
1276 		}
1277 		// write row and seek backward by two rows
1278 		ssize_t written = outDestination->Write(bitsRowData, bitsRowBytes);
1279 		if (msheader.height > 0)
1280 			outDestination->Seek(bitsRowBytes * -2, SEEK_CUR);
1281 
1282 		if (written != bitsRowBytes) {
1283 			// break on write error
1284 			if (written >= 0)
1285 				ret = B_ERROR;
1286 			else
1287 				ret = read;
1288 			break;
1289 		}
1290 	}
1291 
1292 	delete[] bmpRowData;
1293 	delete[] bitsRowData;
1294 
1295 	return ret;
1296 }
1297 
1298 // ---------------------------------------------------------------
1299 // translate_from_bmppal_to_bits
1300 //
1301 // Translates an uncompressed, palette BMP from inSource to
1302 // the B_RGB32 bits format.
1303 //
1304 // Preconditions:
1305 //
1306 // Parameters: inSource,	the BMP data to be translated
1307 //
1308 // outDestination,	where the bits data will be written to
1309 //
1310 // msheader,	header information about the BMP to be written
1311 //
1312 // palette,	BMP palette for the BMP image
1313 //
1314 // frommsformat, true if BMP in inSource is in MS format,
1315 //				 false if it is in OS/2 format
1316 //
1317 // Postconditions:
1318 //
1319 // Returns: B_NO_MEMORY, if there is an error allocating memory
1320 //
1321 // B_OK, if all went well
1322 // ---------------------------------------------------------------
1323 status_t
translate_from_bmppal_to_bits(BPositionIO * inSource,BPositionIO * outDestination,MSInfoHeader & msheader,const uint8 * palette,bool frommsformat)1324 translate_from_bmppal_to_bits(BPositionIO *inSource,
1325 	BPositionIO *outDestination, MSInfoHeader &msheader,
1326 	const uint8 *palette, bool frommsformat)
1327 {
1328 	uint16 pixelsPerByte = 8 / msheader.bitsperpixel;
1329 	uint16 bitsPerPixel = msheader.bitsperpixel;
1330 	uint8 palBytesPerPixel;
1331 	if (frommsformat)
1332 		palBytesPerPixel = 4;
1333 	else
1334 		palBytesPerPixel = 3;
1335 
1336 	uint8 mask = 1;
1337 	mask = (mask << bitsPerPixel) - 1;
1338 
1339 	int32 bmpRowBytes =
1340 		get_rowbytes(msheader.width, msheader.bitsperpixel);
1341 	int32 bmppixrow = 0;
1342 
1343 	// Setup outDestination so that it can be written to
1344 	// from the end of the file to the beginning instead of
1345 	// the other way around
1346 	int32 bitsRowBytes = msheader.width * 4;
1347 	off_t bitsFileSize = (bitsRowBytes * abs(msheader.height)) +
1348 		sizeof(TranslatorBitmap);
1349 	if (outDestination->SetSize(bitsFileSize) != B_OK)
1350 		// This call should work for BFile and BMallocIO objects,
1351 		// but may not work for other BPositionIO based types
1352 		return B_ERROR;
1353 	if (msheader.height > 0)
1354 		outDestination->Seek((msheader.height - 1) * bitsRowBytes, SEEK_CUR);
1355 
1356 	// allocate row buffers
1357 	uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes];
1358 	if (!bmpRowData)
1359 		return B_NO_MEMORY;
1360 	uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes];
1361 	if (!bitsRowData) {
1362 		delete[] bmpRowData;
1363 		return B_NO_MEMORY;
1364 	}
1365 	memset(bitsRowData, 0xff, bitsRowBytes);
1366 	ssize_t rd = inSource->Read(bmpRowData, bmpRowBytes);
1367 	while (rd == static_cast<ssize_t>(bmpRowBytes)) {
1368 		for (int32 i = 0; i < msheader.width; i++) {
1369 			uint8 indices = (bmpRowData + (i / pixelsPerByte))[0];
1370 			uint8 index;
1371 			index = (indices >>
1372 				(bitsPerPixel * ((pixelsPerByte - 1) -
1373 					(i % pixelsPerByte)))) & mask;
1374 			memcpy(bitsRowData + (i * 4),
1375 				palette + (index * palBytesPerPixel), 3);
1376 		}
1377 
1378 		outDestination->Write(bitsRowData, bitsRowBytes);
1379 		bmppixrow++;
1380 		// if I've read all of the pixel data, break
1381 		// out of the loop so I don't try to read
1382 		// non-pixel data
1383 		if (bmppixrow == abs(msheader.height))
1384 			break;
1385 
1386 		if (msheader.height > 0)
1387 			outDestination->Seek(bitsRowBytes * -2, SEEK_CUR);
1388 		rd = inSource->Read(bmpRowData, bmpRowBytes);
1389 	}
1390 
1391 	delete[] bmpRowData;
1392 	delete[] bitsRowData;
1393 
1394 	return B_OK;
1395 }
1396 
1397 
1398 // ---------------------------------------------------------------
1399 // pixelcpy
1400 //
1401 // Copies count 32-bit pixels with a color value of pixel to dest.
1402 //
1403 // Preconditions:
1404 //
1405 // Parameters:	dest,	where the pixel data will be copied to
1406 //
1407 //				pixel,	the 32-bit color value to copy to dest
1408 //						count times
1409 //
1410 //				count,	the number of times pixel is copied to
1411 //						dest
1412 //
1413 // Postconditions:
1414 //
1415 // Returns:
1416 // ---------------------------------------------------------------
1417 void
pixelcpy(uint8 * dest,uint32 pixel,uint32 count)1418 pixelcpy(uint8 *dest, uint32 pixel, uint32 count)
1419 {
1420 	for (uint32 i = 0; i < count; i++) {
1421 		memcpy(dest, &pixel, 3);
1422 		dest += 4;
1423 	}
1424 }
1425 
1426 // ---------------------------------------------------------------
1427 // translate_from_bmppalr_to_bits
1428 //
1429 // Translates an RLE compressed, palette BMP from inSource to
1430 // the B_RGB32 bits format. Currently, this code is not as
1431 // memory effcient as it could be. It assumes that the BMP
1432 // from inSource is relatively small.
1433 //
1434 // Preconditions:
1435 //
1436 // Parameters: inSource,	the BMP data to be translated
1437 //
1438 // outDestination,	where the bits data will be written to
1439 //
1440 // datasize, number of bytes of data needed for the bits output
1441 //
1442 // msheader,	header information about the BMP to be written
1443 //
1444 // palette,	BMP palette for data in inSource
1445 //
1446 // Postconditions:
1447 //
1448 // Returns: B_ERROR, if there is an error allocating memory
1449 //
1450 // B_OK, if all went well
1451 // ---------------------------------------------------------------
1452 status_t
translate_from_bmppalr_to_bits(BPositionIO * inSource,BPositionIO * outDestination,int32 datasize,MSInfoHeader & msheader,const uint8 * palette)1453 translate_from_bmppalr_to_bits(BPositionIO *inSource,
1454 	BPositionIO *outDestination, int32 datasize, MSInfoHeader &msheader,
1455 	const uint8 *palette)
1456 {
1457 	uint16 pixelsPerByte = 8 / msheader.bitsperpixel;
1458 	uint16 bitsPerPixel = msheader.bitsperpixel;
1459 	uint8 mask = (1 << bitsPerPixel) - 1;
1460 
1461 	uint8 count, indices, index;
1462 	// Setup outDestination so that it can be written to
1463 	// from the end of the file to the beginning instead of
1464 	// the other way around
1465 	int32 rowCount = abs(msheader.height);
1466 	int32 bitsRowBytes = msheader.width * 4;
1467 	off_t bitsFileSize = (bitsRowBytes * rowCount) +
1468 		sizeof(TranslatorBitmap);
1469 	if (outDestination->SetSize(bitsFileSize) != B_OK)
1470 		// This call should work for BFile and BMallocIO objects,
1471 		// but may not work for other BPositionIO based types
1472 		return B_ERROR;
1473 	uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes];
1474 	if (!bitsRowData)
1475 		return B_NO_MEMORY;
1476 	memset(bitsRowData, 0xff, bitsRowBytes);
1477 	int32 bmppixcol = 0, bmppixrow = 0;
1478 	uint32 defaultcolor = *(uint32*)palette;
1479 	off_t rowOffset = msheader.height > 0 ? bitsRowBytes * -2 : 0;
1480 	// set bits output to last row in the image
1481 	if (msheader.height > 0)
1482 		outDestination->Seek((msheader.height - 1) * bitsRowBytes, SEEK_CUR);
1483 	ssize_t rd = inSource->Read(&count, 1);
1484 	while (rd > 0) {
1485 		// repeated color
1486 		if (count) {
1487 			// abort if all of the pixels in the row
1488 			// have already been drawn to
1489 			if (bmppixcol == msheader.width) {
1490 				rd = -1;
1491 				break;
1492 			}
1493 			// if count is greater than the number of
1494 			// pixels remaining in the current row,
1495 			// only process the correct number of pixels
1496 			// remaining in the row
1497 			if (count + bmppixcol > msheader.width)
1498 				count = msheader.width - bmppixcol;
1499 
1500 			rd = inSource->Read(&indices, 1);
1501 			if (rd != 1) {
1502 				rd = -1;
1503 				break;
1504 			}
1505 			for (uint8 i = 0; i < count; i++) {
1506 				index = (indices >> (bitsPerPixel * ((pixelsPerByte - 1) -
1507 					(i % pixelsPerByte)))) & mask;
1508 				memcpy(bitsRowData + (bmppixcol*4), palette + (index*4), 3);
1509 				bmppixcol++;
1510 			}
1511 		// special code
1512 		} else {
1513 			uint8 code;
1514 			rd = inSource->Read(&code, 1);
1515 			if (rd != 1) {
1516 				rd = -1;
1517 				break;
1518 			}
1519 			switch (code) {
1520 				// end of line
1521 				case 0:
1522 					// if there are columns remaing on this
1523 					// line, set them to the color at index zero
1524 					if (bmppixcol < msheader.width)
1525 						pixelcpy(bitsRowData + (bmppixcol * 4),
1526 							defaultcolor, msheader.width - bmppixcol);
1527 					outDestination->Write(bitsRowData, bitsRowBytes);
1528 					bmppixcol = 0;
1529 					bmppixrow++;
1530 					if (bmppixrow < rowCount)
1531 						outDestination->Seek(rowOffset, SEEK_CUR);
1532 					break;
1533 
1534 				// end of bitmap
1535 				case 1:
1536 					// if at the end of a row
1537 					if (bmppixcol == msheader.width) {
1538 						outDestination->Write(bitsRowData, bitsRowBytes);
1539 						bmppixcol = 0;
1540 						bmppixrow++;
1541 						if (bmppixrow < rowCount)
1542 							outDestination->Seek(rowOffset, SEEK_CUR);
1543 					}
1544 
1545 					while (bmppixrow < rowCount) {
1546 						pixelcpy(bitsRowData + (bmppixcol * 4), defaultcolor,
1547 							msheader.width - bmppixcol);
1548 						outDestination->Write(bitsRowData, bitsRowBytes);
1549 						bmppixcol = 0;
1550 						bmppixrow++;
1551 						if (bmppixrow < rowCount)
1552 							outDestination->Seek(rowOffset, SEEK_CUR);
1553 					}
1554 					rd = 0;
1555 						// break out of while loop
1556 					break;
1557 
1558 				// delta, skip several rows and/or columns and
1559 				// fill the skipped pixels with the default color
1560 				case 2:
1561 				{
1562 					uint8 da[2], lastcol, dx, dy;
1563 					rd = inSource->Read(da, 2);
1564 					if (rd != 2) {
1565 						rd = -1;
1566 						break;
1567 					}
1568 					dx = da[0];
1569 					dy = da[1];
1570 
1571 					// abort if dx or dy is too large
1572 					if ((dx + bmppixcol >= msheader.width) ||
1573 						(dy + bmppixrow >= rowCount)) {
1574 						rd = -1;
1575 						break;
1576 					}
1577 
1578 					lastcol = bmppixcol;
1579 
1580 					// set all pixels to the first entry in
1581 					// the palette, for the number of rows skipped
1582 					while (dy > 0) {
1583 						pixelcpy(bitsRowData + (bmppixcol * 4), defaultcolor,
1584 							msheader.width - bmppixcol);
1585 						outDestination->Write(bitsRowData, bitsRowBytes);
1586 						bmppixcol = 0;
1587 						bmppixrow++;
1588 						dy--;
1589 						outDestination->Seek(rowOffset, SEEK_CUR);
1590 					}
1591 
1592 					if (bmppixcol < static_cast<int32>(lastcol + dx)) {
1593 						pixelcpy(bitsRowData + (bmppixcol * 4), defaultcolor,
1594 							dx + lastcol - bmppixcol);
1595 						bmppixcol = dx + lastcol;
1596 					}
1597 
1598 					break;
1599 				}
1600 
1601 				// code >= 3
1602 				// read code uncompressed indices
1603 				default:
1604 					// abort if all of the pixels in the row
1605 					// have already been drawn to
1606 					if (bmppixcol == msheader.width) {
1607 						rd = -1;
1608 						break;
1609 					}
1610 					// if code is greater than the number of
1611 					// pixels remaining in the current row,
1612 					// only process the correct number of pixels
1613 					// remaining in the row
1614 					if (code + bmppixcol > msheader.width)
1615 						code = msheader.width - bmppixcol;
1616 
1617 					uint8 uncomp[256];
1618 					int32 padding;
1619 					if (!(code % pixelsPerByte))
1620 						padding = (code / pixelsPerByte) % 2;
1621 					else
1622 						padding = ((code + pixelsPerByte -
1623 							(code % pixelsPerByte)) / pixelsPerByte) % 2;
1624 					int32 uncompBytes = (code / pixelsPerByte) +
1625 						((code % pixelsPerByte) ? 1 : 0) + padding;
1626 					rd = inSource->Read(uncomp, uncompBytes);
1627 					if (rd != uncompBytes) {
1628 						rd = -1;
1629 						break;
1630 					}
1631 					for (uint8 i = 0; i < code; i++) {
1632 						indices = (uncomp + (i / pixelsPerByte))[0];
1633 						index = (indices >>
1634 							(bitsPerPixel * ((pixelsPerByte - 1) -
1635 								(i % pixelsPerByte)))) & mask;
1636 						memcpy(bitsRowData + (bmppixcol * 4),
1637 							palette + (index * 4), 3);
1638 						bmppixcol++;
1639 					}
1640 
1641 					break;
1642 			}
1643 		}
1644 		if (rd > 0)
1645 			rd = inSource->Read(&count, 1);
1646 	}
1647 
1648 	delete[] bitsRowData;
1649 
1650 	if (!rd)
1651 		return B_OK;
1652 	else
1653 		return B_NO_TRANSLATOR;
1654 }
1655 
1656 // ---------------------------------------------------------------
1657 // translate_from_bmp
1658 //
1659 // Convert the data in inSource from the BMP format
1660 // to the format specified in outType (either bits or BMP).
1661 //
1662 // Preconditions:
1663 //
1664 // Parameters:	inSource,	the bits data to translate
1665 //
1666 //				outType,	the type of data to convert to
1667 //
1668 //				outDestination,	where the output is written to
1669 //
1670 // Postconditions:
1671 //
1672 // Returns: B_NO_TRANSLATOR,	if the data is not in a supported
1673 //								format
1674 //
1675 // B_ERROR, if there was an error allocating memory or some other
1676 //			error
1677 //
1678 // B_OK, if successfully translated the data from the bits format
1679 // ---------------------------------------------------------------
1680 status_t
translate_from_bmp(BPositionIO * inSource,uint32 outType,BPositionIO * outDestination)1681 BMPTranslator::translate_from_bmp(BPositionIO *inSource, uint32 outType,
1682 	BPositionIO *outDestination)
1683 {
1684 	bool bheaderonly, bdataonly;
1685 	bheaderonly = bdataonly = false;
1686 
1687 	BMPFileHeader fileHeader;
1688 	MSInfoHeader msheader;
1689 	bool frommsformat;
1690 	off_t os2skip = 0;
1691 
1692 	status_t result;
1693 	result = identify_bmp_header(inSource, NULL, &fileHeader, &msheader,
1694 		&frommsformat, &os2skip);
1695 	if (result != B_OK) {
1696 		INFO("BMPTranslator::translate_from_bmp() - identify_bmp_header failed\n");
1697 		return result;
1698 	}
1699 
1700 	// if the user wants to translate a BMP to a BMP, easy enough :)
1701 	if (outType == B_BMP_FORMAT) {
1702 		// write out the BMP headers
1703 		if (bheaderonly || (!bheaderonly && !bdataonly)) {
1704 			result = write_bmp_headers(outDestination, fileHeader, msheader);
1705 			if (result != B_OK)
1706 				return result;
1707 		}
1708 		if (bheaderonly)
1709 			// if the user only wants the header,
1710 			// bail before it is written
1711 			return result;
1712 
1713 		uint8 buf[1024];
1714 		ssize_t rd;
1715 		uint32 rdtotal = 54;
1716 		if (!frommsformat && (msheader.bitsperpixel == 1 ||
1717 			msheader.bitsperpixel == 4 || msheader.bitsperpixel == 8)) {
1718 			// if OS/2 paletted format, convert palette to MS format
1719 			uint16 ncolors = 1 << msheader.bitsperpixel;
1720 			rd = inSource->Read(buf, ncolors * 3);
1721 			if (rd != ncolors * 3)
1722 				return B_NO_TRANSLATOR;
1723 			uint8 mspalent[4] = {0, 0, 0, 0};
1724 			for (uint16 i = 0; i < ncolors; i++) {
1725 				memcpy(mspalent, buf + (i * 3), 3);
1726 				outDestination->Write(mspalent, 4);
1727 			}
1728 			rdtotal = fileHeader.dataOffset;
1729 		}
1730 		// if there is junk between the OS/2 headers and
1731 		// the actual data, skip it
1732 		if (!frommsformat && os2skip)
1733 			inSource->Seek(os2skip, SEEK_CUR);
1734 
1735 		rd = min((uint32)1024, fileHeader.fileSize - rdtotal);
1736 		rd = inSource->Read(buf, rd);
1737 		while (rd > 0) {
1738 			outDestination->Write(buf, rd);
1739 			rdtotal += rd;
1740 			rd = min((uint32)1024, fileHeader.fileSize - rdtotal);
1741 			rd = inSource->Read(buf, rd);
1742 		}
1743 		if (rd == 0)
1744 			return B_OK;
1745 		else
1746 			return B_ERROR;
1747 
1748 	// if translating a BMP to a Be Bitmap
1749 	} else if (outType == B_TRANSLATOR_BITMAP) {
1750 		TranslatorBitmap bitsHeader;
1751 		bitsHeader.magic = B_TRANSLATOR_BITMAP;
1752 		bitsHeader.bounds.left = 0;
1753 		bitsHeader.bounds.top = 0;
1754 		bitsHeader.bounds.right = msheader.width - 1;
1755 		bitsHeader.bounds.bottom = abs(msheader.height) - 1;
1756 
1757 		// read in palette and/or skip non-BMP data
1758 		uint8 bmppalette[1024];
1759 		off_t nskip = 0;
1760 		if (msheader.bitsperpixel == 1 ||
1761 			msheader.bitsperpixel == 4 ||
1762 			msheader.bitsperpixel == 8) {
1763 
1764 			uint8 palBytesPerPixel;
1765 			if (frommsformat)
1766 				palBytesPerPixel = 4;
1767 			else
1768 				palBytesPerPixel = 3;
1769 
1770 			if (!msheader.colorsused)
1771 				msheader.colorsused = 1 << msheader.bitsperpixel;
1772 
1773 			if (inSource->Read(bmppalette, msheader.colorsused *
1774 				palBytesPerPixel) !=
1775 					(off_t) msheader.colorsused * palBytesPerPixel)
1776 				return B_NO_TRANSLATOR;
1777 
1778 			// skip over non-BMP data
1779 			if (frommsformat) {
1780 				if (fileHeader.dataOffset > (msheader.colorsused *
1781 					palBytesPerPixel) + 54)
1782 					nskip = fileHeader.dataOffset -
1783 						((msheader.colorsused * palBytesPerPixel) + 54);
1784 			} else
1785 				nskip = os2skip;
1786 		} else if (fileHeader.dataOffset > 54)
1787 			// skip over non-BMP data
1788 			nskip = fileHeader.dataOffset - 54;
1789 
1790 		if (nskip > 0 && inSource->Seek(nskip, SEEK_CUR) < 0)
1791 			return B_NO_TRANSLATOR;
1792 
1793 		bitsHeader.rowBytes = msheader.width * 4;
1794 		bitsHeader.colors = B_RGB32;
1795 		int32 datasize = bitsHeader.rowBytes * abs(msheader.height);
1796 		bitsHeader.dataSize = datasize;
1797 
1798 		// write out Be's Bitmap header
1799 		if (bheaderonly || (!bheaderonly && !bdataonly)) {
1800 			if (swap_data(B_UINT32_TYPE, &bitsHeader,
1801 				sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK)
1802 				return B_ERROR;
1803 			outDestination->Write(&bitsHeader, sizeof(TranslatorBitmap));
1804 		}
1805 		if (bheaderonly)
1806 			// if the user only wants the header,
1807 			// bail before the data is written
1808 			return B_OK;
1809 
1810 		// write out the actual image data
1811 		switch (msheader.bitsperpixel) {
1812 			case 32:
1813 			case 24:
1814 				return translate_from_bmpnpal_to_bits(inSource,
1815 					outDestination, msheader);
1816 
1817 			case 8:
1818 				// 8 bit BMP with NO compression
1819 				if (msheader.compression == BMP_NO_COMPRESS)
1820 					return translate_from_bmppal_to_bits(inSource,
1821 						outDestination, msheader, bmppalette, frommsformat);
1822 
1823 				// 8 bit RLE compressed BMP
1824 				else if (msheader.compression == BMP_RLE8_COMPRESS)
1825 					return translate_from_bmppalr_to_bits(inSource,
1826 						outDestination, datasize, msheader, bmppalette);
1827 				else
1828 					return B_NO_TRANSLATOR;
1829 
1830 			case 4:
1831 				// 4 bit BMP with NO compression
1832 				if (!msheader.compression)
1833 					return translate_from_bmppal_to_bits(inSource,
1834 						outDestination, msheader, bmppalette, frommsformat);
1835 
1836 				// 4 bit RLE compressed BMP
1837 				else if (msheader.compression == BMP_RLE4_COMPRESS)
1838 					return translate_from_bmppalr_to_bits(inSource,
1839 						outDestination, datasize, msheader, bmppalette);
1840 				else
1841 					return B_NO_TRANSLATOR;
1842 
1843 			case 1:
1844 				return translate_from_bmppal_to_bits(inSource,
1845 					outDestination, msheader, bmppalette, frommsformat);
1846 
1847 			default:
1848 				return B_NO_TRANSLATOR;
1849 		}
1850 
1851 	} else
1852 		return B_NO_TRANSLATOR;
1853 }
1854 
1855 // ---------------------------------------------------------------
1856 // DerivedTranslate
1857 //
1858 // Translates the data in inSource to the type outType and stores
1859 // the translated data in outDestination.
1860 //
1861 // Preconditions:
1862 //
1863 // Parameters:	inSource,	the data to be translated
1864 //
1865 //				inInfo,	hint about the data in inSource (not used)
1866 //
1867 //				ioExtension,	configuration options for the
1868 //								translator
1869 //
1870 //				outType,	the type to convert inSource to
1871 //
1872 //				outDestination,	where the translated data is
1873 //								put
1874 //
1875 //				baseType, indicates whether inSource is in the
1876 //				          bits format, not in the bits format or
1877 //				          is unknown
1878 //
1879 // Postconditions:
1880 //
1881 // Returns: B_BAD_VALUE, if the options in ioExtension are bad
1882 //
1883 // B_NO_TRANSLATOR, if this translator doesn't understand the data
1884 //
1885 // B_ERROR, if there was an error allocating memory or converting
1886 //          data
1887 //
1888 // B_OK, if all went well
1889 // ---------------------------------------------------------------
1890 status_t
DerivedTranslate(BPositionIO * inSource,const translator_info * inInfo,BMessage * ioExtension,uint32 outType,BPositionIO * outDestination,int32 baseType)1891 BMPTranslator::DerivedTranslate(BPositionIO *inSource,
1892 		const translator_info *inInfo, BMessage *ioExtension,
1893 		uint32 outType, BPositionIO *outDestination, int32 baseType)
1894 {
1895 	if (baseType == 1)
1896 		// if inSource is in bits format
1897 		return translate_from_bits(inSource, outType, outDestination);
1898 	else if (baseType == 0)
1899 		// if inSource is NOT in bits format
1900 		return translate_from_bmp(inSource, outType, outDestination);
1901 	else
1902 		return B_NO_TRANSLATOR;
1903 }
1904 
1905 BView *
NewConfigView(TranslatorSettings * settings)1906 BMPTranslator::NewConfigView(TranslatorSettings *settings)
1907 {
1908 	return new BMPView(BRect(0, 0, 225, 175),
1909 		B_TRANSLATE("BMPTranslator Settings"), B_FOLLOW_ALL, B_WILL_DRAW,
1910 		settings);
1911 }
1912