2 * Copyright 2002-2009, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Michael Wilber <mwilber@users.berlios.de>
9 #include "BMPTranslator.h"
26 //#define INFO(x) printf(x);
28 //#define ERROR(x) printf(x);
31 #undef B_TRANSLATION_CONTEXT
32 #define B_TRANSLATION_CONTEXT "BMPTranslator"
35 // The input formats that this translator supports.
36 static const translation_format sInputFormats
[] = {
43 "Be Bitmap Format (BMPTranslator)"
55 // The output formats that this translator supports.
56 static const translation_format sOutputFormats
[] = {
63 "Be Bitmap Format (BMPTranslator)"
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}
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
);
86 // ---------------------------------------------------------------
87 // make_nth_translator
89 // Creates a BMPTranslator object to be used by BTranslatorRoster
93 // Parameters: n, The translator to return. Since
94 // BMPTranslator only publishes one
95 // translator, it only returns a
96 // BMPTranslator if n == 0
98 // you, The image_id of the add-on that
99 // contains code (not used).
101 // flags, Has no meaning yet, should be 0.
105 // Returns: NULL if n is not zero,
106 // a new BMPTranslator if n is zero
107 // ---------------------------------------------------------------
109 make_nth_translator(int32 n
, image_id you
, uint32 flags
, ...)
112 return new BMPTranslator();
117 // ---------------------------------------------------------------
120 // Sets up the version info and the name of the translator so that
121 // these values can be returned when they are requested.
130 // ---------------------------------------------------------------
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
)
143 // ---------------------------------------------------------------
155 // ---------------------------------------------------------------
156 BMPTranslator::~BMPTranslator()
160 // ---------------------------------------------------------------
163 // Returns number of bytes of padding required at the end of
164 // the row by the BMP format
167 // Preconditions: If bitsperpixel is zero, a division by zero
168 // will occur, which is bad
170 // Parameters: width, width of the row, in pixels
172 // bitsperpixel, bitdepth of the image
177 // ---------------------------------------------------------------
179 get_padding(uint32 width
, uint16 bitsperpixel
)
183 if (bitsperpixel
> 8) {
184 uint8 bytesPerPixel
= bitsperpixel
/ 8;
185 padding
= (width
* bytesPerPixel
) % 4;
187 uint8 pixelsPerByte
= 8 / bitsperpixel
;
188 if (!(width
% pixelsPerByte
))
189 padding
= (width
/ pixelsPerByte
) % 4;
191 padding
= ((width
+ pixelsPerByte
-
192 (width
% pixelsPerByte
)) /
197 padding
= 4 - padding
;
202 // ---------------------------------------------------------------
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.
209 // Preconditions: If bitsperpixel is zero, a division by zero
210 // will occur, which is bad
212 // Parameters: width, width of the row, in pixels
214 // bitsperpixel, bitdepth of the image
219 // ---------------------------------------------------------------
221 get_rowbytes(uint32 width
, uint16 bitsperpixel
)
224 int32 padding
= get_padding(width
, bitsperpixel
);
226 if (bitsperpixel
> 8) {
227 uint8 bytesPerPixel
= bitsperpixel
/ 8;
228 rowbytes
= (width
* bytesPerPixel
) + padding
;
230 uint8 pixelsPerByte
= 8 / bitsperpixel
;
231 rowbytes
= (width
/ pixelsPerByte
) +
232 ((width
% pixelsPerByte
) ? 1 : 0) + padding
;
238 // ---------------------------------------------------------------
239 // identify_bmp_header
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.
247 // Parameters: inSource, The source of the image data
249 // outInfo, Information about the translator
252 // amtread, Amount of data read from inSource
253 // before this function was called
255 // read, Pointer to the data that was read
256 // in before this function was called
258 // pfileheader, File header info for the BMP is
259 // copied here after it is read from
262 // pmsheader, BMP header info read in from the
265 // pfrommsformat, Set to true if BMP data is BMP
266 // format, false if BMP data is OS/2
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
275 // Returns: B_NO_TRANSLATOR, if the data does not look like
278 // B_ERROR, if the header data could not be converted to host
281 // B_OK, if the data looks like bits data and no errors were
283 // ---------------------------------------------------------------
285 identify_bmp_header(BPositionIO
*inSource
, translator_info
*outInfo
,
286 BMPFileHeader
*pfileheader
= NULL
, MSInfoHeader
*pmsheader
= NULL
,
287 bool *pfrommsformat
= NULL
, off_t
*pos2skip
= NULL
)
289 // read in the fileHeader
291 BMPFileHeader fileHeader
;
293 if (inSource
->Read(buf
, size
) != size
)
294 return B_NO_TRANSLATOR
;
296 // check BMP magic number
297 const uint16 kBmpMagic
= B_HOST_TO_LENDIAN_INT16('MB');
299 memcpy(&sourceMagic
, buf
, sizeof(uint16
));
300 if (sourceMagic
!= kBmpMagic
)
301 return B_NO_TRANSLATOR
;
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
)
311 if (swap_data(B_UINT32_TYPE
,
312 (reinterpret_cast<uint8
*> (&fileHeader
)) + 2, 12,
313 B_SWAP_LENDIAN_TO_HOST
) != B_OK
)
316 if (fileHeader
.reserved
!= 0)
317 return B_NO_TRANSLATOR
;
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
)
326 if (headersize
== sizeof(MSInfoHeader
)) {
329 if (fileHeader
.dataOffset
< 54)
330 return B_NO_TRANSLATOR
;
332 MSInfoHeader msheader
;
333 msheader
.size
= headersize
;
335 reinterpret_cast<uint8
*> (&msheader
) + 4, 36) != 36)
336 return B_NO_TRANSLATOR
;
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
)
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
;
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)");
381 strcat(outInfo
->name
, ")");
382 strcpy(outInfo
->MIME
, "image/x-bmp");
386 pfileheader
->magic
= fileHeader
.magic
;
387 pfileheader
->fileSize
= fileHeader
.fileSize
;
388 pfileheader
->reserved
= fileHeader
.reserved
;
389 pfileheader
->dataOffset
= fileHeader
.dataOffset
;
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
;
405 (*pfrommsformat
) = true;
409 } else if (headersize
== sizeof(OS2InfoHeader
)) {
412 if (fileHeader
.dataOffset
< 26)
413 return B_NO_TRANSLATOR
;
415 OS2InfoHeader os2header
;
416 os2header
.size
= headersize
;
418 reinterpret_cast<uint8
*> (&os2header
) + 4, 8) != 8)
419 return B_NO_TRANSLATOR
;
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
)
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
;
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");
447 if (pfileheader
&& pmsheader
) {
448 pfileheader
->magic
= 'MB';
449 pfileheader
->fileSize
= 0;
450 pfileheader
->reserved
= 0;
451 pfileheader
->dataOffset
= 0;
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;
465 // determine fileSize / imagesize
466 switch (pmsheader
->bitsperpixel
) {
468 if (pos2skip
&& fileHeader
.dataOffset
> 26)
469 (*pos2skip
) = fileHeader
.dataOffset
- 26;
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
;
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));
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
;
505 (*pfrommsformat
) = false;
510 return B_NO_TRANSLATOR
;
513 // ---------------------------------------------------------------
516 // Examines the data from inSource and determines if it is in a
517 // format that this translator knows how to work with.
521 // Parameters: inSource, where the data to examine is
523 // inFormat, a hint about the data in inSource,
524 // it is ignored since it is only a hint
526 // ioExtension, configuration settings for the
529 // outInfo, information about what data is in
530 // inSource and how well this translator
531 // can handle that data is stored here
533 // outType, The format that the user wants
534 // the data in inSource to be
539 // Returns: B_NO_TRANSLATOR, if this translator can't handle
540 // the data in inSource
542 // B_ERROR, if there was an error converting the data to the host
545 // B_BAD_VALUE, if the settings in ioExtension are bad
547 // B_OK, if this translator understand the data and there were
549 // ---------------------------------------------------------------
551 BMPTranslator::DerivedIdentify(BPositionIO
*inSource
,
552 const translation_format
*inFormat
, BMessage
*ioExtension
,
553 translator_info
*outInfo
, uint32 outType
)
555 return identify_bmp_header(inSource
, outInfo
);
558 // ---------------------------------------------------------------
559 // translate_from_bits_to_bmp24
561 // Converts various varieties of the Be Bitmap format ('bits') to
562 // the MS BMP 24-bit format.
566 // Parameters: inSource, contains the bits data to convert
568 // outDestination, where the BMP data will be written
570 // fromspace, the format of the data in inSource
572 // msheader, contains information about the BMP
573 // dimensions and filesize
577 // Returns: B_ERROR, if memory couldn't be allocated or another
580 // B_OK, if no errors occurred
581 // ---------------------------------------------------------------
583 translate_from_bits_to_bmp24(BPositionIO
*inSource
,
584 BPositionIO
*outDestination
, color_space fromspace
, MSInfoHeader
&msheader
)
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;
598 bitsBytesPerPixel
= 4;
604 bitsBytesPerPixel
= 3;
613 bitsBytesPerPixel
= 2;
618 bitsBytesPerPixel
= 1;
624 int32 bitsRowBytes
= msheader
.width
* bitsBytesPerPixel
;
625 int32 padding
= get_padding(msheader
.width
, msheader
.bitsperpixel
);
627 get_rowbytes(msheader
.width
, msheader
.bitsperpixel
);
629 if (msheader
.height
> 0)
630 inSource
->Seek((msheader
.height
- 1) * bitsRowBytes
, SEEK_CUR
);
631 uint8
*bmpRowData
= new (nothrow
) uint8
[bmpRowBytes
];
634 uint8
*bitsRowData
= new (nothrow
) uint8
[bitsRowBytes
];
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();
645 delete [] bmpRowData
;
646 delete [] bitsRowData
;
650 while (rd
== static_cast<ssize_t
>(bitsRowBytes
)) {
651 for (int32 i
= 0; i
< msheader
.width
; i
++) {
652 uint8
*bitspixel
, *bmppixel
;
658 memcpy(bmpRowData
+ (i
* 3),
659 bitsRowData
+ (i
* bitsBytesPerPixel
), 3);
664 bitspixel
= bitsRowData
+ (i
* bitsBytesPerPixel
);
665 bmppixel
= bmpRowData
+ (i
* 3);
666 if (fromspace
== B_RGB16
)
667 val
= bitspixel
[0] + (bitspixel
[1] << 8);
669 val
= bitspixel
[1] + (bitspixel
[0] << 8);
671 ((val
& 0x1f) << 3) | ((val
& 0x1f) >> 2);
673 ((val
& 0x7e0) >> 3) | ((val
& 0x7e0) >> 9);
675 ((val
& 0xf800) >> 8) | ((val
& 0xf800) >> 13);
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);
688 val
= bitspixel
[1] + (bitspixel
[0] << 8);
690 ((val
& 0x1f) << 3) | ((val
& 0x1f) >> 2);
692 ((val
& 0x3e0) >> 2) | ((val
& 0x3e0) >> 7);
694 ((val
& 0x7c00) >> 7) | ((val
& 0x7c00) >> 12);
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];
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];
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
;
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];
735 bitspixel
= bitsRowData
+ (i
* bitsBytesPerPixel
);
736 bmppixel
= bmpRowData
+ (i
* 3);
738 int32 comp
= 255 - bitspixel
[2] - bitspixel
[3];
739 bmppixel
[0] = (comp
< 0) ? 0 : comp
;
741 comp
= 255 - bitspixel
[1] - bitspixel
[3];
742 bmppixel
[1] = (comp
< 0) ? 0 : comp
;
744 comp
= 255 - bitspixel
[0] - bitspixel
[3];
745 bmppixel
[2] = (comp
< 0) ? 0 : comp
;
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];
761 } // switch (fromspace)
762 } // for for (uint32 i = 0; i < msheader.width; i++)
764 outDestination
->Write(bmpRowData
, bmpRowBytes
);
766 // if I've read all of the pixel data, break
767 // out of the loop so I don't try to read
769 if (bmppixrow
== abs(msheader
.height
))
772 if (msheader
.height
> 0)
773 inSource
->Seek(bitsRowBytes
* -2, SEEK_CUR
);
774 rd
= inSource
->Read(bitsRowData
, bitsRowBytes
);
775 } // while (rd == bitsRowBytes)
778 delete[] bitsRowData
;
783 // ---------------------------------------------------------------
784 // translate_from_bits8_to_bmp8
786 // Converts 8-bit Be Bitmaps ('bits') to the MS 8-bit BMP format
790 // Parameters: inSource, contains the bits data to convert
792 // outDestination, where the BMP data will be written
794 // bitsRowBytes, number of bytes in one row of
797 // msheader, contains information about the BMP
798 // dimensions and filesize
802 // Returns: B_ERROR, if memory couldn't be allocated or another
805 // B_OK, if no errors occurred
806 // ---------------------------------------------------------------
808 translate_from_bits8_to_bmp8(BPositionIO
*inSource
,
809 BPositionIO
*outDestination
, int32 bitsRowBytes
, MSInfoHeader
&msheader
)
811 int32 padding
= get_padding(msheader
.width
, msheader
.bitsperpixel
);
813 get_rowbytes(msheader
.width
, msheader
.bitsperpixel
);
815 if (msheader
.height
> 0)
816 inSource
->Seek((msheader
.height
- 1) * bitsRowBytes
, SEEK_CUR
);
817 uint8
*bmpRowData
= new (nothrow
) uint8
[bmpRowBytes
];
820 uint8
*bitsRowData
= new (nothrow
) uint8
[bitsRowBytes
];
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
);
831 // if I've read all of the pixel data, break
832 // out of the loop so I don't try to read
834 if (bmppixrow
== abs(msheader
.height
))
837 if (msheader
.height
> 0)
838 inSource
->Seek(bitsRowBytes
* -2, SEEK_CUR
);
839 rd
= inSource
->Read(bitsRowData
, bitsRowBytes
);
840 } // while (rd == bitsRowBytes)
843 delete[] bitsRowData
;
848 // ---------------------------------------------------------------
849 // translate_from_bits1_to_bmp1
851 // Converts 1-bit Be Bitmaps ('bits') to the MS 1-bit BMP format
855 // Parameters: inSource, contains the bits data to convert
857 // outDestination, where the BMP data will be written
859 // bitsRowBytes, number of bytes in one row of
862 // msheader, contains information about the BMP
863 // dimensions and filesize
867 // Returns: B_ERROR, if memory couldn't be allocated or another
870 // B_OK, if no errors occurred
871 // ---------------------------------------------------------------
873 translate_from_bits1_to_bmp1(BPositionIO
*inSource
,
874 BPositionIO
*outDestination
, int32 bitsRowBytes
, MSInfoHeader
&msheader
)
876 uint8 pixelsPerByte
= 8 / msheader
.bitsperpixel
;
878 get_rowbytes(msheader
.width
, msheader
.bitsperpixel
);
880 if (msheader
.height
> 0)
881 inSource
->Seek((msheader
.height
- 1) * bitsRowBytes
, SEEK_CUR
);
882 uint8
*bmpRowData
= new (nothrow
) uint8
[bmpRowBytes
];
885 uint8
*bitsRowData
= new (nothrow
) uint8
[bitsRowBytes
];
890 ssize_t rd
= inSource
->Read(bitsRowData
, bitsRowBytes
);
891 while (rd
== bitsRowBytes
) {
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
903 if (pixels
& compbit
)
909 bmpRowData
[bmppixcol
/ pixelsPerByte
] |=
910 index
<< (7 - (bmppixcol
% pixelsPerByte
));
915 outDestination
->Write(bmpRowData
, bmpRowBytes
);
917 // if I've read all of the pixel data, break
918 // out of the loop so I don't try to read
920 if (bmppixrow
== abs(msheader
.height
))
923 if (msheader
.height
> 0)
924 inSource
->Seek(bitsRowBytes
* -2, SEEK_CUR
);
925 rd
= inSource
->Read(bitsRowData
, bitsRowBytes
);
926 } // while (rd == bitsRowBytes)
929 delete[] bitsRowData
;
934 // ---------------------------------------------------------------
937 // Writes the MS BMP headers (fileHeader and msheader)
938 // to outDestination.
942 // Parameters: outDestination, where the headers are written to
944 // fileHeader, BMP file header data
946 // msheader, BMP info header data
950 // Returns: B_ERROR, if something went wrong
952 // B_OK, if there were no problems writing out the headers
953 // ---------------------------------------------------------------
955 write_bmp_headers(BPositionIO
*outDestination
, BMPFileHeader
&fileHeader
,
956 MSInfoHeader
&msheader
)
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
)
967 if (swap_data(B_UINT32_TYPE
, bmpheaders
+ 2, 12,
968 B_SWAP_HOST_TO_LENDIAN
) != B_OK
)
970 if (swap_data(B_UINT32_TYPE
, bmpheaders
+ 14,
971 sizeof(MSInfoHeader
), B_SWAP_HOST_TO_LENDIAN
) != B_OK
)
973 if (outDestination
->Write(bmpheaders
, 54) != 54)
979 // ---------------------------------------------------------------
980 // translate_from_bits
982 // Convert the data in inSource from the Be Bitmap format ('bits')
983 // to the format specified in outType (either bits or BMP).
987 // Parameters: inSource, the bits data to translate
989 // outType, the type of data to convert to
991 // outDestination, where the output is written to
995 // Returns: B_NO_TRANSLATOR, if the data is not in a supported
998 // B_ERROR, if there was an error allocating memory or some other
1001 // B_OK, if successfully translated the data from the bits format
1002 // ---------------------------------------------------------------
1004 BMPTranslator::translate_from_bits(BPositionIO
*inSource
, uint32 outType
,
1005 BPositionIO
*outDestination
)
1007 bool bheaderonly
, bdataonly
;
1008 bheaderonly
= bdataonly
= false;
1010 TranslatorBitmap bitsHeader
;
1012 result
= identify_bits_header(inSource
, NULL
, &bitsHeader
);
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;
1023 MSInfoHeader msheader
;
1026 static_cast<uint32
> (bitsHeader
.bounds
.Width() + 1);
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;
1035 // determine fileSize / imagesize
1036 switch (bitsHeader
.colors
) {
1054 fileHeader
.dataOffset
= 54;
1055 msheader
.bitsperpixel
= 24;
1056 msheader
.compression
= BMP_NO_COMPRESS
;
1057 msheader
.imagesize
= get_rowbytes(msheader
.width
, 24) *
1059 fileHeader
.fileSize
= fileHeader
.dataOffset
+
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
+
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
+
1094 return B_NO_TRANSLATOR
;
1097 // write out the BMP headers
1098 if (bheaderonly
|| (!bheaderonly
&& !bdataonly
)) {
1099 result
= write_bmp_headers(outDestination
, fileHeader
, msheader
);
1104 // if user only wants the header, bail out
1105 // before the data is written
1108 // write out the BMP pixel data
1109 switch (bitsHeader
.colors
) {
1126 return translate_from_bits_to_bmp24(inSource
, outDestination
,
1127 bitsHeader
.colors
, msheader
);
1132 // write palette to BMP file
1134 uint8
* palHandle
= pal
;
1135 if (bitsHeader
.colors
== B_CMAP8
) {
1136 // write system palette
1137 const color_map
*pmap
= system_colors();
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
;
1149 // write gray palette
1150 for (int32 i
= 0; i
< 256; i
++) {
1158 ssize_t written
= outDestination
->Write(pal
, 1024);
1161 if (written
!= 1024)
1164 return translate_from_bits8_to_bmp8(inSource
, outDestination
,
1165 bitsHeader
.rowBytes
, msheader
);
1170 // write monochrome palette to the BMP file
1171 const uint32 monopal
[] = { 0x00ffffff, 0x00000000 };
1172 ssize_t written
= outDestination
->Write(monopal
, 8);
1178 return translate_from_bits1_to_bmp1(inSource
, outDestination
,
1179 bitsHeader
.rowBytes
, msheader
);
1183 return B_NO_TRANSLATOR
;
1186 return B_NO_TRANSLATOR
;
1189 // ---------------------------------------------------------------
1190 // translate_from_bmpnpal_to_bits
1192 // Translates a non-palette BMP from inSource to the B_RGB32
1197 // Parameters: inSource, the BMP data to be translated
1199 // outDestination, where the bits data will be written to
1201 // msheader, header information about the BMP to be written
1205 // Returns: B_ERROR, if there is an error allocating memory
1207 // B_OK, if all went well
1208 // ---------------------------------------------------------------
1210 translate_from_bmpnpal_to_bits(BPositionIO
*inSource
,
1211 BPositionIO
*outDestination
, MSInfoHeader
&msheader
)
1213 int32 bitsRowBytes
= msheader
.width
* 4;
1214 int32 bmpBytesPerPixel
= msheader
.bitsperpixel
/ 8;
1216 get_rowbytes(msheader
.width
, msheader
.bitsperpixel
);
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");
1230 if (msheader
.height
> 0)
1231 outDestination
->Seek((msheader
.height
- 1) * bitsRowBytes
, SEEK_CUR
);
1233 // allocate row buffers
1234 uint8
*bmpRowData
= new (nothrow
) uint8
[bmpRowBytes
];
1237 uint8
*bitsRowData
= new (nothrow
) uint8
[bitsRowBytes
];
1239 delete[] bmpRowData
;
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
);
1250 status_t ret
= B_OK
;
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
1264 if (bmpBytesPerPixel
== 4) {
1265 memcpy(bitsRowData
, bmpRowData
, bmpRowBytes
);
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];
1274 pBmpPixel
+= bmpBytesPerPixel
;
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
);
1282 if (written
!= bitsRowBytes
) {
1283 // break on write error
1292 delete[] bmpRowData
;
1293 delete[] bitsRowData
;
1298 // ---------------------------------------------------------------
1299 // translate_from_bmppal_to_bits
1301 // Translates an uncompressed, palette BMP from inSource to
1302 // the B_RGB32 bits format.
1306 // Parameters: inSource, the BMP data to be translated
1308 // outDestination, where the bits data will be written to
1310 // msheader, header information about the BMP to be written
1312 // palette, BMP palette for the BMP image
1314 // frommsformat, true if BMP in inSource is in MS format,
1315 // false if it is in OS/2 format
1319 // Returns: B_NO_MEMORY, if there is an error allocating memory
1321 // B_OK, if all went well
1322 // ---------------------------------------------------------------
1324 translate_from_bmppal_to_bits(BPositionIO
*inSource
,
1325 BPositionIO
*outDestination
, MSInfoHeader
&msheader
,
1326 const uint8
*palette
, bool frommsformat
)
1328 uint16 pixelsPerByte
= 8 / msheader
.bitsperpixel
;
1329 uint16 bitsPerPixel
= msheader
.bitsperpixel
;
1330 uint8 palBytesPerPixel
;
1332 palBytesPerPixel
= 4;
1334 palBytesPerPixel
= 3;
1337 mask
= (mask
<< bitsPerPixel
) - 1;
1340 get_rowbytes(msheader
.width
, msheader
.bitsperpixel
);
1341 int32 bmppixrow
= 0;
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
1353 if (msheader
.height
> 0)
1354 outDestination
->Seek((msheader
.height
- 1) * bitsRowBytes
, SEEK_CUR
);
1356 // allocate row buffers
1357 uint8
*bmpRowData
= new (nothrow
) uint8
[bmpRowBytes
];
1360 uint8
*bitsRowData
= new (nothrow
) uint8
[bitsRowBytes
];
1362 delete[] bmpRowData
;
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];
1372 (bitsPerPixel
* ((pixelsPerByte
- 1) -
1373 (i
% pixelsPerByte
)))) & mask
;
1374 memcpy(bitsRowData
+ (i
* 4),
1375 palette
+ (index
* palBytesPerPixel
), 3);
1378 outDestination
->Write(bitsRowData
, bitsRowBytes
);
1380 // if I've read all of the pixel data, break
1381 // out of the loop so I don't try to read
1383 if (bmppixrow
== abs(msheader
.height
))
1386 if (msheader
.height
> 0)
1387 outDestination
->Seek(bitsRowBytes
* -2, SEEK_CUR
);
1388 rd
= inSource
->Read(bmpRowData
, bmpRowBytes
);
1391 delete[] bmpRowData
;
1392 delete[] bitsRowData
;
1398 // ---------------------------------------------------------------
1401 // Copies count 32-bit pixels with a color value of pixel to dest.
1405 // Parameters: dest, where the pixel data will be copied to
1407 // pixel, the 32-bit color value to copy to dest
1410 // count, the number of times pixel is copied to
1416 // ---------------------------------------------------------------
1418 pixelcpy(uint8
*dest
, uint32 pixel
, uint32 count
)
1420 for (uint32 i
= 0; i
< count
; i
++) {
1421 memcpy(dest
, &pixel
, 3);
1426 // ---------------------------------------------------------------
1427 // translate_from_bmppalr_to_bits
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.
1436 // Parameters: inSource, the BMP data to be translated
1438 // outDestination, where the bits data will be written to
1440 // datasize, number of bytes of data needed for the bits output
1442 // msheader, header information about the BMP to be written
1444 // palette, BMP palette for data in inSource
1448 // Returns: B_ERROR, if there is an error allocating memory
1450 // B_OK, if all went well
1451 // ---------------------------------------------------------------
1453 translate_from_bmppalr_to_bits(BPositionIO
*inSource
,
1454 BPositionIO
*outDestination
, int32 datasize
, MSInfoHeader
&msheader
,
1455 const uint8
*palette
)
1457 uint16 pixelsPerByte
= 8 / msheader
.bitsperpixel
;
1458 uint16 bitsPerPixel
= msheader
.bitsperpixel
;
1459 uint8 mask
= (1 << bitsPerPixel
) - 1;
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
1473 uint8
*bitsRowData
= new (nothrow
) uint8
[bitsRowBytes
];
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);
1487 // abort if all of the pixels in the row
1488 // have already been drawn to
1489 if (bmppixcol
== msheader
.width
) {
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
;
1500 rd
= inSource
->Read(&indices
, 1);
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);
1514 rd
= inSource
->Read(&code
, 1);
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
);
1530 if (bmppixrow
< rowCount
)
1531 outDestination
->Seek(rowOffset
, SEEK_CUR
);
1536 // if at the end of a row
1537 if (bmppixcol
== msheader
.width
) {
1538 outDestination
->Write(bitsRowData
, bitsRowBytes
);
1541 if (bmppixrow
< rowCount
)
1542 outDestination
->Seek(rowOffset
, SEEK_CUR
);
1545 while (bmppixrow
< rowCount
) {
1546 pixelcpy(bitsRowData
+ (bmppixcol
* 4), defaultcolor
,
1547 msheader
.width
- bmppixcol
);
1548 outDestination
->Write(bitsRowData
, bitsRowBytes
);
1551 if (bmppixrow
< rowCount
)
1552 outDestination
->Seek(rowOffset
, SEEK_CUR
);
1555 // break out of while loop
1558 // delta, skip several rows and/or columns and
1559 // fill the skipped pixels with the default color
1562 uint8 da
[2], lastcol
, dx
, dy
;
1563 rd
= inSource
->Read(da
, 2);
1571 // abort if dx or dy is too large
1572 if ((dx
+ bmppixcol
>= msheader
.width
) ||
1573 (dy
+ bmppixrow
>= rowCount
)) {
1578 lastcol
= bmppixcol
;
1580 // set all pixels to the first entry in
1581 // the palette, for the number of rows skipped
1583 pixelcpy(bitsRowData
+ (bmppixcol
* 4), defaultcolor
,
1584 msheader
.width
- bmppixcol
);
1585 outDestination
->Write(bitsRowData
, bitsRowBytes
);
1589 outDestination
->Seek(rowOffset
, SEEK_CUR
);
1592 if (bmppixcol
< static_cast<int32
>(lastcol
+ dx
)) {
1593 pixelcpy(bitsRowData
+ (bmppixcol
* 4), defaultcolor
,
1594 dx
+ lastcol
- bmppixcol
);
1595 bmppixcol
= dx
+ lastcol
;
1602 // read code uncompressed indices
1604 // abort if all of the pixels in the row
1605 // have already been drawn to
1606 if (bmppixcol
== msheader
.width
) {
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
;
1619 if (!(code
% pixelsPerByte
))
1620 padding
= (code
/ pixelsPerByte
) % 2;
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
) {
1631 for (uint8 i
= 0; i
< code
; i
++) {
1632 indices
= (uncomp
+ (i
/ pixelsPerByte
))[0];
1634 (bitsPerPixel
* ((pixelsPerByte
- 1) -
1635 (i
% pixelsPerByte
)))) & mask
;
1636 memcpy(bitsRowData
+ (bmppixcol
* 4),
1637 palette
+ (index
* 4), 3);
1645 rd
= inSource
->Read(&count
, 1);
1648 delete[] bitsRowData
;
1653 return B_NO_TRANSLATOR
;
1656 // ---------------------------------------------------------------
1657 // translate_from_bmp
1659 // Convert the data in inSource from the BMP format
1660 // to the format specified in outType (either bits or BMP).
1664 // Parameters: inSource, the bits data to translate
1666 // outType, the type of data to convert to
1668 // outDestination, where the output is written to
1672 // Returns: B_NO_TRANSLATOR, if the data is not in a supported
1675 // B_ERROR, if there was an error allocating memory or some other
1678 // B_OK, if successfully translated the data from the bits format
1679 // ---------------------------------------------------------------
1681 BMPTranslator::translate_from_bmp(BPositionIO
*inSource
, uint32 outType
,
1682 BPositionIO
*outDestination
)
1684 bool bheaderonly
, bdataonly
;
1685 bheaderonly
= bdataonly
= false;
1687 BMPFileHeader fileHeader
;
1688 MSInfoHeader msheader
;
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");
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
);
1709 // if the user only wants the header,
1710 // bail before it is written
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);
1728 rdtotal
= fileHeader
.dataOffset
;
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
);
1735 rd
= min((uint32
)1024, fileHeader
.fileSize
- rdtotal
);
1736 rd
= inSource
->Read(buf
, rd
);
1738 outDestination
->Write(buf
, rd
);
1740 rd
= min((uint32
)1024, fileHeader
.fileSize
- rdtotal
);
1741 rd
= inSource
->Read(buf
, rd
);
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;
1757 // read in palette and/or skip non-BMP data
1758 uint8 bmppalette
[1024];
1760 if (msheader
.bitsperpixel
== 1 ||
1761 msheader
.bitsperpixel
== 4 ||
1762 msheader
.bitsperpixel
== 8) {
1764 uint8 palBytesPerPixel
;
1766 palBytesPerPixel
= 4;
1768 palBytesPerPixel
= 3;
1770 if (!msheader
.colorsused
)
1771 msheader
.colorsused
= 1 << msheader
.bitsperpixel
;
1773 if (inSource
->Read(bmppalette
, msheader
.colorsused
*
1774 palBytesPerPixel
) !=
1775 (off_t
) msheader
.colorsused
* palBytesPerPixel
)
1776 return B_NO_TRANSLATOR
;
1778 // skip over non-BMP data
1780 if (fileHeader
.dataOffset
> (msheader
.colorsused
*
1781 palBytesPerPixel
) + 54)
1782 nskip
= fileHeader
.dataOffset
-
1783 ((msheader
.colorsused
* palBytesPerPixel
) + 54);
1786 } else if (fileHeader
.dataOffset
> 54)
1787 // skip over non-BMP data
1788 nskip
= fileHeader
.dataOffset
- 54;
1790 if (nskip
> 0 && inSource
->Seek(nskip
, SEEK_CUR
) < 0)
1791 return B_NO_TRANSLATOR
;
1793 bitsHeader
.rowBytes
= msheader
.width
* 4;
1794 bitsHeader
.colors
= B_RGB32
;
1795 int32 datasize
= bitsHeader
.rowBytes
* abs(msheader
.height
);
1796 bitsHeader
.dataSize
= datasize
;
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
)
1803 outDestination
->Write(&bitsHeader
, sizeof(TranslatorBitmap
));
1806 // if the user only wants the header,
1807 // bail before the data is written
1810 // write out the actual image data
1811 switch (msheader
.bitsperpixel
) {
1814 return translate_from_bmpnpal_to_bits(inSource
,
1815 outDestination
, msheader
);
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
);
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
);
1828 return B_NO_TRANSLATOR
;
1831 // 4 bit BMP with NO compression
1832 if (!msheader
.compression
)
1833 return translate_from_bmppal_to_bits(inSource
,
1834 outDestination
, msheader
, bmppalette
, frommsformat
);
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
);
1841 return B_NO_TRANSLATOR
;
1844 return translate_from_bmppal_to_bits(inSource
,
1845 outDestination
, msheader
, bmppalette
, frommsformat
);
1848 return B_NO_TRANSLATOR
;
1852 return B_NO_TRANSLATOR
;
1855 // ---------------------------------------------------------------
1858 // Translates the data in inSource to the type outType and stores
1859 // the translated data in outDestination.
1863 // Parameters: inSource, the data to be translated
1865 // inInfo, hint about the data in inSource (not used)
1867 // ioExtension, configuration options for the
1870 // outType, the type to convert inSource to
1872 // outDestination, where the translated data is
1875 // baseType, indicates whether inSource is in the
1876 // bits format, not in the bits format or
1881 // Returns: B_BAD_VALUE, if the options in ioExtension are bad
1883 // B_NO_TRANSLATOR, if this translator doesn't understand the data
1885 // B_ERROR, if there was an error allocating memory or converting
1888 // B_OK, if all went well
1889 // ---------------------------------------------------------------
1891 BMPTranslator::DerivedTranslate(BPositionIO
*inSource
,
1892 const translator_info
*inInfo
, BMessage
*ioExtension
,
1893 uint32 outType
, BPositionIO
*outDestination
, int32 baseType
)
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
);
1902 return B_NO_TRANSLATOR
;
1906 BMPTranslator::NewConfigView(TranslatorSettings
*settings
)
1908 return new BMPView(BRect(0, 0, 225, 175),
1909 B_TRANSLATE("BMPTranslator Settings"), B_FOLLOW_ALL
, B_WILL_DRAW
,