diff --git a/uppsrc/Draw/BiCubic.cpp b/uppsrc/Draw/BiCubic.cpp new file mode 100644 index 000000000..341b5e227 --- /dev/null +++ b/uppsrc/Draw/BiCubic.cpp @@ -0,0 +1,65 @@ +#include "Draw.h" + +NAMESPACE_UPP + +double BicubicKernel(double x) +{ + double r = 0; + double xp2 = x + 2; + double xp1 = x + 1; + double xm1 = x - 1; + if(xp2 > 0) + r += xp2 * xp2 * xp2; + if(xp1 > 0) + r -= 4 * xp1 * xp1 * xp1; + if(x > 0) + r += 6 * x * x * x; + if(xm1 > 0) + r -= 4 * xm1 * xm1 * xm1; + return 1 / 6.0 * r; +} + +Image RescaleBicubic(const Image& img, int cx, int cy) +{ + Size isz = img.GetSize(); + ImageBuffer ib(cx, cy); + RGBA *t = ~ib; + double inv_cx = 1.0 / cx; + for(int y = 0; y < cy; y++) { + int sy = (y * isz.cy) / cy; + double dy = y * isz.cy / (double)cy - sy; + for(int x = 0; x < cx; x++) { + int sx = (x * isz.cx) / cx; + double dx = x * isz.cx * inv_cx - sx; + double red = 0; + double green = 0; + double blue = 0; + double alpha = 0; + for(int yy = -1; yy <= 2; yy++) { + double ky = BicubicKernel(yy - dy); + const RGBA *l = img[minmax(sy + yy, 0, isz.cy - 1)]; + for(int xx = -1; xx <= 2; xx++) { + const RGBA& s = l[minmax(sx + xx, 0, isz.cx - 1)]; + double weight = ky * BicubicKernel(xx - dx); + red += weight * s.r; + green += weight * s.g; + blue += weight * s.b; + alpha += weight * s.a; + } + } + t->r = (int)fround(red); + t->g = (int)fround(green); + t->b = (int)fround(blue); + t->a = (int)fround(alpha); + t++; + } + } + return ib; +} + +Image RescaleBicubic(const Image& src, Size sz) +{ + return RescaleBicubic(src, sz.cx, sz.cy); +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Draw/Draw.upp b/uppsrc/Draw/Draw.upp index caeacd461..ab058222c 100644 --- a/uppsrc/Draw/Draw.upp +++ b/uppsrc/Draw/Draw.upp @@ -50,6 +50,7 @@ file ImageOp.cpp, ImageChOp.cpp, ImageScale.cpp, + BiCubic.cpp, MakeCache.cpp, DrawRasterData.cpp, iml.h, diff --git a/uppsrc/Draw/Image.cpp b/uppsrc/Draw/Image.cpp index f8f686ea9..e4da819d3 100644 --- a/uppsrc/Draw/Image.cpp +++ b/uppsrc/Draw/Image.cpp @@ -161,27 +161,6 @@ const RGBA* Image::operator~() const return data ? ~data->buffer : NULL; } -Image::operator const RGBA*() const -{ - return data ? ~data->buffer : NULL; -} - -const RGBA* Image::operator[](int i) const -{ - ASSERT(data); - return data->buffer[i]; -} - -Size Image::GetSize() const -{ - return data ? data->buffer.GetSize() : Size(0, 0); -} - -int Image::GetLength() const -{ - return data ? data->buffer.GetLength() : 0; -} - Point Image::GetHotSpot() const { return data ? data->buffer.GetHotSpot() : Point(0, 0); diff --git a/uppsrc/Draw/Image.h b/uppsrc/Draw/Image.h index f4b1cbf65..45c397ea3 100644 --- a/uppsrc/Draw/Image.h +++ b/uppsrc/Draw/Image.h @@ -159,13 +159,13 @@ private: public: const RGBA* operator~() const; - operator const RGBA*() const; - const RGBA* operator[](int i) const; + operator const RGBA*() const { return data ? ~data->buffer : NULL; } + const RGBA* operator[](int i) const { ASSERT(data); return data->buffer[i]; } - Size GetSize() const; + Size GetSize() const { return data ? data->buffer.GetSize() : Size(0, 0); } int GetWidth() const { return GetSize().cx; } int GetHeight() const { return GetSize().cy; } - int GetLength() const; + int GetLength() const { return data ? data->buffer.GetLength() : 0; } Point GetHotSpot() const; Point Get2ndSpot() const; Size GetDots() const; diff --git a/uppsrc/Draw/ImageOp.h b/uppsrc/Draw/ImageOp.h index fab8c12ce..51188063a 100644 --- a/uppsrc/Draw/ImageOp.h +++ b/uppsrc/Draw/ImageOp.h @@ -75,6 +75,9 @@ Image Rescale(const Image& src, Size sz, const Rect& src_rc, Gate2 pro Image Rescale(const Image& src, Size sz, Gate2 progress = false); Image Rescale(const Image& src, int cx, int cy, Gate2 progress = false); +Image RescaleBicubic(const Image& img, int cx, int cy); +Image RescaleBicubic(const Image& img, Size sz); + struct ImageFilter9 { virtual RGBA operator()(const RGBA **mx) = 0; virtual ~ImageFilter9() {}