* Added ConvertToCMAP8() bitmap variant.

* Put header guards in the system namespace.
* Cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27035 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-08-18 11:40:01 +00:00
parent d9b93b821a
commit 6e006912aa
2 changed files with 137 additions and 119 deletions
+6 -4
View File
@@ -1,17 +1,17 @@
/* /*
* Copyright 2006-2008, Haiku. All rights reserved. * Copyright 2006-2008, Haiku. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*
*/ */
#ifndef _ICON_UTILS_H
#define _ICON_UTILS_H
#ifndef ICON_UTILS_H
#define ICON_UTILS_H
#include <Mime.h> #include <Mime.h>
class BBitmap; class BBitmap;
class BNode; class BNode;
// This class is a little different from many other classes. // This class is a little different from many other classes.
// You don't create an instance of it; you just call its various // You don't create an instance of it; you just call its various
// static member functions for utility-like operations. // static member functions for utility-like operations.
@@ -65,6 +65,8 @@ public:
// to make any sense). // to make any sense).
static status_t ConvertFromCMAP8(BBitmap* source, static status_t ConvertFromCMAP8(BBitmap* source,
BBitmap* result); BBitmap* result);
static status_t ConvertToCMAP8(BBitmap* source,
BBitmap* result);
static status_t ConvertFromCMAP8(const uint8* data, static status_t ConvertFromCMAP8(const uint8* data,
uint32 width, uint32 height, uint32 width, uint32 height,
@@ -75,4 +77,4 @@ public:
uint32 bytesPerRow, BBitmap* result); uint32 bytesPerRow, BBitmap* result);
}; };
#endif // ICON_UTILS_H #endif // _ICON_UTILS_H
+335 -319
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2006-2007, Haiku. All rights reserved. * Copyright 2006-2008, Haiku. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -33,315 +33,9 @@ using namespace BPrivate::Icon;
using std::nothrow; using std::nothrow;
// GetIcon
status_t
BIconUtils::GetIcon(BNode* node,
const char* vectorIconAttrName,
const char* smallIconAttrName,
const char* largeIconAttrName,
icon_size size,
BBitmap* result)
{
if (!result || result->InitCheck())
return B_BAD_VALUE;
status_t ret = B_ERROR;
switch (result->ColorSpace()) {
case B_RGBA32:
case B_RGB32:
// prefer vector icon
ret = GetVectorIcon(node, vectorIconAttrName, result);
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,
size, result);
}
break;
case B_CMAP8:
// prefer old B_CMAP8 icons
ret = GetCMAP8Icon(node,
smallIconAttrName,
largeIconAttrName,
size, result);
if (ret < B_OK) {
// try to fallback to vector icon
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
BBitmap temp(result->Bounds(),
B_BITMAP_NO_SERVER_LINK, B_RGBA32);
#else
BBitmap temp(result->Bounds(), B_RGBA32);
#endif
ret = temp.InitCheck();
if (ret < B_OK)
break;
ret = GetVectorIcon(node, vectorIconAttrName, &temp);
if (ret < B_OK)
break;
uint32 width = temp.Bounds().IntegerWidth() + 1;
uint32 height = temp.Bounds().IntegerHeight() + 1;
uint32 bytesPerRow = temp.BytesPerRow();
ret = ConvertToCMAP8((uint8*)temp.Bits(),
width, height, bytesPerRow, result);
}
break;
default:
printf("BIconUtils::GetIcon() - unsupported colorspace\n");
break;
}
return ret;
}
// #pragma mark -
// GetVectorIcon
status_t
BIconUtils::GetVectorIcon(BNode* node, const char* attrName,
BBitmap* result)
{
if (!node || node->InitCheck() < B_OK || !attrName)
return B_BAD_VALUE;
#if TIME_VECTOR_ICONS
bigtime_t startTime = system_time();
#endif
// get the attribute info and check type and size of the attr contents
attr_info attrInfo;
status_t ret = node->GetAttrInfo(attrName, &attrInfo);
if (ret < B_OK)
return ret;
type_code attrType = B_VECTOR_ICON_TYPE;
if (attrInfo.type != attrType)
return B_BAD_TYPE;
// chicken out on unrealisticly large attributes
if (attrInfo.size > 16 * 1024)
return B_BAD_VALUE;
uint8 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();
#endif
ret = GetVectorIcon(buffer, attrInfo.size, result);
if (ret < B_OK)
return ret;
#if TIME_VECTOR_ICONS
bigtime_t finishTime = system_time();
printf("read: %lld, import: %lld\n", importTime - startTime, finishTime - importTime);
#endif
return B_OK;
}
// GetVectorIcon
status_t
BIconUtils::GetVectorIcon(const uint8* buffer, size_t size,
BBitmap* result)
{
if (!result)
return B_BAD_VALUE;
status_t ret = result->InitCheck();
if (ret < B_OK)
return ret;
BBitmap* temp = result;
ObjectDeleter<BBitmap> deleter;
if (result->ColorSpace() != B_RGBA32 && result->ColorSpace() != B_RGB32) {
temp = new (nothrow) BBitmap(result->Bounds(),
B_BITMAP_NO_SERVER_LINK, B_RGBA32);
deleter.SetTo(temp);
if (!temp || temp->InitCheck() != B_OK)
return B_NO_MEMORY;
}
Icon icon;
ret = icon.InitCheck();
if (ret < B_OK)
return ret;
FlatIconImporter importer;
ret = importer.Import(&icon, const_cast<uint8*>(buffer), size);
if (ret < B_OK)
return ret;
IconRenderer renderer(temp);
renderer.SetIcon(&icon);
renderer.SetScale((temp->Bounds().Width() + 1.0) / 64.0);
renderer.Render();
if (temp != result) {
uint8* src = (uint8*)temp->Bits();
uint32 width = temp->Bounds().IntegerWidth() + 1;
uint32 height = temp->Bounds().IntegerHeight() + 1;
uint32 srcBPR = temp->BytesPerRow();
ret = ConvertToCMAP8(src, width, height, srcBPR, result);
}
// TODO: would be nice to get rid of this
// (B_RGBA32_PREMULTIPLIED or better yet, new blending_mode)
// NOTE: probably not necessary only because
// transparent colors are "black" in all existing icons
// lighter transparent colors should be too dark if
// app_server uses correct blending
// renderer.Demultiply();
return ret;
}
// #pragma mark -
status_t
BIconUtils::GetCMAP8Icon(BNode* node,
const char* smallIconAttrName,
const char* largeIconAttrName,
icon_size size,
BBitmap* icon)
{
// check parameters and initialization
if (!icon || icon->InitCheck() != B_OK
|| !node || node->InitCheck() != B_OK
|| !smallIconAttrName || !largeIconAttrName)
return B_BAD_VALUE;
status_t ret = B_OK;
// NOTE: this might be changed if other icon
// sizes are supported in B_CMAP8 attributes,
// but this is currently not the case, so we
// relax the requirement to pass an icon
// of just the right size
if (size < B_LARGE_ICON)
size = B_MINI_ICON;
else
size = B_LARGE_ICON;
// set some icon size related variables
const char *attribute = NULL;
BRect bounds;
uint32 attrType = 0;
size_t attrSize = 0;
switch (size) {
case B_MINI_ICON:
attribute = smallIconAttrName;
bounds.Set(0, 0, 15, 15);
attrType = B_MINI_ICON_TYPE;
attrSize = 16 * 16;
break;
case B_LARGE_ICON:
attribute = largeIconAttrName;
bounds.Set(0, 0, 31, 31);
attrType = B_LARGE_ICON_TYPE;
attrSize = 32 * 32;
break;
default:
// can not happen, see above
ret = B_BAD_VALUE;
break;
}
// get the attribute info and check type and size of the attr contents
attr_info attrInfo;
if (ret == B_OK)
ret = node->GetAttrInfo(attribute, &attrInfo);
if (ret == B_OK && attrInfo.type != attrType)
ret = B_BAD_TYPE;
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
|| icon->Bounds() != bounds);
uint8* buffer = NULL;
ssize_t read;
if (tempBuffer) {
// other color space or bitmap size than stored in attribute
buffer = new(nothrow) uint8[attrSize];
if (!buffer) {
ret = B_NO_MEMORY;
} else {
read = node->ReadAttr(attribute, attrType, 0, buffer,
attrSize);
}
} else {
read = node->ReadAttr(attribute, attrType, 0, icon->Bits(),
attrSize);
}
if (ret == B_OK) {
if (read < 0)
ret = read;
else if (read != (ssize_t)attrSize)
ret = B_ERROR;
}
if (tempBuffer) {
// other color space than stored in attribute
if (ret == B_OK) {
ret = ConvertFromCMAP8(buffer,
(uint32)size, (uint32)size,
(uint32)size, icon);
}
delete[] buffer;
}
}
return ret;
}
// #pragma mark -
// ConvertFromCMAP8
status_t
BIconUtils::ConvertFromCMAP8(BBitmap* source, BBitmap* result)
{
if (!source)
return B_BAD_VALUE;
status_t ret = source->InitCheck();
if (ret < B_OK)
return ret;
if (source->ColorSpace() != B_CMAP8)
return B_BAD_VALUE;
uint8* src = (uint8*)source->Bits();
uint32 srcBPR = source->BytesPerRow();
uint32 width = source->Bounds().IntegerWidth() + 1;
uint32 height = source->Bounds().IntegerHeight() + 1;
return ConvertFromCMAP8(src, width, height, srcBPR, result);
}
// scale_bilinear
static void static void
scale_bilinear(uint8* bits, int32 srcWidth, int32 srcHeight, scale_bilinear(uint8* bits, int32 srcWidth, int32 srcHeight, int32 dstWidth,
int32 dstWidth, int32 dstHeight, uint32 bpr) int32 dstHeight, uint32 bpr)
{ {
// first pass: scale bottom to top // first pass: scale bottom to top
@@ -405,11 +99,332 @@ scale_bilinear(uint8* bits, int32 srcWidth, int32 srcHeight,
} }
// ConvertFromCMAP8 // #pragma mark -
status_t status_t
BIconUtils::ConvertFromCMAP8(const uint8* src, BIconUtils::GetIcon(BNode* node, const char* vectorIconAttrName,
uint32 width, uint32 height, uint32 srcBPR, const char* smallIconAttrName, const char* largeIconAttrName,
BBitmap* result) icon_size size, BBitmap* result)
{
if (!result || result->InitCheck())
return B_BAD_VALUE;
status_t ret = B_ERROR;
switch (result->ColorSpace()) {
case B_RGBA32:
case B_RGB32:
// prefer vector icon
ret = GetVectorIcon(node, vectorIconAttrName, result);
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,
size, result);
}
break;
case B_CMAP8:
// prefer old B_CMAP8 icons
ret = GetCMAP8Icon(node, smallIconAttrName, largeIconAttrName,
size, result);
if (ret < B_OK) {
// try to fallback to vector icon
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
BBitmap temp(result->Bounds(), B_BITMAP_NO_SERVER_LINK,
B_RGBA32);
#else
BBitmap temp(result->Bounds(), B_RGBA32);
#endif
ret = temp.InitCheck();
if (ret < B_OK)
break;
ret = GetVectorIcon(node, vectorIconAttrName, &temp);
if (ret < B_OK)
break;
uint32 width = temp.Bounds().IntegerWidth() + 1;
uint32 height = temp.Bounds().IntegerHeight() + 1;
uint32 bytesPerRow = temp.BytesPerRow();
ret = ConvertToCMAP8((uint8*)temp.Bits(), width, height,
bytesPerRow, result);
}
break;
default:
printf("BIconUtils::GetIcon() - unsupported colorspace\n");
break;
}
return ret;
}
// #pragma mark -
status_t
BIconUtils::GetVectorIcon(BNode* node, const char* attrName, BBitmap* result)
{
if (!node || node->InitCheck() < B_OK || !attrName)
return B_BAD_VALUE;
#if TIME_VECTOR_ICONS
bigtime_t startTime = system_time();
#endif
// get the attribute info and check type and size of the attr contents
attr_info attrInfo;
status_t ret = node->GetAttrInfo(attrName, &attrInfo);
if (ret < B_OK)
return ret;
type_code attrType = B_VECTOR_ICON_TYPE;
if (attrInfo.type != attrType)
return B_BAD_TYPE;
// chicken out on unrealisticly large attributes
if (attrInfo.size > 16 * 1024)
return B_BAD_VALUE;
uint8 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();
#endif
ret = GetVectorIcon(buffer, attrInfo.size, result);
if (ret < B_OK)
return ret;
#if TIME_VECTOR_ICONS
bigtime_t finishTime = system_time();
printf("read: %lld, import: %lld\n", importTime - startTime, finishTime - importTime);
#endif
return B_OK;
}
status_t
BIconUtils::GetVectorIcon(const uint8* buffer, size_t size, BBitmap* result)
{
if (!result)
return B_BAD_VALUE;
status_t ret = result->InitCheck();
if (ret < B_OK)
return ret;
BBitmap* temp = result;
ObjectDeleter<BBitmap> deleter;
if (result->ColorSpace() != B_RGBA32 && result->ColorSpace() != B_RGB32) {
temp = new (nothrow) BBitmap(result->Bounds(),
B_BITMAP_NO_SERVER_LINK, B_RGBA32);
deleter.SetTo(temp);
if (!temp || temp->InitCheck() != B_OK)
return B_NO_MEMORY;
}
Icon icon;
ret = icon.InitCheck();
if (ret < B_OK)
return ret;
FlatIconImporter importer;
ret = importer.Import(&icon, const_cast<uint8*>(buffer), size);
if (ret < B_OK)
return ret;
IconRenderer renderer(temp);
renderer.SetIcon(&icon);
renderer.SetScale((temp->Bounds().Width() + 1.0) / 64.0);
renderer.Render();
if (temp != result) {
uint8* src = (uint8*)temp->Bits();
uint32 width = temp->Bounds().IntegerWidth() + 1;
uint32 height = temp->Bounds().IntegerHeight() + 1;
uint32 srcBPR = temp->BytesPerRow();
ret = ConvertToCMAP8(src, width, height, srcBPR, result);
}
// TODO: would be nice to get rid of this
// (B_RGBA32_PREMULTIPLIED or better yet, new blending_mode)
// NOTE: probably not necessary only because
// transparent colors are "black" in all existing icons
// lighter transparent colors should be too dark if
// app_server uses correct blending
// renderer.Demultiply();
return ret;
}
// #pragma mark -
status_t
BIconUtils::GetCMAP8Icon(BNode* node, const char* smallIconAttrName,
const char* largeIconAttrName, icon_size size, BBitmap* icon)
{
// check parameters and initialization
if (!icon || icon->InitCheck() != B_OK
|| !node || node->InitCheck() != B_OK
|| !smallIconAttrName || !largeIconAttrName)
return B_BAD_VALUE;
status_t ret = B_OK;
// NOTE: this might be changed if other icon
// sizes are supported in B_CMAP8 attributes,
// but this is currently not the case, so we
// relax the requirement to pass an icon
// of just the right size
if (size < B_LARGE_ICON)
size = B_MINI_ICON;
else
size = B_LARGE_ICON;
// set some icon size related variables
const char *attribute = NULL;
BRect bounds;
uint32 attrType = 0;
size_t attrSize = 0;
switch (size) {
case B_MINI_ICON:
attribute = smallIconAttrName;
bounds.Set(0, 0, 15, 15);
attrType = B_MINI_ICON_TYPE;
attrSize = 16 * 16;
break;
case B_LARGE_ICON:
attribute = largeIconAttrName;
bounds.Set(0, 0, 31, 31);
attrType = B_LARGE_ICON_TYPE;
attrSize = 32 * 32;
break;
default:
// can not happen, see above
ret = B_BAD_VALUE;
break;
}
// get the attribute info and check type and size of the attr contents
attr_info attrInfo;
if (ret == B_OK)
ret = node->GetAttrInfo(attribute, &attrInfo);
if (ret == B_OK && attrInfo.type != attrType)
ret = B_BAD_TYPE;
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
|| icon->Bounds() != bounds);
uint8* buffer = NULL;
ssize_t read;
if (tempBuffer) {
// other color space or bitmap size than stored in attribute
buffer = new(nothrow) uint8[attrSize];
if (!buffer) {
ret = B_NO_MEMORY;
} else {
read = node->ReadAttr(attribute, attrType, 0, buffer, attrSize);
}
} else {
read = node->ReadAttr(attribute, attrType, 0, icon->Bits(),
attrSize);
}
if (ret == B_OK) {
if (read < 0)
ret = read;
else if (read != (ssize_t)attrSize)
ret = B_ERROR;
}
if (tempBuffer) {
// other color space than stored in attribute
if (ret == B_OK) {
ret = ConvertFromCMAP8(buffer, (uint32)size, (uint32)size,
(uint32)size, icon);
}
delete[] buffer;
}
}
return ret;
}
// #pragma mark -
status_t
BIconUtils::ConvertFromCMAP8(BBitmap* source, BBitmap* result)
{
if (source == NULL || source->ColorSpace() != B_CMAP8)
return B_BAD_VALUE;
status_t status = source->InitCheck();
if (status < B_OK)
return status;
status = result->InitCheck();
if (status < B_OK)
return status;
uint8* src = (uint8*)source->Bits();
uint32 srcBPR = source->BytesPerRow();
uint32 width = source->Bounds().IntegerWidth() + 1;
uint32 height = source->Bounds().IntegerHeight() + 1;
return ConvertFromCMAP8(src, width, height, srcBPR, result);
}
status_t
BIconUtils::ConvertToCMAP8(BBitmap* source, BBitmap* result)
{
if (source == NULL || source->ColorSpace() != B_RGBA32
|| result->ColorSpace() != B_CMAP8)
return B_BAD_VALUE;
status_t status = source->InitCheck();
if (status < B_OK)
return status;
status = result->InitCheck();
if (status < B_OK)
return status;
uint8* src = (uint8*)source->Bits();
uint32 srcBPR = source->BytesPerRow();
uint32 width = source->Bounds().IntegerWidth() + 1;
uint32 height = source->Bounds().IntegerHeight() + 1;
return ConvertToCMAP8(src, width, height, srcBPR, result);
}
status_t
BIconUtils::ConvertFromCMAP8(const uint8* src, uint32 width, uint32 height,
uint32 srcBPR, BBitmap* result)
{ {
if (!src || !result || srcBPR == 0) if (!src || !result || srcBPR == 0)
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -460,8 +475,8 @@ BIconUtils::ConvertFromCMAP8(const uint8* src,
if (dstWidth > width || dstHeight > height) { if (dstWidth > width || dstHeight > height) {
// up scaling // up scaling
scale_bilinear((uint8*)result->Bits(), width, height, scale_bilinear((uint8*)result->Bits(), width, height, dstWidth,
dstWidth, dstHeight, dstBPR); dstHeight, dstBPR);
} }
return B_OK; return B_OK;
@@ -469,11 +484,10 @@ BIconUtils::ConvertFromCMAP8(const uint8* src,
//#endif // __HAIKU__ //#endif // __HAIKU__
} }
// ConvertToCMAP8
status_t status_t
BIconUtils::ConvertToCMAP8(const uint8* src, BIconUtils::ConvertToCMAP8(const uint8* src, uint32 width, uint32 height,
uint32 width, uint32 height, uint32 srcBPR, uint32 srcBPR, BBitmap* result)
BBitmap* result)
{ {
if (!src || !result || srcBPR == 0) if (!src || !result || srcBPR == 0)
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -534,8 +548,10 @@ memset(result->Bits(), 255, result->BitsLength());
//#endif // __HAIKU__ //#endif // __HAIKU__
} }
// #pragma mark - forbidden // #pragma mark - forbidden
BIconUtils::BIconUtils() {} BIconUtils::BIconUtils() {}
BIconUtils::~BIconUtils() {} BIconUtils::~BIconUtils() {}
BIconUtils::BIconUtils(const BIconUtils&) {} BIconUtils::BIconUtils(const BIconUtils&) {}