BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / translators / ico / ICO.cpp
blobef83bfa24198ce4eeabbc9b522275627565f4aea
1 /*
2 * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
6 // ToDo: This definitely needs to be worked over for endian issues
8 #include "ICO.h"
9 #include "ICOTranslator.h"
11 #include <ByteOrder.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
18 //#define TRACE_ICO
19 #ifdef TRACE_ICO
20 # define TRACE(x) printf x
21 #else
22 # define TRACE(x) ;
23 #endif
26 using namespace ICO;
29 static const rgba32_color kMagicTransparentColor = *(rgba32_color *)&B_TRANSPARENT_MAGIC_RGBA32;
32 class TempAllocator {
33 public:
34 TempAllocator() : fMemory(NULL) {}
35 ~TempAllocator() { free(fMemory); }
37 void *Allocate(size_t size) { return fMemory = malloc(size); }
39 private:
40 void *fMemory;
44 bool
45 ico_header::IsValid() const
47 return reserved == 0
48 && (type == kTypeIcon || type == kTypeCursor)
49 && entry_count < 32;
53 void
54 ico_header::SwapToHost()
56 swap_data(B_UINT16_TYPE, this, sizeof(ico_header), B_SWAP_LENDIAN_TO_HOST);
60 void
61 ico_header::SwapFromHost()
63 swap_data(B_UINT16_TYPE, this, sizeof(ico_header), B_SWAP_HOST_TO_LENDIAN);
67 // #pragma mark -
70 void
71 ico_dir_entry::SwapToHost()
73 swap_data(B_UINT16_TYPE, &planes, sizeof(uint16) * 2, B_SWAP_LENDIAN_TO_HOST);
74 swap_data(B_UINT32_TYPE, &size, sizeof(uint32) * 2, B_SWAP_LENDIAN_TO_HOST);
78 void
79 ico_dir_entry::SwapFromHost()
81 swap_data(B_UINT16_TYPE, &planes, sizeof(uint16) * 2, B_SWAP_HOST_TO_LENDIAN);
82 swap_data(B_UINT32_TYPE, &size, sizeof(uint32) * 2, B_SWAP_HOST_TO_LENDIAN);
86 // #pragma mark -
89 bool
90 ico_bitmap_header::IsValid() const
92 return size == sizeof(ico_bitmap_header) && compression == 0
93 && (bits_per_pixel == 1 || bits_per_pixel == 4 || bits_per_pixel == 8
94 || bits_per_pixel == 16 || bits_per_pixel == 24 || bits_per_pixel == 32);
98 void
99 ico_bitmap_header::SwapToHost()
101 swap_data(B_UINT32_TYPE, &size, sizeof(uint32) * 3, B_SWAP_LENDIAN_TO_HOST);
102 swap_data(B_UINT16_TYPE, &planes, sizeof(uint16) * 2, B_SWAP_LENDIAN_TO_HOST);
103 swap_data(B_UINT32_TYPE, &compression, sizeof(uint32) * 6, B_SWAP_LENDIAN_TO_HOST);
107 void
108 ico_bitmap_header::SwapFromHost()
110 swap_data(B_UINT32_TYPE, &size, sizeof(uint32) * 3, B_SWAP_HOST_TO_LENDIAN);
111 swap_data(B_UINT16_TYPE, &planes, sizeof(uint16) * 2, B_SWAP_HOST_TO_LENDIAN);
112 swap_data(B_UINT32_TYPE, &compression, sizeof(uint32) * 6, B_SWAP_HOST_TO_LENDIAN);
116 // #pragma mark -
119 static inline uint8 *
120 get_data_row(uint8 *data, int32 dataSize, int32 rowBytes, int32 row)
122 return data + dataSize - (row + 1) * rowBytes;
126 static inline int32
127 get_bytes_per_row(int32 width, int32 bitsPerPixel)
129 return (((bitsPerPixel * width + 7) / 8) + 3) & ~3;
133 static inline void
134 set_1_bit_per_pixel(uint8 *line, int32 x, int32 value)
136 int32 mask = 1 << (7 - (x & 7));
137 if (value)
138 line[x / 8] |= mask;
139 else
140 line[x / 8] &= ~mask;
144 static inline void
145 set_4_bits_per_pixel(uint8 *line, int32 x, int32 value)
147 int32 shift = x & 1 ? 0 : 4;
148 int32 mask = ~0L & (0xf0 >> shift);
150 line[x / 2] &= mask;
151 line[x / 2] |= value << shift;
155 static inline int32
156 get_1_bit_per_pixel(uint8 *line, int32 x)
158 return (line[x / 8] >> (7 - (x & 7))) & 1;
162 static inline int32
163 get_4_bits_per_pixel(uint8 *line, int32 x)
165 return (line[x / 2] >> (4 * ((x + 1) & 1))) & 0xf;
169 static uint8
170 get_alpha_value(color_space space, uint32 value)
172 // ToDo: support more color spaces
173 if (space == B_RGBA32)
174 return value >> 24;
176 return 0;
180 static uint16
181 rgba32_color_to_16_bit_color(rgba32_color &color)
183 return ((color.blue >> 3) << 11) | ((color.green >> 2) << 5) | (color.red >> 3);
187 static int32
188 find_rgba32_color(rgba32_color *palette, int32 numColors, rgba32_color &color)
190 // ToDo: sorting and binary search?
191 for (int32 i = 0; i < numColors; i++) {
192 if (palette[i] == color)
193 return i;
196 return -1;
200 static inline rgba32_color
201 get_rgba32_color_from_bits(TranslatorBitmap &bitsHeader, uint8 *data, int32 x, int32 y)
203 data += bitsHeader.rowBytes * y;
205 switch (bitsHeader.colors) {
206 case B_RGBA32:
207 return *(rgba32_color *)(data + 4 * x);
208 case B_RGB32:
209 default:
210 // stupid applications like ArtPaint use the alpha channel in B_RGB32 images...
211 rgba32_color color = *(rgba32_color *)(data + 4 * x);
212 if (color.alpha >= 128)
213 color.alpha = 255;
214 else
215 color.alpha = 0;
216 return color;
217 // ToDo: support some more color spaces...
222 static int32
223 fill_palette(TranslatorBitmap &bitsHeader, uint8 *data, rgba32_color *palette)
225 int32 numColors = 0;
227 for (int32 y = 0; y < bitsHeader.bounds.IntegerHeight() + 1; y++) {
228 for (int32 x = 0; x < bitsHeader.bounds.IntegerWidth() + 1; x++) {
229 rgba32_color color = get_rgba32_color_from_bits(bitsHeader, data, x, y);
231 int32 index = find_rgba32_color(palette, numColors, color);
232 if (index == -1) {
233 // add this color if there is space left
234 if (numColors == 256)
235 return -1;
237 color.alpha = 0;
238 // the alpha channel is actually unused
239 palette[numColors++] = color;
244 return numColors;
248 /** This function is used to determine, if a true alpha channel has to
249 * be used in order to preserve all information.
252 static bool
253 has_true_alpha_channel(color_space space, uint8 *data,
254 int32 width, int32 height, int32 bytesPerRow)
256 for (int32 y = 0; y < height; y++) {
257 for (int32 x = 0; x < width; x++) {
258 uint8 value = get_alpha_value(space, ((uint32 *)data)[x]);
259 if (value != 0 && value != 255)
260 return true;
263 data += bytesPerRow;
266 return false;
270 static status_t
271 convert_data_to_bits(ico_dir_entry &entry, ico_bitmap_header &header,
272 const rgba32_color *palette, BPositionIO &source,
273 BPositionIO &target)
275 uint16 bitsPerPixel = header.bits_per_pixel;
277 // round row bytes to next 4 byte boundary
278 int32 xorRowBytes = get_bytes_per_row(entry.width, header.bits_per_pixel);
279 int32 andRowBytes = 0;
280 if (bitsPerPixel != 32)
281 andRowBytes = get_bytes_per_row(entry.width, 1);
282 int32 outRowBytes = entry.width * 4;
284 // allocate buffers
285 TempAllocator xorAllocator, andAllocator, rowAllocator;
287 int32 xorDataSize = xorRowBytes * entry.height;
288 uint8 *xorData = (uint8 *)xorAllocator.Allocate(xorDataSize);
289 if (xorData == NULL)
290 return B_NO_MEMORY;
292 int32 andDataSize = andRowBytes * entry.height;
293 uint8 *andData = NULL;
294 if (bitsPerPixel != 32) {
295 andData = (uint8 *)andAllocator.Allocate(andDataSize);
296 if (andData == NULL)
297 return B_NO_MEMORY;
300 rgba32_color *outRowData = (rgba32_color *)rowAllocator.Allocate(outRowBytes);
301 if (outRowData == NULL)
302 return B_NO_MEMORY;
304 ssize_t bytesRead = source.Read(xorData, xorDataSize);
305 if (bytesRead != xorDataSize)
306 return B_BAD_DATA;
308 if (bitsPerPixel != 32) {
309 bytesRead = source.Read(andData, andDataSize);
310 if (bytesRead != andDataSize) {
311 // reading the alpha channel failed, so we're ignoring it
312 // (but we're still able to show the image data)
313 andData = NULL;
317 for (uint32 row = 0; row < entry.height; row++) {
318 for (uint32 x = 0; x < entry.width; x++) {
319 uint8 *line = get_data_row(xorData, xorDataSize, xorRowBytes, row);
321 if (palette != NULL) {
322 uint8 index;
324 switch (bitsPerPixel) {
325 case 1:
326 index = get_1_bit_per_pixel(line, x);
327 break;
328 case 4:
329 index = get_4_bits_per_pixel(line, x);
330 break;
331 case 8:
332 default:
333 index = line[x];
334 break;
337 outRowData[x] = palette[index];
338 } else {
339 switch (bitsPerPixel) {
340 case 16:
342 uint16 color = ((uint16 *)line)[x];
343 outRowData[x].blue = (color >> 11) << 3;
344 outRowData[x].green = ((color >> 5) & 0x3f) << 3;
345 outRowData[x].red = (color & 0x1f) << 3;
346 break;
349 case 24:
350 outRowData[x].blue = line[x * 3 + 0];
351 outRowData[x].green = line[x * 3 + 1];
352 outRowData[x].red = line[x * 3 + 2];
353 break;
355 case 32:
356 outRowData[x] = ((rgba32_color *)line)[x];
357 break;
361 if (bitsPerPixel != 32) {
362 // set alpha channel
363 if (andData != NULL
364 && get_1_bit_per_pixel(get_data_row(andData, andDataSize, andRowBytes, row), x))
365 outRowData[x] = kMagicTransparentColor;
366 else
367 outRowData[x].alpha = 255;
368 } else if (outRowData[x].alpha == 0)
369 outRowData[x] = kMagicTransparentColor;
372 ssize_t bytesWritten = target.Write(outRowData, outRowBytes);
373 if (bytesWritten < B_OK)
374 return bytesWritten;
375 if (bytesWritten != outRowBytes)
376 return B_IO_ERROR;
379 return B_OK;
383 static status_t
384 convert_bits_to_data(TranslatorBitmap &bitsHeader, uint8 *bitsData, ico_dir_entry &entry,
385 ico_bitmap_header &header, rgba32_color *palette, BPositionIO &target)
387 int32 bitsPerPixel = header.bits_per_pixel;
389 // round row bytes to next 4 byte boundary
390 int32 xorRowBytes = get_bytes_per_row(entry.width, bitsPerPixel);
391 int32 andRowBytes = get_bytes_per_row(entry.width, 1);
393 TempAllocator xorAllocator, andAllocator;
395 uint8 *xorRowData = (uint8 *)xorAllocator.Allocate(xorRowBytes);
396 if (xorRowData == NULL)
397 return B_NO_MEMORY;
399 uint8 *andRowData = (uint8 *)andAllocator.Allocate(andRowBytes);
400 if (andRowData == NULL)
401 return B_NO_MEMORY;
403 int32 numColors = 1 << bitsPerPixel;
405 // write XOR data (the actual image data)
406 // (ICO data is upside down, so we're starting at the last line)
408 for (uint32 row = entry.height; row-- > 0;) {
409 for (uint32 x = 0; x < entry.width; x++) {
410 rgba32_color color = get_rgba32_color_from_bits(bitsHeader, bitsData, x, row);
412 if (palette != NULL) {
413 uint8 index = find_rgba32_color(palette, numColors, color);
415 switch (bitsPerPixel) {
416 case 1:
417 set_1_bit_per_pixel(xorRowData, x, index);
418 break;
419 case 4:
420 set_4_bits_per_pixel(xorRowData, x, index);
421 break;
422 case 8:
423 default:
424 xorRowData[x] = index;
425 break;
427 } else {
428 switch (bitsPerPixel) {
429 default:
430 case 16:
432 uint16 *data = (uint16 *)xorRowData;
433 data[x] = rgba32_color_to_16_bit_color(color);
434 break;
437 case 24:
439 xorRowData[x * 3 + 0] = color.blue;
440 xorRowData[x * 3 + 1] = color.green;
441 xorRowData[x * 3 + 2] = color.red;
442 break;
445 case 32:
447 rgba32_color *data = (rgba32_color *)xorRowData;
448 data[x] = color;
449 break;
455 ssize_t bytesWritten = target.Write(xorRowData, xorRowBytes);
456 if (bytesWritten < B_OK)
457 return bytesWritten;
458 if (bytesWritten != xorRowBytes)
459 return B_IO_ERROR;
462 if (bitsPerPixel == 32) {
463 // the alpha channel has already been written with the image data
464 return B_OK;
467 // write AND data (the transparency bit)
469 for (uint32 row = entry.height; row-- > 0;) {
470 for (uint32 x = 0; x < entry.width; x++) {
471 rgba32_color color = get_rgba32_color_from_bits(bitsHeader, bitsData, x, row);
472 bool transparent = *(uint32 *)&color == B_TRANSPARENT_MAGIC_RGBA32 || color.alpha == 0;
474 set_1_bit_per_pixel(andRowData, x, transparent ? 1 : 0);
477 ssize_t bytesWritten = target.Write(andRowData, andRowBytes);
478 if (bytesWritten < B_OK)
479 return bytesWritten;
480 if (bytesWritten != andRowBytes)
481 return B_IO_ERROR;
484 return B_OK;
488 // #pragma mark -
491 bool
492 ICO::is_valid_size(int32 size)
494 return size == 16 || size == 32 || size == 48;
498 status_t
499 ICO::identify(BMessage *settings, BPositionIO &stream, uint8 &type, int32 &bitsPerPixel)
501 // read in the header
503 ico_header header;
504 if (stream.Read(&header, sizeof(ico_header)) != (ssize_t)sizeof(ico_header))
505 return B_BAD_VALUE;
507 header.SwapToHost();
509 // check header
511 if (!header.IsValid())
512 return B_BAD_VALUE;
514 int32 iconIndex = 0;
515 type = header.type;
517 if (settings) {
518 // Add page count to ioExtension
519 settings->RemoveName(kDocumentCount);
520 settings->AddInt32(kDocumentCount, header.entry_count);
522 // Check if a document index has been specified
523 if (settings->FindInt32(kDocumentIndex, &iconIndex) == B_OK)
524 iconIndex--;
525 else
526 iconIndex = 0;
528 if (iconIndex < 0 || iconIndex >= header.entry_count)
529 return B_NO_TRANSLATOR;
532 TRACE(("iconIndex = %ld, count = %ld\n", iconIndex, header.entry_count));
534 // read in directory entries
536 for (uint32 i = 0; i < header.entry_count; i++) {
537 ico_dir_entry entry;
538 if (stream.Read(&entry, sizeof(ico_dir_entry)) != (ssize_t)sizeof(ico_dir_entry))
539 return B_BAD_VALUE;
541 entry.SwapToHost();
542 TRACE(("width: %d, height: %d, planes: %d, color_count: %d, bits_per_pixel: %d, size: %ld, offset: %ld\n",
543 entry.width, entry.height, entry.planes, entry.color_count, entry.bits_per_pixel,
544 entry.size, entry.offset));
546 ico_bitmap_header bitmapHeader;
547 if (stream.ReadAt(entry.offset, &bitmapHeader, sizeof(ico_bitmap_header)) != (ssize_t)sizeof(ico_bitmap_header))
548 return B_BAD_VALUE;
550 bitmapHeader.SwapToHost();
551 TRACE(("size: %ld, width: %ld, height: %ld, bits_per_pixel: %d, x/y per meter: %ld:%ld, compression: %ld, image_size: %ld, colors used: %ld, important colors: %ld\n",
552 bitmapHeader.size, bitmapHeader.width, bitmapHeader.height, bitmapHeader.bits_per_pixel,
553 bitmapHeader.x_pixels_per_meter, bitmapHeader.y_pixels_per_meter,
554 bitmapHeader.compression, bitmapHeader.image_size, bitmapHeader.colors_used,
555 bitmapHeader.important_colors));
557 if (!bitmapHeader.IsValid())
558 return B_BAD_VALUE;
560 if ((uint32)iconIndex == i)
561 bitsPerPixel = bitmapHeader.bits_per_pixel;
564 return B_OK;
568 /** Converts an ICO image of any type into a B_RGBA32 B_TRANSLATOR_BITMAP.
571 status_t
572 ICO::convert_ico_to_bits(BMessage *settings, BPositionIO &source, BPositionIO &target)
574 ico_header header;
575 if (source.Read(&header, sizeof(ico_header)) != (ssize_t)sizeof(ico_header))
576 return B_BAD_VALUE;
578 header.SwapToHost();
580 // check header
582 if (!header.IsValid())
583 return B_BAD_VALUE;
585 int32 iconIndex = 0;
587 if (settings) {
588 // Check if a document index has been specified
589 if (settings->FindInt32(kDocumentIndex, &iconIndex) == B_OK)
590 iconIndex--;
591 else
592 iconIndex = 0;
594 if (iconIndex < 0 || iconIndex >= header.entry_count)
595 return B_BAD_VALUE;
598 // read in selected entry
600 ico_dir_entry entry;
601 if (source.ReadAt(sizeof(ico_header) + sizeof(ico_dir_entry) * iconIndex,
602 &entry, sizeof(ico_dir_entry)) != (ssize_t)sizeof(ico_dir_entry))
603 return B_BAD_VALUE;
605 entry.SwapToHost();
606 source.Seek(entry.offset, SEEK_SET);
608 ico_bitmap_header bitmapHeader;
609 if (source.Read(&bitmapHeader, sizeof(ico_bitmap_header)) != (ssize_t)sizeof(ico_bitmap_header))
610 return B_BAD_VALUE;
612 bitmapHeader.SwapToHost();
614 if (!bitmapHeader.IsValid())
615 return B_BAD_VALUE;
617 if (bitmapHeader.compression != 0)
618 return EOPNOTSUPP;
620 int32 numColors = 0;
621 if (bitmapHeader.bits_per_pixel <= 8)
622 numColors = 1L << bitmapHeader.bits_per_pixel;
624 // This is a work-around for a broken ICO file writer that publishes
625 // a wrong image height in the ico_dir_entry structure
626 if (entry.size != 0 && 2 * entry.width == entry.height && numColors != 0
627 && sizeof(rgba32_color) * numColors + entry.width * entry.height > entry.size)
628 entry.height = entry.width;
630 TranslatorBitmap bitsHeader;
631 bitsHeader.magic = B_TRANSLATOR_BITMAP;
632 bitsHeader.bounds.left = 0;
633 bitsHeader.bounds.top = 0;
634 bitsHeader.bounds.right = entry.width - 1;
635 bitsHeader.bounds.bottom = entry.height - 1;
636 bitsHeader.bounds.Set(0, 0, entry.width - 1, entry.height - 1);
637 bitsHeader.rowBytes = entry.width * 4;
638 bitsHeader.colors = B_RGBA32;
639 bitsHeader.dataSize = bitsHeader.rowBytes * entry.height;
641 // read in palette
643 rgba32_color palette[256];
644 if (numColors > 0) {
645 if (source.Read(palette, numColors * 4) != numColors * 4)
646 return B_BAD_VALUE;
648 // clear alpha channel (it's not used in ICO color information)
649 for (int32 i = 0; i < numColors; i++)
650 palette[i].alpha = 0;
653 // write out Be's Bitmap header
654 swap_data(B_UINT32_TYPE, &bitsHeader, sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN);
655 target.Write(&bitsHeader, sizeof(TranslatorBitmap));
657 return convert_data_to_bits(entry, bitmapHeader, numColors > 0 ? palette : NULL, source, target);
661 status_t
662 ICO::convert_bits_to_ico(BMessage *settings, BPositionIO &source,
663 TranslatorBitmap &bitsHeader, BPositionIO &target)
665 int32 width = bitsHeader.bounds.IntegerWidth() + 1;
666 int32 height = bitsHeader.bounds.IntegerHeight() + 1;
667 if (!is_valid_size(width) || !is_valid_size(height))
668 return B_BAD_VALUE;
670 int32 bitsPerPixel;
671 switch (bitsHeader.colors) {
672 case B_RGBA32:
673 bitsPerPixel = 32;
674 break;
675 case B_RGB32:
676 bitsPerPixel = 24;
677 break;
678 case B_RGB16:
679 bitsPerPixel = 16;
680 break;
681 case B_CMAP8:
682 case B_GRAY8:
683 bitsPerPixel = 8;
684 break;
685 case B_GRAY1:
686 bitsPerPixel = 1;
687 break;
688 default:
689 fprintf(stderr, "unsupported color space.\n");
690 return B_BAD_VALUE;
693 TempAllocator dataAllocator;
694 uint8 *bitsData = (uint8 *)dataAllocator.Allocate(bitsHeader.rowBytes * height);
695 if (bitsData == NULL)
696 return B_NO_MEMORY;
698 ssize_t bytesRead = source.Read(bitsData, bitsHeader.rowBytes * height);
699 if (bytesRead < B_OK)
700 return bytesRead;
702 rgba32_color palette[256];
703 if (bitsPerPixel > 8) {
704 // it's a non-palette mode - but does it have to be?
705 if (bitsHeader.colors != B_RGBA32
706 || !has_true_alpha_channel(bitsHeader.colors, bitsData,
707 width, height, bitsHeader.rowBytes)) {
708 memset(palette, 0, sizeof(palette));
710 // count colors
711 int32 colors = fill_palette(bitsHeader, bitsData, palette);
712 if (colors != -1) {
713 // we fit into a palette mode
714 if (colors > 16)
715 bitsPerPixel = 8;
716 else if (colors > 2)
717 bitsPerPixel = 4;
718 else
719 bitsPerPixel = 1;
723 int32 numColors = 1 << bitsPerPixel;
725 ico_header header;
726 header.type = B_HOST_TO_LENDIAN_INT16(1);
727 header.entry_count = B_HOST_TO_LENDIAN_INT16(1);
728 header.reserved = 0;
730 ssize_t bytesWritten = target.Write(&header, sizeof(ico_header));
731 if (bytesWritten < B_OK)
732 return bytesWritten;
734 ico_dir_entry entry;
735 entry.width = width;
736 entry.height = height;
737 entry.planes = 1;
738 entry.bits_per_pixel = bitsPerPixel;
739 entry.color_count = 0;
740 if (bitsPerPixel <= 8)
741 entry.color_count = numColors;
743 // When bits_per_pixel == 32, the data already contains the alpha channel
745 int32 xorRowBytes = get_bytes_per_row(width, bitsPerPixel);
746 int32 andRowBytes = 0;
747 if (bitsPerPixel != 32)
748 andRowBytes = get_bytes_per_row(width, 1);
750 entry.size = sizeof(ico_bitmap_header) + width * (xorRowBytes + andRowBytes);
751 if (bitsPerPixel <= 8)
752 entry.size += numColors * sizeof(rgba32_color);
753 entry.offset = sizeof(ico_header) + sizeof(ico_dir_entry);
754 entry.reserved = 0;
756 ico_bitmap_header bitmapHeader;
757 memset(&bitmapHeader, 0, sizeof(ico_bitmap_header));
758 bitmapHeader.size = sizeof(ico_bitmap_header);
759 bitmapHeader.width = width;
760 bitmapHeader.height = height + (bitsPerPixel == 32 ? 0 : height);
761 bitmapHeader.bits_per_pixel = bitsPerPixel;
762 bitmapHeader.planes = 1;
763 bitmapHeader.image_size = 0;
764 if (bitsPerPixel <= 8)
765 bitmapHeader.colors_used = numColors;
767 entry.SwapFromHost();
768 bitmapHeader.SwapFromHost();
770 bytesWritten = target.Write(&entry, sizeof(ico_dir_entry));
771 if (bytesWritten < B_OK)
772 return bytesWritten;
774 bytesWritten = target.Write(&bitmapHeader, sizeof(ico_bitmap_header));
775 if (bytesWritten < B_OK)
776 return bytesWritten;
778 // we'll need them in convert_bits_to_data()
779 entry.SwapToHost();
780 bitmapHeader.SwapToHost();
782 if (bitsPerPixel <= 8) {
783 bytesWritten = target.Write(palette, numColors * sizeof(rgba32_color));
784 if (bytesWritten < B_OK)
785 return bytesWritten;
788 return convert_bits_to_data(bitsHeader, bitsData, entry, bitmapHeader,
789 bitsPerPixel <= 8 ? palette : NULL, target);