Update bitmap downscaling for BeOS icons.
Implemented a simple down sampling algorithm in the scale_down() function. For non-integer scaling first scale up using the scale2x, scale3x, or scale4x algorithm doubling, tripling, or quadrupling the icon then use the downscaling algorithm to shrink to the desired size. This produces nicer looking results than bilinear scaling alone. Note that this only applies to bitmap-based BeOS icons and not vector-based HVIF icons.
This commit is contained in:
parent
f3ac8bc089
commit
b09c265cb4
@ -1,11 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2006-2011, Haiku. All rights reserved.
|
* Copyright 2006-2013, Haiku. All rights reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Stephan Aßmus <superstippi@gmx.de>
|
* Stephan Aßmus, superstippi@gmx.de
|
||||||
* Ingo Weinhold <bonefish@cs.tu-berlin.de>
|
* Axel Dörfler, axeld@pinc-software.de
|
||||||
* John Scipione <jscipione@gmail.com>
|
* John Scipione, jscipione@gmail.com
|
||||||
|
* Ingo Weinhold, bonefish@cs.tu-berlin.de
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -101,6 +102,70 @@ scale_bilinear(uint8* bits, int32 srcWidth, int32 srcHeight, int32 dstWidth,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
scale_down(const uint8* srcBits, uint8* dstBits, int32 srcWidth, int32 srcHeight,
|
||||||
|
int32 dstWidth, int32 dstHeight)
|
||||||
|
{
|
||||||
|
int32 l;
|
||||||
|
int32 c;
|
||||||
|
float t;
|
||||||
|
float u;
|
||||||
|
float tmp;
|
||||||
|
float d1, d2, d3, d4;
|
||||||
|
// coefficients
|
||||||
|
uint32 p1, p2, p3, p4;
|
||||||
|
// nearby pixels
|
||||||
|
uint8 red, green, blue, alpha;
|
||||||
|
// color components
|
||||||
|
|
||||||
|
for (int32 i = 0; i < dstHeight; i++) {
|
||||||
|
for (int32 j = 0; j < dstWidth; j++) {
|
||||||
|
tmp = (float)(i) / (float)(dstHeight - 1) * (srcHeight - 1);
|
||||||
|
l = (int32)floorf(tmp);
|
||||||
|
if (l < 0)
|
||||||
|
l = 0;
|
||||||
|
else if (l >= srcHeight - 1)
|
||||||
|
l = srcHeight - 2;
|
||||||
|
u = tmp - l;
|
||||||
|
|
||||||
|
tmp = (float)(j) / (float)(dstWidth - 1) * (srcWidth - 1);
|
||||||
|
c = (int32)floorf(tmp);
|
||||||
|
if (c < 0)
|
||||||
|
c = 0;
|
||||||
|
else if (c >= srcWidth - 1)
|
||||||
|
c = srcWidth - 2;
|
||||||
|
t = tmp - c;
|
||||||
|
|
||||||
|
// coefficients
|
||||||
|
d1 = (1 - t) * (1 - u);
|
||||||
|
d2 = t * (1 - u);
|
||||||
|
d3 = t * u;
|
||||||
|
d4 = (1 - t) * u;
|
||||||
|
|
||||||
|
// nearby pixels
|
||||||
|
p1 = *((uint32*)srcBits + (l * srcWidth) + c);
|
||||||
|
p2 = *((uint32*)srcBits + (l * srcWidth) + c + 1);
|
||||||
|
p3 = *((uint32*)srcBits + ((l + 1)* srcWidth) + c + 1);
|
||||||
|
p4 = *((uint32*)srcBits + ((l + 1)* srcWidth) + c);
|
||||||
|
|
||||||
|
// color components
|
||||||
|
blue = (uint8)p1 * d1 + (uint8)p2 * d2 + (uint8)p3 * d3
|
||||||
|
+ (uint8)p4 * d4;
|
||||||
|
green = (uint8)(p1 >> 8) * d1 + (uint8)(p2 >> 8) * d2
|
||||||
|
+ (uint8)(p3 >> 8) * d3 + (uint8)(p4 >> 8) * d4;
|
||||||
|
red = (uint8)(p1 >> 16) * d1 + (uint8)(p2 >> 16) * d2
|
||||||
|
+ (uint8)(p3 >> 16) * d3 + (uint8)(p4 >> 16) * d4;
|
||||||
|
alpha = (uint8)(p1 >> 24) * d1 + (uint8)(p2 >> 24) * d2
|
||||||
|
+ (uint8)(p3 >> 24) * d3 + (uint8)(p4 >> 24) * d4;
|
||||||
|
|
||||||
|
// destination RGBA pixel
|
||||||
|
*((uint32*)dstBits + (i * dstWidth) + j)
|
||||||
|
= (alpha << 24) | (red << 16) | (green << 8) | (blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
scale2x(const uint8* srcBits, uint8* dstBits, int32 srcWidth, int32 srcHeight,
|
scale2x(const uint8* srcBits, uint8* dstBits, int32 srcWidth, int32 srcHeight,
|
||||||
int32 srcBPR, int32 dstBPR)
|
int32 srcBPR, int32 dstBPR)
|
||||||
@ -584,6 +649,39 @@ BIconUtils::ConvertFromCMAP8(const uint8* src, uint32 width, uint32 height,
|
|||||||
uint8* dst = (uint8*)result->Bits();
|
uint8* dst = (uint8*)result->Bits();
|
||||||
uint32 dstBPR = result->BytesPerRow();
|
uint32 dstBPR = result->BytesPerRow();
|
||||||
|
|
||||||
|
// check for integer multiple scale
|
||||||
|
if (dstWidth == 2 * width && dstHeight == 2 * height) {
|
||||||
|
// scale2x
|
||||||
|
BBitmap* converted = new BBitmap(BRect(0, 0, width - 1, height - 1),
|
||||||
|
result->ColorSpace());
|
||||||
|
converted->ImportBits(src, height * srcBPR, srcBPR, 0, B_CMAP8);
|
||||||
|
uint8* convertedBits = (uint8*)converted->Bits();
|
||||||
|
int32 convertedBPR = converted->BytesPerRow();
|
||||||
|
scale2x(convertedBits, dst, width, height, convertedBPR, dstBPR);
|
||||||
|
delete converted;
|
||||||
|
return B_OK;
|
||||||
|
} else if (dstWidth == 3 * width && dstHeight == 3 * height) {
|
||||||
|
// scale3x
|
||||||
|
BBitmap* converted = new BBitmap(BRect(0, 0, width - 1, height - 1),
|
||||||
|
result->ColorSpace());
|
||||||
|
converted->ImportBits(src, height * srcBPR, srcBPR, 0, B_CMAP8);
|
||||||
|
uint8* convertedBits = (uint8*)converted->Bits();
|
||||||
|
int32 convertedBPR = converted->BytesPerRow();
|
||||||
|
scale3x(convertedBits, dst, width, height, convertedBPR, dstBPR);
|
||||||
|
delete converted;
|
||||||
|
return B_OK;
|
||||||
|
} else if (dstWidth == 4 * width && dstHeight == 4 * height) {
|
||||||
|
// scale4x
|
||||||
|
BBitmap* converted = new BBitmap(BRect(0, 0, width - 1, height - 1),
|
||||||
|
result->ColorSpace());
|
||||||
|
converted->ImportBits(src, height * srcBPR, srcBPR, 0, B_CMAP8);
|
||||||
|
uint8* convertedBits = (uint8*)converted->Bits();
|
||||||
|
int32 convertedBPR = converted->BytesPerRow();
|
||||||
|
scale4x(convertedBits, dst, width, height, convertedBPR, dstBPR);
|
||||||
|
delete converted;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
const rgb_color* colorMap = system_colors()->color_list;
|
const rgb_color* colorMap = system_colors()->color_list;
|
||||||
if (colorMap == NULL)
|
if (colorMap == NULL)
|
||||||
return B_NO_INIT;
|
return B_NO_INIT;
|
||||||
@ -591,6 +689,7 @@ BIconUtils::ConvertFromCMAP8(const uint8* src, uint32 width, uint32 height,
|
|||||||
const uint8* srcStart = src;
|
const uint8* srcStart = src;
|
||||||
uint8* dstStart = dst;
|
uint8* dstStart = dst;
|
||||||
|
|
||||||
|
// convert from B_CMAP8 to B_RGB(A)32 without scaling
|
||||||
for (uint32 y = 0; y < height; y++) {
|
for (uint32 y = 0; y < height; y++) {
|
||||||
uint32* d = (uint32*)dst;
|
uint32* d = (uint32*)dst;
|
||||||
const uint8* s = src;
|
const uint8* s = src;
|
||||||
@ -605,35 +704,45 @@ BIconUtils::ConvertFromCMAP8(const uint8* src, uint32 width, uint32 height,
|
|||||||
dst += dstBPR;
|
dst += dstBPR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (width == dstWidth && height == dstHeight)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
// reset src and dst back to their original locations
|
// reset src and dst back to their original locations
|
||||||
src = srcStart;
|
src = srcStart;
|
||||||
dst = dstStart;
|
dst = dstStart;
|
||||||
|
|
||||||
if ((dstWidth == 2 * width && dstHeight == 2 * height)
|
if (dstWidth > width && dstHeight > height
|
||||||
|| (dstWidth == 3 * width && dstHeight == 3 * height)
|
&& dstWidth < 2 * width && dstHeight < 2 * height) {
|
||||||
|| (dstWidth == 4 * width && dstHeight == 4 * height)) {
|
// scale2x then downscale
|
||||||
// we can do some special scaling here
|
BBitmap* temp = new BBitmap(BRect(0, 0, width * 2 - 1, height * 2 - 1),
|
||||||
|
result->ColorSpace());
|
||||||
// first convert to B_RGBA32
|
uint8* tempBits = (uint8*)temp->Bits();
|
||||||
BBitmap* converted
|
uint32 tempBPR = temp->BytesPerRow();
|
||||||
= new BBitmap(BRect(0, 0, width - 1, height - 1),
|
scale2x(dst, tempBits, width, height, dstBPR, tempBPR);
|
||||||
result->ColorSpace());
|
scale_down(tempBits, dst, width * 2, height * 2, dstWidth, dstHeight);
|
||||||
converted->ImportBits(src, height * srcBPR, srcBPR, 0, B_CMAP8);
|
delete temp;
|
||||||
uint8* convertedBits = (uint8*)converted->Bits();
|
} else if (dstWidth > 2 * width && dstHeight > 2 * height
|
||||||
int32 convertedBPR = converted->BytesPerRow();
|
&& dstWidth < 3 * width && dstHeight < 3 * height) {
|
||||||
|
// scale3x then downscale
|
||||||
// scale using the scale2x/scale3x/scale4x algorithm
|
BBitmap* temp = new BBitmap(BRect(0, 0, width * 3 - 1, height * 3 - 1),
|
||||||
if (dstWidth == 2 * width && dstHeight == 2 * height)
|
result->ColorSpace());
|
||||||
scale2x(convertedBits, dst, width, height, convertedBPR, dstBPR);
|
uint8* tempBits = (uint8*)temp->Bits();
|
||||||
else if (dstWidth == 3 * width && dstHeight == 3 * height)
|
uint32 tempBPR = temp->BytesPerRow();
|
||||||
scale3x(convertedBits, dst, width, height, convertedBPR, dstBPR);
|
scale3x(dst, tempBits, width, height, dstBPR, tempBPR);
|
||||||
else if (dstWidth == 4 * width && dstHeight == 4 * height)
|
scale_down(tempBits, dst, width * 3, height * 3, dstWidth, dstHeight);
|
||||||
scale4x(convertedBits, dst, width, height, convertedBPR, dstBPR);
|
delete temp;
|
||||||
|
} else if (dstWidth > 3 * width && dstHeight > 3 * height
|
||||||
// cleanup
|
&& dstWidth < 4 * width && dstHeight < 4 * height) {
|
||||||
delete converted;
|
// scale4x then downscale
|
||||||
|
BBitmap* temp = new BBitmap(BRect(0, 0, width * 4 - 1, height * 4 - 1),
|
||||||
|
result->ColorSpace());
|
||||||
|
uint8* tempBits = (uint8*)temp->Bits();
|
||||||
|
uint32 tempBPR = temp->BytesPerRow();
|
||||||
|
scale4x(dst, tempBits, width, height, dstBPR, tempBPR);
|
||||||
|
scale_down(tempBits, dst, width * 3, height * 3, dstWidth, dstHeight);
|
||||||
|
delete temp;
|
||||||
} else {
|
} else {
|
||||||
// bilinear scaling
|
// fall back to bilinear scaling
|
||||||
scale_bilinear(dst, width, height, dstWidth, dstHeight, dstBPR);
|
scale_bilinear(dst, width, height, dstWidth, dstHeight, dstBPR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user