From 36129be0909f741d7c4e9175c16b7d95587b8589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 9 Feb 2005 16:52:39 +0000 Subject: [PATCH] Fixed/implemented support for reading and writing true color ICO images. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@11295 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/translators/icotranslator/ICO.cpp | 130 +++++++++++++----- src/add-ons/translators/icotranslator/ICO.h | 8 +- 2 files changed, 103 insertions(+), 35 deletions(-) diff --git a/src/add-ons/translators/icotranslator/ICO.cpp b/src/add-ons/translators/icotranslator/ICO.cpp index 166fdc1f1b..541c045254 100644 --- a/src/add-ons/translators/icotranslator/ICO.cpp +++ b/src/add-ons/translators/icotranslator/ICO.cpp @@ -24,6 +24,9 @@ using namespace ICO; +static const rgba32_color kMagicTransparentColor = *(rgba32_color *)&B_TRANSPARENT_MAGIC_RGBA32; + + class TempAllocator { public: TempAllocator() : fMemory(NULL) {} @@ -170,8 +173,15 @@ get_alpha_value(color_space space, uint32 value) } +static uint16 +rgba32_color_to_16_bit_color(rgba32_color &color) +{ + return ((color.blue >> 3) << 11) | ((color.green >> 2) << 5) | (color.red >> 3); +} + + static int32 -find_ico_color(ico_color *palette, int32 numColors, ico_color &color) +find_rgba32_color(rgba32_color *palette, int32 numColors, rgba32_color &color) { // ToDo: sorting and binary search? for (int32 i = 0; i < numColors; i++) { @@ -183,18 +193,18 @@ find_ico_color(ico_color *palette, int32 numColors, ico_color &color) } -static inline ico_color -get_ico_color_from_bits(TranslatorBitmap &bitsHeader, uint8 *data, int32 x, int32 y) +static inline rgba32_color +get_rgba32_color_from_bits(TranslatorBitmap &bitsHeader, uint8 *data, int32 x, int32 y) { data += bitsHeader.rowBytes * y; switch (bitsHeader.colors) { case B_RGBA32: - return *(ico_color *)(data + 4 * x); + return *(rgba32_color *)(data + 4 * x); case B_RGB32: default: // stupid applications like ArtPaint use the alpha channel in B_RGB32 images... - ico_color color = *(ico_color *)(data + 4 * x); + rgba32_color color = *(rgba32_color *)(data + 4 * x); if (color.alpha >= 128) color.alpha = 255; else @@ -206,15 +216,15 @@ get_ico_color_from_bits(TranslatorBitmap &bitsHeader, uint8 *data, int32 x, int3 static int32 -fill_palette(TranslatorBitmap &bitsHeader, uint8 *data, ico_color *palette) +fill_palette(TranslatorBitmap &bitsHeader, uint8 *data, rgba32_color *palette) { int32 numColors = 0; for (int32 y = 0; y < bitsHeader.bounds.IntegerHeight() + 1; y++) { for (int32 x = 0; x < bitsHeader.bounds.IntegerWidth() + 1; x++) { - ico_color color = get_ico_color_from_bits(bitsHeader, data, x, y); + rgba32_color color = get_rgba32_color_from_bits(bitsHeader, data, x, y); - int32 index = find_ico_color(palette, numColors, color); + int32 index = find_rgba32_color(palette, numColors, color); if (index == -1) { // add this color if there is space left if (numColors == 256) @@ -255,14 +265,16 @@ has_true_alpha_channel(color_space space, uint8 *data, static status_t convert_data_to_bits(ico_dir_entry &entry, ico_bitmap_header &header, - const uint32 *palette, BPositionIO &source, + const rgba32_color *palette, BPositionIO &source, BPositionIO &target) { uint16 bitsPerPixel = header.bits_per_pixel; // round row bytes to next 4 byte boundary int32 xorRowBytes = get_bytes_per_row(entry.width, header.bits_per_pixel); - int32 andRowBytes = get_bytes_per_row(entry.width, 1); + int32 andRowBytes = 0; + if (bitsPerPixel != 32) + andRowBytes = get_bytes_per_row(entry.width, 1); int32 outRowBytes = entry.width * 4; // allocate buffers @@ -274,11 +286,14 @@ convert_data_to_bits(ico_dir_entry &entry, ico_bitmap_header &header, return B_NO_MEMORY; int32 andDataSize = andRowBytes * entry.height; - uint8 *andData = (uint8 *)andAllocator.Allocate(andDataSize); - if (andData == NULL) - return B_NO_MEMORY; + uint8 *andData = NULL; + if (bitsPerPixel != 32) { + andData = (uint8 *)andAllocator.Allocate(andDataSize); + if (andData == NULL) + return B_NO_MEMORY; + } - uint32 *outRowData = (uint32 *)rowAllocator.Allocate(outRowBytes); + rgba32_color *outRowData = (rgba32_color *)rowAllocator.Allocate(outRowBytes); if (outRowData == NULL) return B_NO_MEMORY; @@ -286,9 +301,11 @@ convert_data_to_bits(ico_dir_entry &entry, ico_bitmap_header &header, if (bytesRead != xorDataSize) return B_BAD_DATA; - bytesRead = source.Read(andData, andDataSize); - if (bytesRead != andDataSize) - return B_BAD_DATA; + if (bitsPerPixel != 32) { + bytesRead = source.Read(andData, andDataSize); + if (bytesRead != andDataSize) + return B_BAD_DATA; + } for (uint32 row = 0; row < entry.height; row++) { for (uint32 x = 0; x < entry.width; x++) { @@ -311,16 +328,37 @@ convert_data_to_bits(ico_dir_entry &entry, ico_bitmap_header &header, } outRowData[x] = palette[index]; - } else - outRowData[x] = ((uint32 *)line)[x]; + } else { + switch (bitsPerPixel) { + case 16: + { + uint16 color = ((uint16 *)line)[x]; + outRowData[x].blue = (color >> 11) << 3; + outRowData[x].green = ((color >> 5) & 0x3f) << 3; + outRowData[x].red = (color & 0x1f) << 3; + break; + } + + case 24: + outRowData[x].red = ((rgba32_color *)line)[x].red; + outRowData[x].green = ((rgba32_color *)line)[x].green; + outRowData[x].blue = ((rgba32_color *)line)[x].blue; + break; + + case 32: + outRowData[x] = ((rgba32_color *)line)[x]; + break; + } + } if (bitsPerPixel != 32) { // set alpha channel if (get_1_bit_per_pixel(get_data_row(andData, andDataSize, andRowBytes, row), x)) - outRowData[x] = B_TRANSPARENT_MAGIC_RGBA32; + outRowData[x] = kMagicTransparentColor; else - ((ico_color *)&outRowData[x])->alpha = 255; - } + outRowData[x].alpha = 255; + } else if (outRowData[x].alpha == 0) + outRowData[x] = kMagicTransparentColor; } ssize_t bytesWritten = target.Write(outRowData, outRowBytes); @@ -336,7 +374,7 @@ convert_data_to_bits(ico_dir_entry &entry, ico_bitmap_header &header, static status_t convert_bits_to_data(TranslatorBitmap &bitsHeader, uint8 *bitsData, ico_dir_entry &entry, - ico_bitmap_header &header, ico_color *palette, BPositionIO &target) + ico_bitmap_header &header, rgba32_color *palette, BPositionIO &target) { int32 bitsPerPixel = header.bits_per_pixel; @@ -361,10 +399,10 @@ convert_bits_to_data(TranslatorBitmap &bitsHeader, uint8 *bitsData, ico_dir_entr for (uint32 row = entry.height; row-- > 0;) { for (uint32 x = 0; x < entry.width; x++) { - ico_color color = get_ico_color_from_bits(bitsHeader, bitsData, x, row); + rgba32_color color = get_rgba32_color_from_bits(bitsHeader, bitsData, x, row); if (palette != NULL) { - uint8 index = find_ico_color(palette, numColors, color); + uint8 index = find_rgba32_color(palette, numColors, color); switch (bitsPerPixel) { case 1: @@ -379,7 +417,30 @@ convert_bits_to_data(TranslatorBitmap &bitsHeader, uint8 *bitsData, ico_dir_entr break; } } else { - // ToDo: true color modi + switch (bitsPerPixel) { + default: + case 16: + { + uint16 *data = (uint16 *)xorRowData; + data[x] = rgba32_color_to_16_bit_color(color); + break; + } + + case 24: + { + xorRowData[x * 3 + 0] = color.blue; + xorRowData[x * 3 + 1] = color.green; + xorRowData[x * 3 + 2] = color.red; + break; + } + + case 32: + { + rgba32_color *data = (rgba32_color *)xorRowData; + data[x] = color; + break; + } + } } } @@ -399,7 +460,7 @@ convert_bits_to_data(TranslatorBitmap &bitsHeader, uint8 *bitsData, ico_dir_entr for (uint32 row = entry.height; row-- > 0;) { for (uint32 x = 0; x < entry.width; x++) { - ico_color color = get_ico_color_from_bits(bitsHeader, bitsData, x, row); + rgba32_color color = get_rgba32_color_from_bits(bitsHeader, bitsData, x, row); bool transparent = *(uint32 *)&color == B_TRANSPARENT_MAGIC_RGBA32 || color.alpha == 0; set_1_bit_per_pixel(andRowData, x, transparent ? 1 : 0); @@ -468,6 +529,9 @@ ICO::identify(BPositionIO &stream, int32 &bitsPerPixel) } +/** Converts an ICO image of any type into a B_RGBA32 B_TRANSLATOR_BITMAP. + */ + status_t ICO::convert_ico_to_bits(BPositionIO &source, BPositionIO &target) { @@ -519,14 +583,14 @@ ICO::convert_ico_to_bits(BPositionIO &source, BPositionIO &target) if (bitmapHeader.bits_per_pixel <= 8) numColors = 1L << bitmapHeader.bits_per_pixel; - uint32 palette[256]; + rgba32_color palette[256]; if (numColors > 0) { if (source.Read(palette, numColors * 4) != numColors * 4) return B_BAD_VALUE; - // clear alpha channel + // clear alpha channel (it's not used in ICO color information) for (int32 i = 0; i < numColors; i++) - palette[i] &= 0xffffff; + palette[i].alpha = 0; } // write out Be's Bitmap header @@ -577,7 +641,7 @@ ICO::convert_bits_to_ico(BPositionIO &source, TranslatorBitmap &bitsHeader, BPos if (bytesRead < B_OK) return bytesRead; - ico_color palette[256]; + rgba32_color palette[256]; if (bitsPerPixel > 8) { // it's a non-palette mode - but does it have to be? if (bitsHeader.colors != B_RGBA32 @@ -627,7 +691,7 @@ ICO::convert_bits_to_ico(BPositionIO &source, TranslatorBitmap &bitsHeader, BPos entry.size = sizeof(ico_bitmap_header) + width * (xorRowBytes + andRowBytes); if (bitsPerPixel <= 8) - entry.size += numColors * sizeof(ico_color); + entry.size += numColors * sizeof(rgba32_color); entry.offset = sizeof(ico_header) + sizeof(ico_dir_entry); entry.reserved = 0; @@ -658,7 +722,7 @@ ICO::convert_bits_to_ico(BPositionIO &source, TranslatorBitmap &bitsHeader, BPos bitmapHeader.SwapToHost(); if (bitsPerPixel <= 8) { - bytesWritten = target.Write(palette, numColors * sizeof(ico_color)); + bytesWritten = target.Write(palette, numColors * sizeof(rgba32_color)); if (bytesWritten < B_OK) return bytesWritten; } diff --git a/src/add-ons/translators/icotranslator/ICO.h b/src/add-ons/translators/icotranslator/ICO.h index f5e17ed3c8..a4507dd5d7 100644 --- a/src/add-ons/translators/icotranslator/ICO.h +++ b/src/add-ons/translators/icotranslator/ICO.h @@ -59,14 +59,18 @@ struct ico_bitmap_header { void SwapFromHost(); } _PACKED; -struct ico_color { + +// More or less accidently, ICO colors are in the same format as +// the color information in B_RGBA32 bitmaps + +struct rgba32_color { uint8 blue; uint8 green; uint8 red; uint8 alpha; inline bool - operator==(const ico_color& other) const + operator==(const rgba32_color& other) const { return red == other.red && green == other.green && blue == other.blue; }