summaryrefslogtreecommitdiff
path: root/src/Fl_Image.cxx
diff options
context:
space:
mode:
authorLauri Kasanen <cand@gmx.com>2014-09-03 11:00:56 +0000
committerLauri Kasanen <cand@gmx.com>2014-09-03 11:00:56 +0000
commitcce4cece01b755dace58e20840a2bc9ec9593b9f (patch)
tree8ff77369abb94246513aa9642a475b20170aa0f7 /src/Fl_Image.cxx
parent105c2b466a020dda40f8a9dec189c5fe9fd4fa3e (diff)
Add bilinear scaling support. STRs #2869 and #3062.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10268 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src/Fl_Image.cxx')
-rw-r--r--src/Fl_Image.cxx95
1 files changed, 81 insertions, 14 deletions
diff --git a/src/Fl_Image.cxx b/src/Fl_Image.cxx
index c27d90b63..7d1643f56 100644
--- a/src/Fl_Image.cxx
+++ b/src/Fl_Image.cxx
@@ -164,6 +164,7 @@ Fl_Image::measure(const Fl_Label *lo, // I - Label
// RGB image class...
//
size_t Fl_RGB_Image::max_size_ = ~((size_t)0);
+Fl_RGB_Scaling Fl_RGB_Image::scaling_ = FL_SCALING_NEAREST;
int fl_convert_pixmap(const char*const* cdata, uchar* out, Fl_Color bg);
@@ -260,25 +261,84 @@ Fl_Image *Fl_RGB_Image::copy(int W, int H) {
new_image = new Fl_RGB_Image(new_array, W, H, d());
new_image->alloc_array = 1;
- // Scale the image using a nearest-neighbor algorithm...
- for (dy = H, sy = 0, yerr = H, new_ptr = new_array; dy > 0; dy --) {
- for (dx = W, xerr = W, old_ptr = array + sy * line_d; dx > 0; dx --) {
- for (c = 0; c < d(); c ++) *new_ptr++ = old_ptr[c];
+ if (scaling_ == FL_SCALING_NEAREST) {
+ // Scale the image using a nearest-neighbor algorithm...
+ for (dy = H, sy = 0, yerr = H, new_ptr = new_array; dy > 0; dy --) {
+ for (dx = W, xerr = W, old_ptr = array + sy * line_d; dx > 0; dx --) {
+ for (c = 0; c < d(); c ++) *new_ptr++ = old_ptr[c];
- old_ptr += xstep;
- xerr -= xmod;
+ old_ptr += xstep;
+ xerr -= xmod;
- if (xerr <= 0) {
- xerr += W;
- old_ptr += d();
+ if (xerr <= 0) {
+ xerr += W;
+ old_ptr += d();
+ }
+ }
+
+ sy += ystep;
+ yerr -= ymod;
+ if (yerr <= 0) {
+ yerr += H;
+ sy ++;
}
}
+ } else {
+ // Bilinear scaling
+ const float xscale = (w() - 1) / (float) W;
+ const float yscale = (h() - 1) / (float) H;
+ for (dy = 0; dy < H; dy++) {
+ float oldy = dy * yscale;
+ if (oldy >= h())
+ oldy = h() - 1;
+ const float yfract = oldy - (unsigned) oldy;
+
+ for (dx = 0; dx < W; dx++) {
+ new_ptr = new_array + dy * W * d() + dx * d();
+
+ float oldx = dx * xscale;
+ if (oldx >= w())
+ oldx = w() - 1;
+ const float xfract = oldx - (unsigned) oldx;
+
+ const unsigned leftx = oldx;
+ const unsigned lefty = oldy;
+ const unsigned rightx = oldx + 1 >= w() ? oldx : oldx + 1;
+ const unsigned righty = oldy;
+ const unsigned dleftx = oldx;
+ const unsigned dlefty = oldy + 1 >= h() ? oldy : oldy + 1;
+ const unsigned drightx = rightx;
+ const unsigned drighty = dlefty;
+
+ uchar left[4], right[4], downleft[4], downright[4];
+ memcpy(left, array + lefty * line_d + leftx * d(), d());
+ memcpy(right, array + righty * line_d + rightx * d(), d());
+ memcpy(downleft, array + dlefty * line_d + dleftx * d(), d());
+ memcpy(downright, array + drighty * line_d + drightx * d(), d());
+
+ // TODO: how to check if it's premultiplied alpha?
+ int i;
+ if (d() == 4) {
+ for (i = 0; i < 3; i++) {
+ left[i] *= left[3] / 255.0f;
+ right[i] *= right[3] / 255.0f;
+ downleft[i] *= downleft[3] / 255.0f;
+ downright[i] *= downright[3] / 255.0f;
+ }
+ }
+
+ const float leftf = 1 - xfract;
+ const float rightf = xfract;
+ const float upf = 1 - yfract;
+ const float downf = yfract;
- sy += ystep;
- yerr -= ymod;
- if (yerr <= 0) {
- yerr += H;
- sy ++;
+ for (i = 0; i < d(); i++) {
+ new_ptr[i] = (left[i] * leftf +
+ right[i] * rightf) * upf +
+ (downleft[i] * leftf +
+ downright[i] * rightf) * downf;
+ }
+ }
}
}
@@ -614,6 +674,13 @@ void Fl_RGB_Image::label(Fl_Menu_Item* m) {
m->label(_FL_IMAGE_LABEL, (const char*)this);
}
+void Fl_RGB_Image::scaling(Fl_RGB_Scaling method) {
+ scaling_ = method;
+}
+
+Fl_RGB_Scaling Fl_RGB_Image::scaling() {
+ return scaling_;
+}
//
// End of "$Id$".