* 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
This commit is contained in:
Stephan Aßmus 2006-11-16 04:53:24 +00:00
parent 6f095d6a03
commit 9f5078060d
4 changed files with 122 additions and 29 deletions

View File

@ -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,

View File

@ -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;
}

View File

@ -12,6 +12,7 @@
#include <new>
#include <fs_attr.h>
#include <stdio.h>
#include <string.h>
#include <Bitmap.h>
#include <Node.h>
@ -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__

View File

@ -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);