From 9f5078060d488bc8d3d3389ad3fc1c0e61a519c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Thu, 16 Nov 2006 04:53:24 +0000 Subject: [PATCH] * fixed a couple of remaining issues with vector icons, there is some unfortunate code duplication in AppFileInfo, because it cannot use BMimeType/BNode alone to retrieve icons, now it works closer to the code in BIconUtils, this fixes R5 icons not displaying for other icon sizes * implemented a bilinear scaling function, I don't know if it is very fast, but I hope it is reasonable. Now that I see the results though, I wonder if R5 icons should be scaled with nearest neighbor instead... * corrected a small bug in the icon format stuff... 7 bit coords are -32-+95, not 96 * improved comment for BIconUtils function git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19302 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/libs/icon/IconUtils.h | 5 +- src/kits/storage/AppFileInfo.cpp | 42 +++++---- src/libs/icon/IconUtils.cpp | 102 +++++++++++++++++++-- src/libs/icon/flat_icon/FlatIconFormat.cpp | 2 +- 4 files changed, 122 insertions(+), 29 deletions(-) diff --git a/headers/libs/icon/IconUtils.h b/headers/libs/icon/IconUtils.h index c5a2023259..8c558e497d 100644 --- a/headers/libs/icon/IconUtils.h +++ b/headers/libs/icon/IconUtils.h @@ -27,9 +27,8 @@ class BIconUtils { // has either of the provided attribute names. Which icon type // is preferred (vector, small or large B_CMAP8 icon) depends // on the colorspace of the provided bitmap. If the colorspace - // is B_CMAP8, B_CMAP8 icons are preferred. If no vector icon - // is available, the bitmap size must match the provided - // icon_size "size"! + // is B_CMAP8, B_CMAP8 icons are preferred. In that case, the + // bitmap size must also match the provided icon_size "size"! static status_t GetIcon(BNode* node, const char* vectorIconAttrName, const char* smallIconAttrName, diff --git a/src/kits/storage/AppFileInfo.cpp b/src/kits/storage/AppFileInfo.cpp index 68d2a96cf2..42589abaff 100644 --- a/src/kits/storage/AppFileInfo.cpp +++ b/src/kits/storage/AppFileInfo.cpp @@ -823,8 +823,8 @@ BAppFileInfo::SetVersionInfo(const version_info *info, version_kind kind) - other error codes */ status_t -BAppFileInfo::GetIconForType(const char *type, BBitmap *icon, - icon_size which) const +BAppFileInfo::GetIconForType(const char* type, BBitmap* icon, + icon_size size) const { if (InitCheck() != B_OK) return B_NO_INIT; @@ -857,7 +857,12 @@ BAppFileInfo::GetIconForType(const char *type, BBitmap *icon, return error; } - // no vector icon if we got this far + // no vector icon if we got this far, + // align size argument just in case + if (size < B_LARGE_ICON) + size = B_MINI_ICON; + else + size = B_LARGE_ICON; error = B_OK; // set some icon size related variables @@ -865,7 +870,7 @@ BAppFileInfo::GetIconForType(const char *type, BBitmap *icon, BRect bounds; uint32 attrType = 0; size_t attrSize = 0; - switch (which) { + switch (size) { case B_MINI_ICON: attributeString = kMiniIconAttribute; bounds.Set(0, 0, 15, 15); @@ -892,21 +897,23 @@ BAppFileInfo::GetIconForType(const char *type, BBitmap *icon, attribute = attributeString.String(); - // check parameter and initialization - if (icon->Bounds() != bounds) + // check parameters + // currently, scaling B_CMAP8 icons is not supported + if (icon->ColorSpace() == B_CMAP8 && icon->Bounds() != bounds) return B_BAD_VALUE; // read the data if (error == B_OK) { - bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); - char *buffer = NULL; + bool tempBuffer = (icon->ColorSpace() != B_CMAP8 + || icon->Bounds() != bounds); + uint8* buffer = NULL; size_t read; - if (otherColorSpace) { - // other color space than stored in attribute - buffer = new(nothrow) char[attrSize]; - if (!buffer) + if (tempBuffer) { + // other color space or bitmap size than stored in attribute + buffer = new(nothrow) uint8[attrSize]; + if (!buffer) { error = B_NO_MEMORY; - if (error == B_OK) { + } else { error = _ReadData(attribute, -1, attrType, buffer, attrSize, read); } @@ -916,11 +923,14 @@ BAppFileInfo::GetIconForType(const char *type, BBitmap *icon, } if (error == B_OK && read != attrSize) error = B_ERROR; - if (otherColorSpace) { + if (tempBuffer) { // other color space than stored in attribute if (error == B_OK) { - error = icon->ImportBits(buffer, attrSize, B_ANY_BYTES_PER_ROW, - 0, B_CMAP8); + error = BIconUtils::ConvertFromCMAP8(buffer, + (uint32)size, + (uint32)size, + (uint32)size, + icon); } delete[] buffer; } diff --git a/src/libs/icon/IconUtils.cpp b/src/libs/icon/IconUtils.cpp index 6615ed27dd..dad42cea48 100644 --- a/src/libs/icon/IconUtils.cpp +++ b/src/libs/icon/IconUtils.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -55,6 +56,13 @@ BIconUtils::GetIcon(BNode* node, if (ret < B_OK) { // try to fallback to B_CMAP8 icons // (converting to B_RGBA32 is handled) + + // override size + if (result->Bounds().IntegerWidth() + 1 >= 32) + size = B_LARGE_ICON; + else + size = B_MINI_ICON; + ret = GetCMAP8Icon(node, smallIconAttrName, largeIconAttrName, @@ -123,7 +131,9 @@ bigtime_t startTime = system_time(); return B_BAD_VALUE; uint8 buffer[attrInfo.size]; - node->ReadAttr(attrName, attrType, 0, buffer, attrInfo.size); + ssize_t read = node->ReadAttr(attrName, attrType, 0, buffer, attrInfo.size); + if (read != attrInfo.size) + return B_ERROR; #if TIME_VECTOR_ICONS bigtime_t importTime = system_time(); @@ -242,6 +252,11 @@ BIconUtils::GetCMAP8Icon(BNode* node, if (ret == B_OK && attrInfo.size != attrSize) ret = B_BAD_DATA; + // check parameters + // currently, scaling B_CMAP8 icons is not supported + if (icon->ColorSpace() == B_CMAP8 && icon->Bounds() != bounds) + return B_BAD_VALUE; + // read the attribute if (ret == B_OK) { bool tempBuffer = (icon->ColorSpace() != B_CMAP8 @@ -249,11 +264,11 @@ BIconUtils::GetCMAP8Icon(BNode* node, uint8* buffer = NULL; ssize_t read; if (tempBuffer) { - // other color space than stored in attribute + // other color space or bitmap size than stored in attribute buffer = new(nothrow) uint8[attrSize]; - if (!buffer) + if (!buffer) { ret = B_NO_MEMORY; - if (ret == B_OK) { + } else { read = node->ReadAttr(attribute, attrType, 0, buffer, attrSize); } @@ -264,7 +279,7 @@ BIconUtils::GetCMAP8Icon(BNode* node, if (ret == B_OK) { if (read < 0) ret = read; - else if (read != attrInfo.size) + else if (read != (ssize_t)attrSize) ret = B_ERROR; } if (tempBuffer) { @@ -304,6 +319,73 @@ BIconUtils::ConvertFromCMAP8(BBitmap* source, BBitmap* result) return ConvertFromCMAP8(src, width, height, srcBPR, result); } +// scale_bilinear +static void +scale_bilinear(uint8* bits, int32 srcWidth, int32 srcHeight, + int32 dstWidth, int32 dstHeight, uint32 bpr) +{ + // first pass: scale bottom to top + + uint8* dst = bits + (dstHeight - 1) * bpr; + // offset to bottom left pixel in target size + for (int32 x = 0; x < srcWidth; x++) { + uint8* d = dst; + for (int32 y = dstHeight - 1; y >= 0; y--) { + int32 lineF = y * 256 * srcHeight / (dstHeight - 1); + int32 lineI = lineF >> 8; + uint8 weight = (uint8)(lineF & 0xff); + uint8* s1 = bits + lineI * bpr + 4 * x; + if (weight == 0) { + d[0] = s1[0]; + d[1] = s1[1]; + d[2] = s1[2]; + d[3] = s1[3]; + } else { + uint8* s2 = s1 + bpr; + + d[0] = (((s2[0] - s1[0]) * weight) + (s1[0] << 8)) >> 8; + d[1] = (((s2[1] - s1[1]) * weight) + (s1[1] << 8)) >> 8; + d[2] = (((s2[2] - s1[2]) * weight) + (s1[2] << 8)) >> 8; + d[3] = (((s2[3] - s1[3]) * weight) + (s1[3] << 8)) >> 8; + } + + d -= bpr; + } + dst += 4; + } + + // second pass: scale right to left + + dst = bits + (dstWidth - 1) * 4; + // offset to top left pixel in target size + for (int32 y = 0; y < dstWidth; y++) { + uint8* d = dst; + for (int32 x = dstWidth - 1; x >= 0; x--) { + int32 columnF = x * 256 * srcWidth / (dstWidth - 1); + int32 columnI = columnF >> 8; + uint8 weight = (uint8)(columnF & 0xff); + uint8* s1 = bits + y * bpr + 4 * columnI; + if (weight == 0) { + d[0] = s1[0]; + d[1] = s1[1]; + d[2] = s1[2]; + d[3] = s1[3]; + } else { + uint8* s2 = s1 + 4; + + d[0] = (((s2[0] - s1[0]) * weight) + (s1[0] << 8)) >> 8; + d[1] = (((s2[1] - s1[1]) * weight) + (s1[1] << 8)) >> 8; + d[2] = (((s2[2] - s1[2]) * weight) + (s1[2] << 8)) >> 8; + d[3] = (((s2[3] - s1[3]) * weight) + (s1[3] << 8)) >> 8; + } + + d -= 4; + } + dst += bpr; + } +} + + // ConvertFromCMAP8 status_t BIconUtils::ConvertFromCMAP8(const uint8* src, @@ -323,10 +405,6 @@ BIconUtils::ConvertFromCMAP8(const uint8* src, if (dstWidth < width || dstHeight < height) { // TODO: down scaling return B_ERROR; - } else if (dstWidth > width || dstHeight > height) { - // TODO: up scaling - // (currently copies bitmap into result at left-top) -memset(result->Bits(), 255, result->BitsLength()); } //#if __HAIKU__ @@ -361,6 +439,12 @@ memset(result->Bits(), 255, result->BitsLength()); dst += dstBPR; } + if (dstWidth > width || dstHeight > height) { + // up scaling + scale_bilinear((uint8*)result->Bits(), width, height, + dstWidth, dstHeight, dstBPR); + } + return B_OK; //#endif // __HAIKU__ diff --git a/src/libs/icon/flat_icon/FlatIconFormat.cpp b/src/libs/icon/flat_icon/FlatIconFormat.cpp index 9b4fe77c7e..519e295ab9 100644 --- a/src/libs/icon/flat_icon/FlatIconFormat.cpp +++ b/src/libs/icon/flat_icon/FlatIconFormat.cpp @@ -49,7 +49,7 @@ write_coord(LittleEndianBuffer& buffer, float coord) coord = 192.0; if (int(coord * 100.0) == (int)coord * 100 - && coord >= - 32.0 && coord <= 96.0) { + && coord >= - 32.0 && coord <= 95.0) { // saving coord in 7 bit is sufficient uint8 value = (uint8)(coord + 32.0); return buffer.Write(value);