Alien-FreeImage
view release on metacpan or search on metacpan
src/Source/FreeImageToolkit/Resize.cpp view on Meta::CPAN
// calculate weights
const double weight = dFScale * pFilter->Filter(dFScale * ((double)iSrc + 0.5 - dCenter));
// assert((iSrc-iLeft) < m_WindowSize);
m_WeightTable[u].Weights[iSrc-iLeft] = weight;
dTotalWeight += weight;
}
if((dTotalWeight > 0) && (dTotalWeight != 1)) {
// normalize weight of neighbouring points
for(int iSrc = iLeft; iSrc < iRight; iSrc++) {
// normalize point
m_WeightTable[u].Weights[iSrc-iLeft] /= dTotalWeight;
}
}
// simplify the filter, discarding null weights at the right
{
int iTrailing = iRight - iLeft - 1;
while(m_WeightTable[u].Weights[iTrailing] == 0) {
m_WeightTable[u].Right--;
iTrailing--;
if(m_WeightTable[u].Right == m_WeightTable[u].Left) {
break;
}
}
}
} // next dst pixel
}
CWeightsTable::~CWeightsTable() {
for(unsigned u = 0; u < m_LineLength; u++) {
// free contributions for every pixel
free(m_WeightTable[u].Weights);
}
// free list of pixels contributions
free(m_WeightTable);
}
// --------------------------------------------------------------------------
FIBITMAP* CResizeEngine::scale(FIBITMAP *src, unsigned dst_width, unsigned dst_height, unsigned src_left, unsigned src_top, unsigned src_width, unsigned src_height, unsigned flags) {
const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src);
const unsigned src_bpp = FreeImage_GetBPP(src);
// determine the image's color type
BOOL bIsGreyscale = FALSE;
FREE_IMAGE_COLOR_TYPE color_type;
if (src_bpp <= 8) {
color_type = GetExtendedColorType(src, &bIsGreyscale);
} else {
color_type = FIC_RGB;
}
// determine the required bit depth of the destination image
unsigned dst_bpp;
unsigned dst_bpp_s1 = 0;
if (color_type == FIC_PALETTE && !bIsGreyscale) {
// non greyscale FIC_PALETTE images require a high-color destination
// image (24- or 32-bits depending on the image's transparent state)
dst_bpp = FreeImage_IsTransparent(src) ? 32 : 24;
} else if (src_bpp <= 8) {
// greyscale images require an 8-bit destination image
// (or a 32-bit image if the image is transparent);
// however, if flag FI_RESCALE_TRUE_COLOR is set, we will return
// a true color (24 bpp) image
if (FreeImage_IsTransparent(src)) {
dst_bpp = 32;
// additionally, for transparent images we always need a
// palette including transparency information (an RGBA palette)
// so, set color_type accordingly
color_type = FIC_PALETTE;
} else {
dst_bpp = ((flags & FI_RESCALE_TRUE_COLOR) == FI_RESCALE_TRUE_COLOR) ? 24 : 8;
// in any case, we use a fast 8-bit temporary image for the
// first filter operation (stage 1, either horizontal or
// vertical) and implicitly convert to 24 bpp (if requested
// by flag FI_RESCALE_TRUE_COLOR) during the second filter
// operation
dst_bpp_s1 = 8;
}
} else if (src_bpp == 16 && image_type == FIT_BITMAP) {
// 16-bit 555 and 565 RGB images require a high-color destination
// image (fixed to 24 bits, since 16-bit RGBs don't support
// transparency in FreeImage)
dst_bpp = 24;
} else {
// bit depth remains unchanged for all other images
dst_bpp = src_bpp;
}
// make 'stage 1' bpp a copy of the destination bpp if it
// was not explicitly set
if (dst_bpp_s1 == 0) {
dst_bpp_s1 = dst_bpp;
}
// early exit if destination size is equal to source size
if ((src_width == dst_width) && (src_height == dst_height)) {
FIBITMAP *out = src;
FIBITMAP *tmp = src;
if ((src_width != FreeImage_GetWidth(src)) || (src_height != FreeImage_GetHeight(src))) {
out = FreeImage_Copy(tmp, src_left, src_top, src_left + src_width, src_top + src_height);
tmp = out;
}
if (src_bpp != dst_bpp) {
switch (dst_bpp) {
case 8:
out = FreeImage_ConvertToGreyscale(tmp);
break;
case 24:
out = FreeImage_ConvertTo24Bits(tmp);
break;
case 32:
out = FreeImage_ConvertTo32Bits(tmp);
break;
default:
break;
}
if (tmp != src) {
FreeImage_Unload(tmp);
tmp = NULL;
}
}
return (out != src) ? out : FreeImage_Clone(src);
}
RGBQUAD pal_buffer[256];
RGBQUAD *src_pal = NULL;
// provide the source image's palette to the rescaler for
// FIC_PALETTE type images (this includes palletized greyscale
// images with an unordered palette as well as transparent images)
if (color_type == FIC_PALETTE) {
if (dst_bpp == 32) {
// a 32-bit destination image signals transparency, so
// create an RGBA palette from the source palette
src_pal = GetRGBAPalette(src, pal_buffer);
} else {
src_pal = FreeImage_GetPalette(src);
}
}
// allocate the dst image
FIBITMAP *dst = FreeImage_AllocateT(image_type, dst_width, dst_height, dst_bpp, 0, 0, 0);
if (!dst) {
return NULL;
}
if (dst_bpp == 8) {
RGBQUAD * const dst_pal = FreeImage_GetPalette(dst);
if (color_type == FIC_MINISWHITE) {
// build an inverted greyscale palette
CREATE_GREYSCALE_PALETTE_REVERSE(dst_pal, 256);
}
/*
else {
// build a default greyscale palette
// Currently, FreeImage_AllocateT already creates a default
// greyscale palette for 8 bpp images, so we can skip this here.
CREATE_GREYSCALE_PALETTE(dst_pal, 256);
}
*/
}
// calculate x and y offsets; since FreeImage uses bottom-up bitmaps, the
// value of src_offset_y is measured from the bottom of the image
unsigned src_offset_x = src_left;
unsigned src_offset_y = FreeImage_GetHeight(src) - src_height - src_top;
/*
Decide which filtering order (xy or yx) is faster for this mapping.
--- The theory ---
Try to minimize calculations by counting the number of convolution multiplies
if(dst_width*src_height <= src_width*dst_height) {
// xy filtering
} else {
// yx filtering
}
--- The practice ---
Try to minimize calculations by counting the number of vertical convolutions (the most time consuming task)
if(dst_width*dst_height <= src_width*dst_height) {
// xy filtering
} else {
// yx filtering
}
*/
if (dst_width <= src_width) {
// xy filtering
// -------------
FIBITMAP *tmp = NULL;
src/Source/FreeImageToolkit/Resize.cpp view on Meta::CPAN
}
} else {
// source and destination widths are equal so, we can directly
// scale into destination image (second filter method will not
// be invoked)
tmp = dst;
}
// scale source image vertically into temporary (or destination) image
verticalFilter(src, src_width, src_height, src_offset_x, src_offset_y, src_pal, tmp, dst_height);
// set x and y offsets to zero for the second filter method
// invocation (the temporary image only contains the portion of
// the image to be rescaled with no offsets)
src_offset_x = 0;
src_offset_y = 0;
// also ensure, that the second filter method gets no source
// palette (the temporary image is palletized only, if it is
// greyscale; in that case, it is an 8-bit image with a linear
// palette so, the source palette is not needed or will even be
// mismatching, if the source palette is unordered)
src_pal = NULL;
} else {
// source and destination heights are equal so, just copy the
// image pointer
tmp = src;
}
if (src_width != dst_width) {
// source and destination heights are different so, scale
// temporary (or source) image horizontally into destination image
horizontalFilter(tmp, dst_height, src_width, src_offset_x, src_offset_y, src_pal, dst, dst_width);
}
// free temporary image, if not pointing to either src or dst
if (tmp != src && tmp != dst) {
FreeImage_Unload(tmp);
}
}
return dst;
}
void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsigned src_width, unsigned src_offset_x, unsigned src_offset_y, const RGBQUAD *const src_pal, FIBITMAP *const dst, unsigned dst_width) {
// allocate and calculate the contributions
CWeightsTable weightsTable(m_pFilter, dst_width, src_width);
// step through rows
switch(FreeImage_GetImageType(src)) {
case FIT_BITMAP:
{
switch(FreeImage_GetBPP(src)) {
case 1:
{
switch(FreeImage_GetBPP(dst)) {
case 8:
{
// transparently convert the 1-bit non-transparent greyscale image to 8 bpp
src_offset_x >>= 3;
if (src_pal) {
// we have got a palette
for (unsigned y = 0; y < height; y++) {
// scale each row
const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
BYTE * const dst_bits = FreeImage_GetScanLine(dst, y);
for (unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
double value = 0;
for (unsigned i = iLeft; i < iRight; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const unsigned pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0;
value += (weightsTable.getWeight(x, i - iLeft) * (double)*(BYTE *)&src_pal[pixel]);
}
// clamp and place result in destination pixel
dst_bits[x] = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
}
}
} else {
// we do not have a palette
for (unsigned y = 0; y < height; y++) {
// scale each row
const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
BYTE * const dst_bits = FreeImage_GetScanLine(dst, y);
for (unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
double value = 0;
for (unsigned i = iLeft; i < iRight; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const unsigned pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0;
value += (weightsTable.getWeight(x, i - iLeft) * (double)pixel);
}
value *= 0xFF;
// clamp and place result in destination pixel
dst_bits[x] = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
}
}
}
}
break;
case 24:
{
// transparently convert the non-transparent 1-bit image to 24 bpp
src_offset_x >>= 3;
if (src_pal) {
// we have got a palette
for (unsigned y = 0; y < height; y++) {
// scale each row
const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
for (unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
double r = 0, g = 0, b = 0;
for (unsigned i = iLeft; i < iRight; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(x, i - iLeft);
const unsigned pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0;
const BYTE * const entry = (BYTE *)&src_pal[pixel];
r += (weight * (double)entry[FI_RGBA_RED]);
g += (weight * (double)entry[FI_RGBA_GREEN]);
b += (weight * (double)entry[FI_RGBA_BLUE]);
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
dst_bits += 3;
}
}
} else {
// we do not have a palette
for (unsigned y = 0; y < height; y++) {
// scale each row
const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
for (unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
double value = 0;
for (unsigned i = iLeft; i < iRight; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const unsigned pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0;
value += (weightsTable.getWeight(x, i - iLeft) * (double)pixel);
}
value *= 0xFF;
// clamp and place result in destination pixel
const BYTE bval = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_RED] = bval;
dst_bits[FI_RGBA_GREEN] = bval;
dst_bits[FI_RGBA_BLUE] = bval;
dst_bits += 3;
}
}
}
}
break;
case 32:
{
// transparently convert the transparent 1-bit image to 32 bpp;
// we always have got a palette here
src_offset_x >>= 3;
for (unsigned y = 0; y < height; y++) {
// scale each row
const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
for (unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
double r = 0, g = 0, b = 0, a = 0;
for (unsigned i = iLeft; i < iRight; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(x, i - iLeft);
const unsigned pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0;
const BYTE * const entry = (BYTE *)&src_pal[pixel];
r += (weight * (double)entry[FI_RGBA_RED]);
g += (weight * (double)entry[FI_RGBA_GREEN]);
b += (weight * (double)entry[FI_RGBA_BLUE]);
a += (weight * (double)entry[FI_RGBA_ALPHA]);
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
dst_bits += 4;
}
}
}
break;
}
}
break;
case 4:
{
switch(FreeImage_GetBPP(dst)) {
case 8:
{
// transparently convert the non-transparent 4-bit greyscale image to 8 bpp;
// we always have got a palette for 4-bit images
src_offset_x >>= 1;
for (unsigned y = 0; y < height; y++) {
// scale each row
const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
BYTE * const dst_bits = FreeImage_GetScanLine(dst, y);
for (unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
double value = 0;
for (unsigned i = iLeft; i < iRight; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const unsigned pixel = i & 0x01 ? src_bits[i >> 1] & 0x0F : src_bits[i >> 1] >> 4;
value += (weightsTable.getWeight(x, i - iLeft) * (double)*(BYTE *)&src_pal[pixel]);
}
// clamp and place result in destination pixel
dst_bits[x] = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
}
}
}
break;
case 24:
{
// transparently convert the non-transparent 4-bit image to 24 bpp;
// we always have got a palette for 4-bit images
src_offset_x >>= 1;
for (unsigned y = 0; y < height; y++) {
// scale each row
const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
for (unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
double r = 0, g = 0, b = 0;
for (unsigned i = iLeft; i < iRight; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(x, i - iLeft);
const unsigned pixel = i & 0x01 ? src_bits[i >> 1] & 0x0F : src_bits[i >> 1] >> 4;
const BYTE * const entry = (BYTE *)&src_pal[pixel];
r += (weight * (double)entry[FI_RGBA_RED]);
g += (weight * (double)entry[FI_RGBA_GREEN]);
b += (weight * (double)entry[FI_RGBA_BLUE]);
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
dst_bits += 3;
}
}
}
break;
case 32:
{
// transparently convert the transparent 4-bit image to 32 bpp;
// we always have got a palette for 4-bit images
src_offset_x >>= 1;
for (unsigned y = 0; y < height; y++) {
// scale each row
const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
for (unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
double r = 0, g = 0, b = 0, a = 0;
for (unsigned i = iLeft; i < iRight; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(x, i - iLeft);
const unsigned pixel = i & 0x01 ? src_bits[i >> 1] & 0x0F : src_bits[i >> 1] >> 4;
const BYTE * const entry = (BYTE *)&src_pal[pixel];
r += (weight * (double)entry[FI_RGBA_RED]);
g += (weight * (double)entry[FI_RGBA_GREEN]);
b += (weight * (double)entry[FI_RGBA_BLUE]);
a += (weight * (double)entry[FI_RGBA_ALPHA]);
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
dst_bits += 4;
}
}
}
break;
}
}
break;
case 8:
{
switch(FreeImage_GetBPP(dst)) {
case 8:
{
// scale the 8-bit non-transparent greyscale image
// into an 8 bpp destination image
if (src_pal) {
// we have got a palette
for (unsigned y = 0; y < height; y++) {
// scale each row
const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
BYTE * const dst_bits = FreeImage_GetScanLine(dst, y);
for (unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
const BYTE * const pixel = src_bits + iLeft;
double value = 0;
// for(i = iLeft to iRight)
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
value += (weightsTable.getWeight(x, i) * (double)*(BYTE *)&src_pal[pixel[i]]);
}
// clamp and place result in destination pixel
dst_bits[x] = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
}
}
} else {
// we do not have a palette
for (unsigned y = 0; y < height; y++) {
// scale each row
const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
BYTE * const dst_bits = FreeImage_GetScanLine(dst, y);
for (unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
const BYTE * const pixel = src_bits + iLeft;
double value = 0;
// for(i = iLeft to iRight)
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
value += (weightsTable.getWeight(x, i) * (double)pixel[i]);
}
// clamp and place result in destination pixel
dst_bits[x] = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
}
}
}
}
break;
case 24:
{
// transparently convert the non-transparent 8-bit image to 24 bpp
if (src_pal) {
// we have got a palette
for (unsigned y = 0; y < height; y++) {
// scale each row
const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
for (unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
const BYTE * const pixel = src_bits + iLeft;
double r = 0, g = 0, b = 0;
// for(i = iLeft to iRight)
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(x, i);
const BYTE *const entry = (BYTE *)&src_pal[pixel[i]];
r += (weight * (double)entry[FI_RGBA_RED]);
g += (weight * (double)entry[FI_RGBA_GREEN]);
b += (weight * (double)entry[FI_RGBA_BLUE]);
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
dst_bits += 3;
}
}
} else {
// we do not have a palette
for (unsigned y = 0; y < height; y++) {
// scale each row
const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
for (unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
const BYTE * const pixel = src_bits + iLeft;
double value = 0;
// for(i = iLeft to iRight)
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(x, i);
value += (weight * (double)pixel[i]);
}
// clamp and place result in destination pixel
const BYTE bval = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_RED] = bval;
dst_bits[FI_RGBA_GREEN] = bval;
dst_bits[FI_RGBA_BLUE] = bval;
dst_bits += 3;
}
}
}
}
break;
case 32:
{
// transparently convert the transparent 8-bit image to 32 bpp;
// we always have got a palette here
for (unsigned y = 0; y < height; y++) {
// scale each row
const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
for (unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
const BYTE * const pixel = src_bits + iLeft;
double r = 0, g = 0, b = 0, a = 0;
// for(i = iLeft to iRight)
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(x, i);
const BYTE * const entry = (BYTE *)&src_pal[pixel[i]];
r += (weight * (double)entry[FI_RGBA_RED]);
g += (weight * (double)entry[FI_RGBA_GREEN]);
b += (weight * (double)entry[FI_RGBA_BLUE]);
a += (weight * (double)entry[FI_RGBA_ALPHA]);
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
dst_bits += 4;
}
}
}
break;
}
}
break;
case 16:
{
// transparently convert the 16-bit non-transparent image to 24 bpp
if (IS_FORMAT_RGB565(src)) {
// image has 565 format
for (unsigned y = 0; y < height; y++) {
// scale each row
const WORD * const src_bits = (WORD *)FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x / sizeof(WORD);
BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
for (unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
const WORD *pixel = src_bits + iLeft;
double r = 0, g = 0, b = 0;
// for(i = iLeft to iRight)
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(x, i);
r += (weight * (double)((*pixel & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT));
g += (weight * (double)((*pixel & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT));
b += (weight * (double)((*pixel & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT));
pixel++;
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(((r * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(((g * 0xFF) / 0x3F) + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(((b * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
dst_bits += 3;
}
}
} else {
// image has 555 format
for (unsigned y = 0; y < height; y++) {
// scale each row
const WORD * const src_bits = (WORD *)FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
for (unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
const WORD *pixel = src_bits + iLeft;
double r = 0, g = 0, b = 0;
// for(i = iLeft to iRight)
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(x, i);
r += (weight * (double)((*pixel & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT));
g += (weight * (double)((*pixel & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT));
b += (weight * (double)((*pixel & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT));
pixel++;
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(((r * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(((g * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(((b * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
dst_bits += 3;
}
}
}
}
break;
case 24:
{
// scale the 24-bit non-transparent image into a 24 bpp destination image
for (unsigned y = 0; y < height; y++) {
// scale each row
const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x * 3;
BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
for (unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
const BYTE * pixel = src_bits + iLeft * 3;
double r = 0, g = 0, b = 0;
// for(i = iLeft to iRight)
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(x, i);
r += (weight * (double)pixel[FI_RGBA_RED]);
g += (weight * (double)pixel[FI_RGBA_GREEN]);
b += (weight * (double)pixel[FI_RGBA_BLUE]);
pixel += 3;
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
dst_bits += 3;
}
}
}
break;
case 32:
{
// scale the 32-bit transparent image into a 32 bpp destination image
for (unsigned y = 0; y < height; y++) {
// scale each row
const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x * 4;
BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
for (unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
const BYTE *pixel = src_bits + iLeft * 4;
double r = 0, g = 0, b = 0, a = 0;
// for(i = iLeft to iRight)
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(x, i);
r += (weight * (double)pixel[FI_RGBA_RED]);
g += (weight * (double)pixel[FI_RGBA_GREEN]);
b += (weight * (double)pixel[FI_RGBA_BLUE]);
a += (weight * (double)pixel[FI_RGBA_ALPHA]);
pixel += 4;
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
dst_bits += 4;
}
}
}
break;
}
}
break;
case FIT_UINT16:
{
// Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
const unsigned wordspp = (FreeImage_GetLine(src) / src_width) / sizeof(WORD);
for (unsigned y = 0; y < height; y++) {
// scale each row
const WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x / sizeof(WORD);
WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
for (unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
const WORD *pixel = src_bits + iLeft * wordspp;
double value = 0;
// for(i = iLeft to iRight)
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(x, i);
src/Source/FreeImageToolkit/Resize.cpp view on Meta::CPAN
// Calculate the number of floats per pixel (1 for 32-bit, 3 for 96-bit or 4 for 128-bit)
const unsigned floatspp = (FreeImage_GetLine(src) / src_width) / sizeof(float);
for(unsigned y = 0; y < height; y++) {
// scale each row
const float *src_bits = (float*)FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x / sizeof(float);
float *dst_bits = (float*)FreeImage_GetScanLine(dst, y);
for(unsigned x = 0; x < dst_width; x++) {
// loop through row
const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
double value[4] = {0, 0, 0, 0}; // 4 = 128 bpp max
for(unsigned i = iLeft; i < iRight; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(x, i-iLeft);
unsigned index = i * floatspp; // pixel index
for (unsigned j = 0; j < floatspp; j++) {
value[j] += (weight * (double)src_bits[index++]);
}
}
// place result in destination pixel
for (unsigned j = 0; j < floatspp; j++) {
dst_bits[j] = (float)value[j];
}
dst_bits += floatspp;
}
}
}
break;
}
}
/// Performs vertical image filtering
void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned src_height, unsigned src_offset_x, unsigned src_offset_y, const RGBQUAD *const src_pal, FIBITMAP *const dst, unsigned dst_height) {
// allocate and calculate the contributions
CWeightsTable weightsTable(m_pFilter, dst_height, src_height);
// step through columns
switch(FreeImage_GetImageType(src)) {
case FIT_BITMAP:
{
const unsigned dst_pitch = FreeImage_GetPitch(dst);
BYTE * const dst_base = FreeImage_GetBits(dst);
switch(FreeImage_GetBPP(src)) {
case 1:
{
const unsigned src_pitch = FreeImage_GetPitch(src);
const BYTE * const src_base = FreeImage_GetBits(src) + src_offset_y * src_pitch + (src_offset_x >> 3);
switch(FreeImage_GetBPP(dst)) {
case 8:
{
// transparently convert the 1-bit non-transparent greyscale image to 8 bpp
if (src_pal) {
// we have got a palette
for (unsigned x = 0; x < width; x++) {
// work on column x in dst
BYTE *dst_bits = dst_base + x;
const unsigned index = x >> 3;
const unsigned mask = 0x80 >> (x & 0x07);
// scale each column
for (unsigned y = 0; y < dst_height; y++) {
// loop through column
const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
const BYTE *src_bits = src_base + iLeft * src_pitch + index;
double value = 0;
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const unsigned pixel = (*src_bits & mask) != 0;
value += (weightsTable.getWeight(y, i) * (double)*(BYTE *)&src_pal[pixel]);
src_bits += src_pitch;
}
value *= 0xFF;
// clamp and place result in destination pixel
*dst_bits = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
dst_bits += dst_pitch;
}
}
} else {
// we do not have a palette
for (unsigned x = 0; x < width; x++) {
// work on column x in dst
BYTE *dst_bits = dst_base + x;
const unsigned index = x >> 3;
const unsigned mask = 0x80 >> (x & 0x07);
// scale each column
for (unsigned y = 0; y < dst_height; y++) {
// loop through column
const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
const BYTE *src_bits = src_base + iLeft * src_pitch + index;
double value = 0;
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
value += (weightsTable.getWeight(y, i) * (double)((*src_bits & mask) != 0));
src_bits += src_pitch;
}
value *= 0xFF;
// clamp and place result in destination pixel
*dst_bits = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
dst_bits += dst_pitch;
}
}
}
}
break;
case 24:
{
// transparently convert the non-transparent 1-bit image to 24 bpp
if (src_pal) {
// we have got a palette
for (unsigned x = 0; x < width; x++) {
// work on column x in dst
BYTE *dst_bits = dst_base + x * 3;
const unsigned index = x >> 3;
const unsigned mask = 0x80 >> (x & 0x07);
// scale each column
for (unsigned y = 0; y < dst_height; y++) {
// loop through column
const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
const BYTE *src_bits = src_base + iLeft * src_pitch + index;
double r = 0, g = 0, b = 0;
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(y, i);
const unsigned pixel = (*src_bits & mask) != 0;
const BYTE * const entry = (BYTE *)&src_pal[pixel];
r += (weight * (double)entry[FI_RGBA_RED]);
g += (weight * (double)entry[FI_RGBA_GREEN]);
b += (weight * (double)entry[FI_RGBA_BLUE]);
src_bits += src_pitch;
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
dst_bits += dst_pitch;
}
}
} else {
// we do not have a palette
for (unsigned x = 0; x < width; x++) {
// work on column x in dst
BYTE *dst_bits = dst_base + x * 3;
const unsigned index = x >> 3;
const unsigned mask = 0x80 >> (x & 0x07);
// scale each column
for (unsigned y = 0; y < dst_height; y++) {
// loop through column
const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
const BYTE *src_bits = src_base + iLeft * src_pitch + index;
double value = 0;
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
value += (weightsTable.getWeight(y, i) * (double)((*src_bits & mask) != 0));
src_bits += src_pitch;
}
value *= 0xFF;
// clamp and place result in destination pixel
const BYTE bval = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_RED] = bval;
dst_bits[FI_RGBA_GREEN] = bval;
dst_bits[FI_RGBA_BLUE] = bval;
dst_bits += dst_pitch;
}
}
}
}
break;
case 32:
{
// transparently convert the transparent 1-bit image to 32 bpp;
// we always have got a palette here
for (unsigned x = 0; x < width; x++) {
// work on column x in dst
BYTE *dst_bits = dst_base + x * 4;
const unsigned index = x >> 3;
const unsigned mask = 0x80 >> (x & 0x07);
// scale each column
for (unsigned y = 0; y < dst_height; y++) {
// loop through column
const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
const BYTE *src_bits = src_base + iLeft * src_pitch + index;
double r = 0, g = 0, b = 0, a = 0;
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(y, i);
const unsigned pixel = (*src_bits & mask) != 0;
const BYTE * const entry = (BYTE *)&src_pal[pixel];
r += (weight * (double)entry[FI_RGBA_RED]);
g += (weight * (double)entry[FI_RGBA_GREEN]);
b += (weight * (double)entry[FI_RGBA_BLUE]);
a += (weight * (double)entry[FI_RGBA_ALPHA]);
src_bits += src_pitch;
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
dst_bits += dst_pitch;
}
}
}
break;
}
}
break;
case 4:
{
const unsigned src_pitch = FreeImage_GetPitch(src);
const BYTE *const src_base = FreeImage_GetBits(src) + src_offset_y * src_pitch + (src_offset_x >> 1);
switch(FreeImage_GetBPP(dst)) {
case 8:
{
// transparently convert the non-transparent 4-bit greyscale image to 8 bpp;
// we always have got a palette for 4-bit images
for (unsigned x = 0; x < width; x++) {
// work on column x in dst
BYTE *dst_bits = dst_base + x;
const unsigned index = x >> 1;
// scale each column
for (unsigned y = 0; y < dst_height; y++) {
// loop through column
const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
const BYTE *src_bits = src_base + iLeft * src_pitch + index;
double value = 0;
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const unsigned pixel = x & 0x01 ? *src_bits & 0x0F : *src_bits >> 4;
value += (weightsTable.getWeight(y, i) * (double)*(BYTE *)&src_pal[pixel]);
src_bits += src_pitch;
}
// clamp and place result in destination pixel
*dst_bits = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
dst_bits += dst_pitch;
}
}
}
break;
case 24:
{
// transparently convert the non-transparent 4-bit image to 24 bpp;
// we always have got a palette for 4-bit images
for (unsigned x = 0; x < width; x++) {
// work on column x in dst
BYTE *dst_bits = dst_base + x * 3;
const unsigned index = x >> 1;
// scale each column
for (unsigned y = 0; y < dst_height; y++) {
// loop through column
const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
const BYTE *src_bits = src_base + iLeft * src_pitch + index;
double r = 0, g = 0, b = 0;
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(y, i);
const unsigned pixel = x & 0x01 ? *src_bits & 0x0F : *src_bits >> 4;
const BYTE *const entry = (BYTE *)&src_pal[pixel];
r += (weight * (double)entry[FI_RGBA_RED]);
g += (weight * (double)entry[FI_RGBA_GREEN]);
b += (weight * (double)entry[FI_RGBA_BLUE]);
src_bits += src_pitch;
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
dst_bits += dst_pitch;
}
}
}
break;
case 32:
{
// transparently convert the transparent 4-bit image to 32 bpp;
// we always have got a palette for 4-bit images
for (unsigned x = 0; x < width; x++) {
// work on column x in dst
BYTE *dst_bits = dst_base + x * 4;
const unsigned index = x >> 1;
// scale each column
for (unsigned y = 0; y < dst_height; y++) {
// loop through column
const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
const BYTE *src_bits = src_base + iLeft * src_pitch + index;
double r = 0, g = 0, b = 0, a = 0;
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(y, i);
const unsigned pixel = x & 0x01 ? *src_bits & 0x0F : *src_bits >> 4;
const BYTE *const entry = (BYTE *)&src_pal[pixel];
r += (weight * (double)entry[FI_RGBA_RED]);
g += (weight * (double)entry[FI_RGBA_GREEN]);
b += (weight * (double)entry[FI_RGBA_BLUE]);
a += (weight * (double)entry[FI_RGBA_ALPHA]);
src_bits += src_pitch;
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
dst_bits += dst_pitch;
}
}
}
break;
}
}
break;
case 8:
{
const unsigned src_pitch = FreeImage_GetPitch(src);
const BYTE *const src_base = FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x;
switch(FreeImage_GetBPP(dst)) {
case 8:
{
// scale the 8-bit non-transparent greyscale image into an 8 bpp destination image
if (src_pal) {
// we have got a palette
for (unsigned x = 0; x < width; x++) {
// work on column x in dst
BYTE *dst_bits = dst_base + x;
// scale each column
for (unsigned y = 0; y < dst_height; y++) {
// loop through column
const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
const BYTE *src_bits = src_base + iLeft * src_pitch + x;
double value = 0;
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
value += (weightsTable.getWeight(y, i) * (double)*(BYTE *)&src_pal[*src_bits]);
src_bits += src_pitch;
}
// clamp and place result in destination pixel
*dst_bits = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
dst_bits += dst_pitch;
}
}
} else {
// we do not have a palette
for (unsigned x = 0; x < width; x++) {
// work on column x in dst
BYTE *dst_bits = dst_base + x;
// scale each column
for (unsigned y = 0; y < dst_height; y++) {
// loop through column
const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
const BYTE *src_bits = src_base + iLeft * src_pitch + x;
double value = 0;
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
value += (weightsTable.getWeight(y, i) * (double)*src_bits);
src_bits += src_pitch;
}
// clamp and place result in destination pixel
*dst_bits = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
dst_bits += dst_pitch;
}
}
}
}
break;
case 24:
{
// transparently convert the non-transparent 8-bit image to 24 bpp
if (src_pal) {
// we have got a palette
for (unsigned x = 0; x < width; x++) {
// work on column x in dst
BYTE *dst_bits = dst_base + x * 3;
// scale each column
for (unsigned y = 0; y < dst_height; y++) {
// loop through column
const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
const BYTE *src_bits = src_base + iLeft * src_pitch + x;
double r = 0, g = 0, b = 0;
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(y, i);
const BYTE * const entry = (BYTE *)&src_pal[*src_bits];
r += (weight * (double)entry[FI_RGBA_RED]);
g += (weight * (double)entry[FI_RGBA_GREEN]);
b += (weight * (double)entry[FI_RGBA_BLUE]);
src_bits += src_pitch;
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
dst_bits += dst_pitch;
}
}
} else {
// we do not have a palette
for (unsigned x = 0; x < width; x++) {
// work on column x in dst
BYTE *dst_bits = dst_base + x * 3;
// scale each column
for (unsigned y = 0; y < dst_height; y++) {
// loop through column
const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
const BYTE *src_bits = src_base + iLeft * src_pitch + x;
double value = 0;
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
value += (weightsTable.getWeight(y, i) * (double)*src_bits);
src_bits += src_pitch;
}
// clamp and place result in destination pixel
const BYTE bval = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_RED] = bval;
dst_bits[FI_RGBA_GREEN] = bval;
dst_bits[FI_RGBA_BLUE] = bval;
dst_bits += dst_pitch;
}
}
}
}
break;
case 32:
{
// transparently convert the transparent 8-bit image to 32 bpp;
// we always have got a palette here
for (unsigned x = 0; x < width; x++) {
// work on column x in dst
BYTE *dst_bits = dst_base + x * 4;
// scale each column
for (unsigned y = 0; y < dst_height; y++) {
// loop through column
const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
const BYTE *src_bits = src_base + iLeft * src_pitch + x;
double r = 0, g = 0, b = 0, a = 0;
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(y, i);
const BYTE * const entry = (BYTE *)&src_pal[*src_bits];
r += (weight * (double)entry[FI_RGBA_RED]);
g += (weight * (double)entry[FI_RGBA_GREEN]);
b += (weight * (double)entry[FI_RGBA_BLUE]);
a += (weight * (double)entry[FI_RGBA_ALPHA]);
src_bits += src_pitch;
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
dst_bits += dst_pitch;
}
}
}
break;
}
}
break;
case 16:
{
// transparently convert the 16-bit non-transparent image to 24 bpp
const unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(WORD);
const WORD *const src_base = (WORD *)FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x;
if (IS_FORMAT_RGB565(src)) {
// image has 565 format
for (unsigned x = 0; x < width; x++) {
// work on column x in dst
BYTE *dst_bits = dst_base + x * 3;
// scale each column
for (unsigned y = 0; y < dst_height; y++) {
// loop through column
const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
const WORD *src_bits = src_base + iLeft * src_pitch + x;
double r = 0, g = 0, b = 0;
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(y, i);
r += (weight * (double)((*src_bits & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT));
g += (weight * (double)((*src_bits & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT));
b += (weight * (double)((*src_bits & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT));
src_bits += src_pitch;
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(((r * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(((g * 0xFF) / 0x3F) + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(((b * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
dst_bits += dst_pitch;
}
}
} else {
// image has 555 format
for (unsigned x = 0; x < width; x++) {
// work on column x in dst
BYTE *dst_bits = dst_base + x * 3;
// scale each column
for (unsigned y = 0; y < dst_height; y++) {
// loop through column
const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
const WORD *src_bits = src_base + iLeft * src_pitch + x;
double r = 0, g = 0, b = 0;
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(y, i);
r += (weight * (double)((*src_bits & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT));
g += (weight * (double)((*src_bits & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT));
b += (weight * (double)((*src_bits & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT));
src_bits += src_pitch;
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(((r * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(((g * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(((b * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
dst_bits += dst_pitch;
}
}
}
}
break;
case 24:
{
// scale the 24-bit transparent image into a 24 bpp destination image
const unsigned src_pitch = FreeImage_GetPitch(src);
const BYTE *const src_base = FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x * 3;
for (unsigned x = 0; x < width; x++) {
// work on column x in dst
const unsigned index = x * 3;
BYTE *dst_bits = dst_base + index;
// scale each column
for (unsigned y = 0; y < dst_height; y++) {
// loop through column
const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
const BYTE *src_bits = src_base + iLeft * src_pitch + index;
double r = 0, g = 0, b = 0;
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(y, i);
r += (weight * (double)src_bits[FI_RGBA_RED]);
g += (weight * (double)src_bits[FI_RGBA_GREEN]);
b += (weight * (double)src_bits[FI_RGBA_BLUE]);
src_bits += src_pitch;
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int) (r + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int) (g + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int) (b + 0.5), 0, 0xFF);
dst_bits += dst_pitch;
}
}
}
break;
case 32:
{
// scale the 32-bit transparent image into a 32 bpp destination image
const unsigned src_pitch = FreeImage_GetPitch(src);
const BYTE *const src_base = FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x * 4;
for (unsigned x = 0; x < width; x++) {
// work on column x in dst
const unsigned index = x * 4;
BYTE *dst_bits = dst_base + index;
// scale each column
for (unsigned y = 0; y < dst_height; y++) {
// loop through column
const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
const BYTE *src_bits = src_base + iLeft * src_pitch + index;
double r = 0, g = 0, b = 0, a = 0;
for (unsigned i = 0; i < iLimit; i++) {
// scan between boundaries
// accumulate weighted effect of each neighboring pixel
const double weight = weightsTable.getWeight(y, i);
r += (weight * (double)src_bits[FI_RGBA_RED]);
g += (weight * (double)src_bits[FI_RGBA_GREEN]);
b += (weight * (double)src_bits[FI_RGBA_BLUE]);
a += (weight * (double)src_bits[FI_RGBA_ALPHA]);
src_bits += src_pitch;
}
// clamp and place result in destination pixel
dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int) (r + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int) (g + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int) (b + 0.5), 0, 0xFF);
dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int) (a + 0.5), 0, 0xFF);
dst_bits += dst_pitch;
}
}
}
break;
}
}
break;
case FIT_UINT16:
{
// Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
const unsigned wordspp = (FreeImage_GetLine(src) / width) / sizeof(WORD);
const unsigned dst_pitch = FreeImage_GetPitch(dst) / sizeof(WORD);
WORD *const dst_base = (WORD *)FreeImage_GetBits(dst);
const unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(WORD);
const WORD *const src_base = (WORD *)FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x * wordspp;
for (unsigned x = 0; x < width; x++) {
// work on column x in dst
const unsigned index = x * wordspp; // pixel index
WORD *dst_bits = dst_base + index;
// scale each column
for (unsigned y = 0; y < dst_height; y++) {
// loop through column
( run in 0.777 second using v1.01-cache-2.11-cpan-787462296c9 )