summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FL/Fl_Image.H17
-rw-r--r--src/Fl_Image.cxx95
2 files changed, 98 insertions, 14 deletions
diff --git a/FL/Fl_Image.H b/FL/Fl_Image.H
index edba4fe29..7a1f4fdbc 100644
--- a/FL/Fl_Image.H
+++ b/FL/Fl_Image.H
@@ -154,6 +154,14 @@ class FL_EXPORT Fl_Image {
virtual void uncache();
};
+/// \enum Fl_RGB_Scaling
+/// The scaling algorithm to use.
+///
+enum Fl_RGB_Scaling {
+ FL_SCALING_NEAREST = 0,
+ FL_SCALING_BILINEAR
+};
+
/**
The Fl_RGB_Image class supports caching and drawing
of full-color images with 1 to 4 channels of color information.
@@ -170,6 +178,7 @@ class FL_EXPORT Fl_RGB_Image : public Fl_Image {
friend class Fl_GDI_Graphics_Driver;
friend class Fl_Xlib_Graphics_Driver;
static size_t max_size_;
+ static Fl_RGB_Scaling scaling_;
public:
const uchar *array;
@@ -230,6 +239,14 @@ public:
\sa void Fl_RGB_Image::max_size(size_t)
*/
static size_t max_size() {return max_size_;}
+
+ /** Sets the currently used scaling method.
+ Applies to all RGB images, defaults to FL_SCALING_NEAREST.
+ */
+ static void scaling(Fl_RGB_Scaling);
+
+ /** Returns the currently used scaling method. */
+ static Fl_RGB_Scaling scaling();
};
#endif // !Fl_Image_H
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$".