Scaler::~Scaler() { if (GetDestImage() != fScaledImage) { delete fScaledImage; fScaledImage = NULL; } }
void Scaler::Completed() { if (GetDestImage() != fScaledImage) { delete fScaledImage; fScaledImage = NULL; } }
void Scaler::Run(int32 i, int32 n) { int32 from, to, height, imageHeight; imageHeight = GetDestImage()->Bounds().IntegerHeight() + 1; height = imageHeight / n; from = i * height; if (i+1 == n) { to = imageHeight - 1; } else { to = from + height - 1; } if (GetDestImage()->Bounds().Width() >= GetSrcImage()->Bounds().Width()) { ScaleBilinearFP(from, to); } else { DownScaleBilinear(from, to); } if (fDither) { Dither(from, to); } }
void Scaler::Dither(int32 fromRow, int32 toRow) { BBitmap* src; BBitmap* dest; intType destW; intType x, y; uchar* srcBits; intType srcBPR; uchar* srcDataRow; uchar* srcData; uchar* destBits; intType destBPR; uchar* destDataRow; uchar* destData; const int32 kBPP = 4; DitheringColumnData* columnData0; DitheringColumnData* columnData; DitheringColumnData* cd; BScreen screen; intType error[3], err[3]; src = fScaledImage; dest = GetDestImage(); ASSERT(src->ColorSpace() == B_RGB32 || src->ColorSpace() == B_RGBA32); ASSERT(dest->ColorSpace() == B_CMAP8); ASSERT(src->Bounds().IntegerWidth() == dest->Bounds().IntegerWidth()); ASSERT(src->Bounds().IntegerHeight() == dest->Bounds().IntegerHeight()); destW = dest->Bounds().IntegerWidth(); srcBits = (uchar*)src->Bits(); srcBPR = src->BytesPerRow(); destBits = (uchar*)dest->Bits(); destBPR = dest->BytesPerRow(); // Allocate space for sentinel at left and right bounds, // so that columnData[-1] and columnData[destW+1] can be safely accessed columnData0 = new DitheringColumnData[destW+3]; columnData = columnData0 + 1; // clear error cd = columnData; for (x = destW; x >= 0; x --, cd ++) { cd->error[0] = cd->error[1] = cd->error[2] =0; } srcDataRow = srcBits + fromRow * srcBPR; destDataRow = destBits + fromRow * destBPR; for (y = fromRow; IsRunning() && y <= toRow; y ++, srcDataRow += srcBPR, destDataRow += destBPR) { // left to right error[0] = error[1] = error[2] = 0; srcData = srcDataRow; destData = destDataRow; for (x = 0; x <= destW; x ++, srcData += kBPP, destData += 1) { rgb_color color, actualColor; uint8 index; color.red = Limit(srcData[2] + error[0] / 16); color.green = Limit(srcData[1] + error[1] / 16); color.blue = Limit(srcData[0] + error[2] / 16); index = screen.IndexForColor(color); actualColor = screen.ColorForIndex(index); *destData = index; err[0] = color.red - actualColor.red; err[1] = color.green -actualColor.green; err[2] = color.blue -actualColor.blue; // distribute error // get error for next pixel cd = &columnData[x+1]; error[0] = cd->error[0] + 7 * err[0]; error[1] = cd->error[1] + 7 * err[1]; error[2] = cd->error[2] + 7 * err[2]; // set error for right pixel below current pixel cd->error[0] = err[0]; cd->error[1] = err[1]; cd->error[2] = err[2]; // add error for pixel below current pixel cd --; cd->error[0] += 5 * err[0]; cd->error[1] += 5 * err[1]; cd->error[2] += 5 * err[2]; // add error for left pixel below current pixel cd --; cd->error[0] += 3 * err[0]; cd->error[1] += 3 * err[1]; cd->error[2] += 3 * err[2]; } // Note: Alogrithm has good results with "left to right" already // Optionally remove code to end of block: y ++; srcDataRow += srcBPR; destDataRow += destBPR; if (y > toRow) break; // right to left error[0] = error[1] = error[2] = 0; srcData = srcDataRow + destW * kBPP; destData = destDataRow + destW; for (x = 0; x <= destW; x ++, srcData -= kBPP, destData -= 1) { rgb_color color, actualColor; uint8 index; color.red = Limit(srcData[2] + error[0] / 16); color.green = Limit(srcData[1] + error[1] / 16); color.blue = Limit(srcData[0] + error[2] / 16); index = screen.IndexForColor(color); actualColor = screen.ColorForIndex(index); *destData = index; err[0] = color.red - actualColor.red; err[1] = color.green -actualColor.green; err[2] = color.blue -actualColor.blue; // distribute error // get error for next pixel cd = &columnData[x-1]; error[0] = cd->error[0] + 7 * err[0]; error[1] = cd->error[1] + 7 * err[1]; error[2] = cd->error[2] + 7 * err[2]; // set error for left pixel below current pixel cd->error[0] = err[0]; cd->error[1] = err[1]; cd->error[2] = err[2]; // add error for pixel below current pixel cd ++; cd->error[0] += 5 * err[0]; cd->error[1] += 5 * err[1]; cd->error[2] += 5 * err[2]; // add error for right pixel below current pixel cd ++; cd->error[0] += 3 * err[0]; cd->error[1] += 3 * err[1]; cd->error[2] += 3 * err[2]; } } delete[] columnData0; }
// Note: On my systems, the operation kInvert shows a speedup on multiple CPUs only! void ImageProcessor::Run(int32 i, int32 n) { int32 from, to; int32 height = (fHeight+1) / n; from = i * height; if (i+1 == n) { to = fHeight; } else { to = from + height - 1; } int32 x, y, destX, destY; const uchar* src = (uchar*)GetSrcImage()->Bits(); uchar* dest = (uchar*)GetDestImage()->Bits(); switch (fOp) { case kRotateClockwise: for (y = from; y <= to; y ++) { for (x = 0; x <= fWidth; x ++) { destX = fHeight - y; destY = x; CopyPixel(dest, destX, destY, src, x, y); } } break; case kRotateCounterClockwise: for (y = from; y <= to; y ++) { for (x = 0; x <= fWidth; x ++) { destX = y; destY = fWidth - x; CopyPixel(dest, destX, destY, src, x, y); } } break; case kFlipTopToBottom: for (y = from; y <= to; y ++) { for (x = 0; x <= fWidth; x ++) { destX = x; destY = fHeight - y; CopyPixel(dest, destX, destY, src, x, y); } } break; case kFlipLeftToRight: for (y = from; y <= to; y ++) { for (x = 0; x <= fWidth; x ++) { destX = fWidth - x; destY = y; CopyPixel(dest, destX, destY, src, x, y); } } break; case kInvert: for (y = from; y <= to; y ++) { for (x = 0; x <= fWidth; x ++) { InvertPixel(x, y, dest, src); } } break; } }