summaryrefslogtreecommitdiffstats
path: root/src/display/pixblock-scaler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/display/pixblock-scaler.cpp')
-rw-r--r--src/display/pixblock-scaler.cpp87
1 files changed, 82 insertions, 5 deletions
diff --git a/src/display/pixblock-scaler.cpp b/src/display/pixblock-scaler.cpp
index d65cfd4e0..ddb4c4ee2 100644
--- a/src/display/pixblock-scaler.cpp
+++ b/src/display/pixblock-scaler.cpp
@@ -34,7 +34,7 @@ struct RGBA {
* decimal part. (24.8 assuming 32-bit int)
*/
__attribute__ ((const))
-inline int sampley(unsigned const char a, unsigned const char b,
+inline static int sampley(unsigned const char a, unsigned const char b,
unsigned const char c, unsigned const char d,
const double len)
{
@@ -62,7 +62,7 @@ inline int sampley(unsigned const char a, unsigned const char b,
* Returns the interpolated value in 8-bit format, ready to be written
* to output buffer.
*/
-inline int samplex(const int a, const int b, const int c, const int d, const double len) {
+inline static int samplex(const int a, const int b, const int c, const int d, const double len) {
double lenf = len - floor(len);
int sum = 0;
sum += (int)(a * (((-1.0 / 3.0) * lenf + 4.0 / 5.0) * lenf - 7.0 / 15.0) * lenf);
@@ -79,7 +79,7 @@ inline int samplex(const int a, const int b, const int c, const int d, const dou
* Catches reading and writing outside the pixblock area.
* When enabled, decreases filter rendering speed massively.
*/
-inline void _check_index(NRPixBlock const * const pb, int const location, int const line)
+inline static void _check_index(NRPixBlock const * const pb, int const location, int const line)
{
if(false) {
int max_loc = pb->rs * (pb->area.y1 - pb->area.y0);
@@ -88,10 +88,10 @@ inline void _check_index(NRPixBlock const * const pb, int const location, int co
}
}
-void scale_bicubic(NRPixBlock *to, NRPixBlock *from)
+static void scale_bicubic_rgba(NRPixBlock *to, NRPixBlock *from)
{
if (NR_PIXBLOCK_BPP(from) != 4 || NR_PIXBLOCK_BPP(to) != 4) {
- g_warning("A non-32-bpp image passed to scale_bicubic: scaling aborted.");
+ g_warning("A non-32-bpp image passed to scale_bicubic_rgba: scaling aborted.");
return;
}
@@ -192,6 +192,83 @@ void scale_bicubic(NRPixBlock *to, NRPixBlock *from)
}
}
+void scale_bicubic_alpha(NRPixBlock *to, NRPixBlock *from)
+{
+ if (NR_PIXBLOCK_BPP(from) != 1 || NR_PIXBLOCK_BPP(to) != 1) {
+ g_warning("A non-8-bpp image passed to scale_bicubic_alpha: scaling aborted.");
+ return;
+ }
+
+ // Precalculate sizes of source and destination pixblocks
+ int from_width = from->area.x1 - from->area.x0;
+ int from_height = from->area.y1 - from->area.y0;
+ int to_width = to->area.x1 - to->area.x0;
+ int to_height = to->area.y1 - to->area.y0;
+
+ // from_step: when advancing one pixel in destination image,
+ // how much we should advance in source image
+ double from_stepx = (double)from_width / (double)to_width;
+ double from_stepy = (double)from_height / (double)to_height;
+
+ // Loop through every pixel of destination image, a line at a time
+ for (int to_y = 0 ; to_y < to_height ; to_y++) {
+ double from_y = to_y * from_stepy + from_stepy / 2;
+ // Pre-calculate beginning of the four horizontal lines, from
+ // which we should read
+ int from_line[4];
+ for (int i = 0 ; i < 4 ; i++) {
+ if ((int)floor(from_y) + i - 1 >= 0) {
+ if ((int)floor(from_y) + i - 1 < from_height) {
+ from_line[i] = ((int)floor(from_y) + i - 1) * from->rs;
+ } else {
+ from_line[i] = (from_height - 1) * from->rs;
+ }
+ } else {
+ from_line[i] = 0;
+ }
+ }
+ // Loop through this horizontal line in destination image
+ // For every pixel, calculate the color of pixel with
+ // bicubic interpolation and set the pixel value in destination image
+ for (int to_x = 0 ; to_x < to_width ; to_x++) {
+ double from_x = to_x * from_stepx + from_stepx / 2;
+ int line[4];
+ for (int i = 0 ; i < 4 ; i++) {
+ int k = (int)floor(from_x) + i - 1;
+ if (k < 0) k = 0;
+ if (k >= from_width) k = from_width - 1;
+ _check_index(from, from_line[0] + k, __LINE__);
+ _check_index(from, from_line[1] + k, __LINE__);
+ _check_index(from, from_line[2] + k, __LINE__);
+ _check_index(from, from_line[3] + k, __LINE__);
+ line[i] = sampley(NR_PIXBLOCK_PX(from)[from_line[0] + k],
+ NR_PIXBLOCK_PX(from)[from_line[1] + k],
+ NR_PIXBLOCK_PX(from)[from_line[2] + k],
+ NR_PIXBLOCK_PX(from)[from_line[3] + k],
+ from_y);
+ }
+ int result;
+ result = samplex(line[0], line[1], line[2], line[3],
+ from_x);
+
+ _check_index(to, to_y * to->rs + to_x, __LINE__);
+
+ NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x] = clamp(result);
+ }
+ }
+}
+
+void scale_bicubic(NRPixBlock *to, NRPixBlock *from)
+{
+ if (NR_PIXBLOCK_BPP(to) == 4 && NR_PIXBLOCK_BPP(from) == 4) {
+ scale_bicubic_rgba(to, from);
+ } else if (NR_PIXBLOCK_BPP(to) == 1 && NR_PIXBLOCK_BPP(from) == 1) {
+ scale_bicubic_alpha(to, from);
+ } else {
+ g_warning("NR::scale_bicubic: unsupported bitdepths for scaling: to %d, from %d", NR_PIXBLOCK_BPP(to), NR_PIXBLOCK_BPP(from));
+ }
+}
+
} /* namespace NR */
/*
Local Variables: