From 916b44e361f275555c5f22b9d91c973ccc089037 Mon Sep 17 00:00:00 2001 From: Manolo Gouy Date: Mon, 19 Mar 2018 17:43:18 +0000 Subject: New member function Fl_Image::scale(int width, int height) to set the FLTK size of an image. Each image has now two sizes implemented as follows: - the pixel size is stored in private members pixel_w_ and pixel_h_ with public accessors pixel_w() and pixel_h() - the FLTK size is stored in private members w_ and h_ and read by w() and h() - when the image is constructed, the two sizes have the same value - the protected w(int) and h(int) member functions set both FLTK and pixel sizes. - the public scale(int, int) member function is essentially nothing but set the FLTK size and don't change the pixel size. - when the image is drawn, its FLTK size determines how big it is drawn, its pixel size determines how much data are available to draw it. FLTK 1.3.4 with FL_ABI_VERSION=10304 contained an equivalent member function but only for the Fl_Shared_Image class. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.4@12776 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- src/Fl_Bitmap.cxx | 20 ++- src/Fl_Graphics_Driver.cxx | 89 ++++--------- src/Fl_Image.cxx | 116 ++++++++++++----- src/Fl_Pixmap.cxx | 16 +-- src/Fl_SVG_Image.cxx | 25 +--- src/Fl_Shared_Image.cxx | 59 +-------- src/drivers/GDI/Fl_GDI_Graphics_Driver.H | 4 +- src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx | 34 ++--- src/drivers/PostScript/Fl_PostScript_image.cxx | 138 ++++++++++++--------- src/drivers/Quartz/Fl_Quartz_Graphics_Driver.H | 5 +- .../Quartz/Fl_Quartz_Graphics_Driver_image.cxx | 34 ++--- src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H | 4 +- src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx | 66 +++++++--- 13 files changed, 292 insertions(+), 318 deletions(-) (limited to 'src') diff --git a/src/Fl_Bitmap.cxx b/src/Fl_Bitmap.cxx index c35a63538..4324b5367 100644 --- a/src/Fl_Bitmap.cxx +++ b/src/Fl_Bitmap.cxx @@ -125,7 +125,7 @@ int Fl_Bitmap::prepare(int XP, int YP, int WP, int HP, int &cx, int &cy, } if (fl_graphics_driver->start_image(this, XP,YP,WP,HP,cx,cy,X,Y,W,H)) return 1; if (!id_) - id_ = fl_graphics_driver->cache(this, w(), h(), array); + id_ = fl_graphics_driver->cache(this); return 0; } @@ -158,7 +158,7 @@ Fl_Image *Fl_Bitmap::copy(int W, int H) { uchar *new_array; // New array for image data // Optimize the simple copy where the width and height are the same... - if (W == w() && H == h()) { + if (W == pixel_w() && H == pixel_h()) { new_array = new uchar [H * ((W + 7) / 8)]; memcpy(new_array, array, H * ((W + 7) / 8)); @@ -182,10 +182,10 @@ Fl_Image *Fl_Bitmap::copy(int W, int H) { // Figure out Bresenham step/modulus values... - xmod = w() % W; - xstep = w() / W; - ymod = h() % H; - ystep = h() / H; + xmod = pixel_w() % W; + xstep = pixel_w() / W; + ymod = pixel_h() % H; + ystep = pixel_h() / H; // Allocate memory for the new image... new_array = new uchar [H * ((W + 7) / 8)]; @@ -196,7 +196,7 @@ Fl_Image *Fl_Bitmap::copy(int W, int H) { // 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 * ((w() + 7) / 8), sx = 0, new_bit = 1; + for (dx = W, xerr = W, old_ptr = array + sy * ((pixel_w() + 7) / 8), sx = 0, new_bit = 1; dx > 0; dx --) { old_bit = (uchar)(1 << (sx & 7)); @@ -230,12 +230,6 @@ Fl_Image *Fl_Bitmap::copy(int W, int H) { return new_image; } - -int Fl_Bitmap::draw_scaled(int X, int Y, int W, int H) { - return (W <= w() && H <= h()) ? fl_graphics_driver->draw_scaled(this, X, Y, W, H) : 0; -} - - // // End of "$Id$". // diff --git a/src/Fl_Graphics_Driver.cxx b/src/Fl_Graphics_Driver.cxx index d27bb3eaa..7655e1c27 100644 --- a/src/Fl_Graphics_Driver.cxx +++ b/src/Fl_Graphics_Driver.cxx @@ -70,7 +70,8 @@ void Fl_Graphics_Driver::focus_rect(int x, int y, int w, int h) } /** Draws an Fl_Image scaled to width \p W & height \p H with top-left corner at \em X,Y - \return zero when the graphics driver doesn't implement scaled drawing, non-zero if it does implement it. + \return zero when the graphics driver doesn't implement scaled drawing for the received image, + non-zero if it does implement it. */ int Fl_Graphics_Driver::draw_scaled(Fl_Image *img, int X, int Y, int W, int H) { return 0; @@ -194,29 +195,6 @@ void Fl_Graphics_Driver::uncache_pixmap(fl_uintptr_t p) { void Fl_Graphics_Driver::set_current_() { } - -/** Draws an Fl_Shared_Image object using this graphics driver. - \param shared shared image to be drawn - \param X,Y top-left position of the drawn image */ -void Fl_Graphics_Driver::draw(Fl_Shared_Image *shared, int X, int Y) { - if ( shared->w() == shared->image_->w() && shared->h() == shared->image_->h()) { - shared->image_->draw(X, Y, shared->w(), shared->h(), 0, 0); - return; - } - if ( shared->image_->draw_scaled(X, Y, shared->w(), shared->h()) ) return; - if (shared->scaled_image_ && (shared->scaled_image_->w() != shared->w() || shared->scaled_image_->h() != shared->h())) { - delete shared->scaled_image_; - shared->scaled_image_ = NULL; - } - if (!shared->scaled_image_) { - Fl_RGB_Scaling previous = Fl_Shared_Image::RGB_scaling(); - Fl_Shared_Image::RGB_scaling(shared->scaling_algorithm_); // useless but no harm if image_ is not an Fl_RGB_Image - shared->scaled_image_ = shared->image_->copy(shared->w(), shared->h()); - Fl_Shared_Image::RGB_scaling(previous); - } - shared->scaled_image_->draw(X, Y, shared->scaled_image_->w(), shared->scaled_image_->h(), 0, 0); -} - unsigned Fl_Graphics_Driver::font_desc_size() { return (unsigned)sizeof(Fl_Fontdesc); } @@ -348,22 +326,20 @@ void Fl_Scalable_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, i return; } // to allow rescale at runtime - if (*id(pxm)) { - if (*cache_scale(pxm) != scale_) { - pxm->uncache(); - } + if (*id(pxm) && *cache_scale(pxm) != scale_) { + pxm->uncache(); } if (!*id(pxm)) { - if (scale_ != 1) { // build a scaled id_ & pixmap_ for pxm - int w2=pxm->w(), h2=pxm->h(); - cache_size(pxm, w2, h2); + int w2=pxm->w(), h2=pxm->h(); + cache_size(pxm, w2, h2); // after this, w2 x h2 is size of desired cached image + if (pxm->pixel_w() != w2 || pxm->pixel_h() != h2) { // build a scaled id_ & pixmap_ for pxm Fl_Pixmap *pxm2 = (Fl_Pixmap*)pxm->copy(w2, h2); - *id(pxm) = cache(pxm2, pxm2->w(), pxm2->h(), pxm2->data()); + *id(pxm) = cache(pxm2); *cache_scale(pxm) = scale_; *mask(pxm) = *mask(pxm2); *mask(pxm2) = 0; delete pxm2; - } else *id(pxm) = cache(pxm, pxm->w(), pxm->h(), pxm->data()); + } else *id(pxm) = cache(pxm); } // draw pxm using its scaled id_ & pixmap_ draw_unscaled(pxm, scale_, X, Y, W, H, cx, cy); @@ -375,20 +351,18 @@ void Fl_Scalable_Graphics_Driver::draw(Fl_Bitmap *bm, int XP, int YP, int WP, in if (Fl_Graphics_Driver::start_image(bm, XP, YP, WP, HP, cx, cy, X, Y, W, H)) { return; } - if (*id(bm)) { - if (*cache_scale(bm) != scale_) { - bm->uncache(); - } + if (*id(bm) && *cache_scale(bm) != scale_) { + bm->uncache(); } if (!*id(bm)) { - if (scale_ != 1) { // build a scaled id_ for bm - int w2 = bm->w(), h2 = bm->h(); - cache_size(bm, w2, h2); + int w2 = bm->w(), h2 = bm->h(); + cache_size(bm, w2, h2); // after this, w2 x h2 is size of desired cached image + if (bm->pixel_w() != w2 || bm->pixel_h() != h2) { // build a scaled id_ for bm Fl_Bitmap *bm2 = (Fl_Bitmap*)bm->copy(w2, h2); - *id(bm) = cache(bm2, bm2->w(), bm2->h(), bm2->array); + *id(bm) = cache(bm2); *cache_scale(bm) = scale_; delete bm2; - } else *id(bm) = cache(bm, bm->w(), bm->h(), bm->array); + } else *id(bm) = cache(bm); } // draw bm using its scaled id_ draw_unscaled(bm, scale_, X, Y, W, H, cx, cy); @@ -404,7 +378,9 @@ void Fl_Scalable_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP if (start_image(img, XP, YP, WP, HP, cx, cy, XP, YP, WP, HP)) { return; } - if (scale() != 1 && can_do_alpha_blending()) { // try and use the system's scaled image drawing + int need_scaled_drawing = fabs(img->w() - img->pixel_w()/scale_)/img->w() > 0.05 || + fabs(img->h() - img->pixel_h()/scale_)/img->h() > 0.05; + if (need_scaled_drawing && can_do_alpha_blending()) { // try and use the system's scaled image drawing push_clip(XP, YP, WP, HP); int done = draw_scaled(img, XP-cx, YP-cy, img->w(), img->h()); pop_clip(); @@ -412,12 +388,15 @@ void Fl_Scalable_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP } // to allow rescale at runtime if (*id(img) && *cache_scale(img) != scale_) { - img->uncache(); + img->uncache(); } - if (!*id(img) && scale_ != 1) { // build and draw a scaled id_ for img + if (!*id(img) && need_scaled_drawing ) { // build and draw a scaled id_ for img int w2=img->w(), h2=img->h(); cache_size(img, w2, h2); + Fl_RGB_Scaling keep = Fl_Image::RGB_scaling(); + Fl_Image::RGB_scaling(Fl_Image::scaling_algorithm()); Fl_RGB_Image *img2 = (Fl_RGB_Image*)img->copy(w2, h2); + Fl_Image::RGB_scaling(keep); draw_unscaled(img2, scale_, XP, YP, WP, HP, cx, cy); *id(img) = *id(img2); *id(img2) = 0; @@ -430,23 +409,6 @@ void Fl_Scalable_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP } -void Fl_Scalable_Graphics_Driver::draw(Fl_Shared_Image *shared, int X, int Y) { - if (scale_ == 1) { - Fl_Graphics_Driver::draw(shared, X, Y); - return; - } - float s = scale_; scale_ = 1; - Fl_Region r2 = scale_clip(s); - int oldw=shared->w(); - int oldh=shared->h(); - change_image_size(shared, (oldw*s < 1 ? 1: int(oldw*s)), (oldh*s < 1 ? 1: int(oldh*s))); - Fl_Graphics_Driver::draw(shared, X*s, Y*s); - change_image_size(shared, oldw, oldh); - unscale_clip(r2); - scale_ = s; -} - - void Fl_Scalable_Graphics_Driver::font(Fl_Font face, Fl_Fontsize size) { if (!font_descriptor()) fl_open_display(); // to catch the correct initial value of scale_ font_unscaled(face, size * scale_); @@ -536,7 +498,10 @@ void Fl_Scalable_Graphics_Driver::draw_image_rescale(void *buf, Fl_Draw_Image_Cb } Fl_RGB_Image *rgb = new Fl_RGB_Image(tmp_buf, W, H, depth); rgb->alloc_array = 1; + Fl_RGB_Scaling keep = Fl_Image::RGB_scaling(); + Fl_Image::RGB_scaling(Fl_Image::scaling_algorithm()); Fl_RGB_Image *scaled_rgb = (Fl_RGB_Image*)rgb->copy(ceil(W * s), ceil(H * s)); + Fl_Image::RGB_scaling(keep); delete rgb; if (scaled_rgb) { Fl_Region r2 = scale_clip(s); diff --git a/src/Fl_Image.cxx b/src/Fl_Image.cxx index 2a01f8558..1276b0513 100644 --- a/src/Fl_Image.cxx +++ b/src/Fl_Image.cxx @@ -33,6 +33,7 @@ void fl_restore_clip(); // from fl_rect.cxx Fl_RGB_Scaling Fl_Image::RGB_scaling_ = FL_RGB_SCALING_NEAREST; +Fl_RGB_Scaling Fl_Image::scaling_algorithm_ = FL_RGB_SCALING_BILINEAR; /** The constructor creates an empty image with the specified @@ -42,6 +43,7 @@ Fl_RGB_Scaling Fl_Image::RGB_scaling_ = FL_RGB_SCALING_NEAREST; */ Fl_Image::Fl_Image(int W, int H, int D) : w_(W), h_(H), d_(D), ld_(0), count_(0), data_(0L) +, pixel_w_(W), pixel_h_(H) {} /** @@ -232,6 +234,66 @@ Fl_RGB_Scaling Fl_Image::RGB_scaling() { return RGB_scaling_; } +/** Sets the drawing size of the image. + This function gives the image its own drawing size, independently from its pixel size. + This can be useful to draw an image on a drawing surface with more than 1 pixel per + FLTK unit: all pixels of the original image become available to fill an area of the drawing surface + sized at width,height FLTK units. + Examples of such drawing surfaces: HiDPI displays, laser printers, PostScript files, PDF printers. + + \param width,height maximum width and height (in FLTK units) to use when drawing the image + \param proportional if not null, keep the width and height of the image proportional to those of the original size + \param can_expand if null, the width and height of the image will not exceed those of the original size + \version 1.4 (1.3.4 and FL_ABI_VERSION for Fl_Shared_Image only) + + Example code: scale an image to fit in a box + \code + Fl_Box *b = ... // a box + Fl_Image *img = Fl_Shared_Image::get("/path/to/picture.jpeg"); // read a picture file + img->scale(b->w(), b->h()); // set the drawing size of the image to the size of the box + b->image(img); // use the image as the box image + b->align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER | FL_ALIGN_CLIP); // the image is to be drawn centered in the box + \endcode + */ +void Fl_Image::scale(int width, int height, int proportional, int can_expand) +{ + if ((width <= pixel_w() && height <= pixel_h()) || can_expand) { + w_ = width; + h_ = height; + } + if (fail()) return; + if (!proportional && can_expand) return; + if (!proportional && width <= pixel_w() && height <= pixel_h()) return; + float fw = pixel_w() / float(width); + float fh = pixel_h() / float(height); + if (proportional) { + if (fh > fw) fw = fh; + else fh = fw; + } + if (!can_expand) { + if (fw < 1) fw = 1; + if (fh < 1) fh = 1; + } + w_ = int(pixel_w() / fw); + h_ = int(pixel_h() / fh); +} + +/** Draw the image to the current drawing surface rescaled to a given width and height. + Deprecated. Only for API compatibility with FLTK 1.3.4. + Intended for internal use by the FLTK library. + \param X,Y position of the image's top-left + \param W,H width and height for the drawn image + \return 1 + */ +int Fl_Image::draw_scaled(int X, int Y, int W, int H) { + // transiently set image drawing size to WxH + int width = w(), height = h(); + scale(W, H, 0, 1); + draw(X, Y, W, H, 0, 0); + scale(width, height, 0, 1); + return 1; +} + // // RGB image class... @@ -334,29 +396,29 @@ Fl_Image *Fl_RGB_Image::copy(int W, int H) { // Optimize the simple copy where the width and height are the same, // or when we are copying an empty image... - if ((W == w() && H == h()) || + if ((W == pixel_w() && H == pixel_h()) || !w() || !h() || !d() || !array) { if (array) { // Make a copy of the image data and return a new Fl_RGB_Image... - new_array = new uchar[w() * h() * d()]; - if (ld() && ld()!=w()*d()) { + new_array = new uchar[pixel_w() * pixel_h() * d()]; + if (ld() && ld()!=pixel_w()*d()) { const uchar *src = array; uchar *dst = new_array; - int dy, dh = h(), wd = w()*d(), wld = ld(); + int dy, dh = h(), wd = pixel_w()*d(), wld = ld(); for (dy=0; dyalloc_array = 1; return new_image; } else { - return new Fl_RGB_Image(array, w(), h(), d(), ld()); + return new Fl_RGB_Image(array, pixel_w(), pixel_h(), d(), ld()); } } if (W <= 0 || H <= 0) return 0; @@ -372,7 +434,7 @@ 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; - line_d = ld() ? ld() : w() * d(); + line_d = ld() ? ld() : pixel_w() * d(); if (Fl_Image::RGB_scaling() == FL_RGB_SCALING_NEAREST) { @@ -383,10 +445,10 @@ Fl_Image *Fl_RGB_Image::copy(int W, int H) { xstep, ystep; // X & Y step increments // Figure out Bresenham step/modulus values... - xmod = w() % W; - xstep = (w() / W) * d(); - ymod = h() % H; - ystep = h() / H; + xmod = pixel_w() % W; + xstep = (pixel_w() / W) * d(); + ymod = pixel_h() % H; + ystep = pixel_h() / H; // Scale the image using a nearest-neighbor algorithm... for (dy = H, sy = 0, yerr = H, new_ptr = new_array; dy > 0; dy --) { @@ -411,28 +473,28 @@ Fl_Image *Fl_RGB_Image::copy(int W, int H) { } } else { // Bilinear scaling (FL_RGB_SCALING_BILINEAR) - const float xscale = (w() - 1) / (float) W; - const float yscale = (h() - 1) / (float) H; + const float xscale = (pixel_w() - 1) / (float) W; + const float yscale = (pixel_h() - 1) / (float) H; for (dy = 0; dy < H; dy++) { float oldy = dy * yscale; - if (oldy >= h()) - oldy = float(h() - 1); + if (oldy >= pixel_h()) + oldy = float(pixel_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 = float(w() - 1); + if (oldx >= pixel_w()) + oldx = float(pixel_w() - 1); const float xfract = oldx - (unsigned) oldx; const unsigned leftx = (unsigned)oldx; const unsigned lefty = (unsigned)oldy; - const unsigned rightx = (unsigned)(oldx + 1 >= w() ? oldx : oldx + 1); + const unsigned rightx = (unsigned)(oldx + 1 >= pixel_w() ? oldx : oldx + 1); const unsigned righty = (unsigned)oldy; const unsigned dleftx = (unsigned)oldx; - const unsigned dlefty = (unsigned)(oldy + 1 >= h() ? oldy : oldy + 1); + const unsigned dlefty = (unsigned)(oldy + 1 >= pixel_h() ? oldy : oldy + 1); const unsigned drightx = (unsigned)rightx; const unsigned drighty = (unsigned)dlefty; @@ -586,20 +648,6 @@ void Fl_RGB_Image::label(Fl_Menu_Item* m) { m->label(FL_IMAGE_LABEL, (const char*)this); } -int Fl_RGB_Image::draw_scaled(int X, int Y, int W, int H) { - return fl_graphics_driver->draw_scaled(this, X, Y, W, H); -} - -/** Attempts to draw the image to the current drawing surface rescaled to a given width and height. - This virtual member function is mostly intended for use by the FLTK library. - \param X,Y position of the image's top-left - \param W,H width and height for the drawn image - \return 0 if scaled drawing is not implemented for this image, non-zero if it is implemented. - */ -int Fl_Image::draw_scaled(int X, int Y, int W, int H) { - return 0; -} - // // End of "$Id$". // diff --git a/src/Fl_Pixmap.cxx b/src/Fl_Pixmap.cxx index 54410a401..21d9e87a3 100644 --- a/src/Fl_Pixmap.cxx +++ b/src/Fl_Pixmap.cxx @@ -64,7 +64,7 @@ int Fl_Pixmap::prepare(int XP, int YP, int WP, int HP, int &cx, int &cy, } if ( fl_graphics_driver->start_image(this, XP,YP,WP,HP,cx,cy,X,Y,W,H) ) return 1; if (!id_) { - id_ = fl_graphics_driver->cache(this, w(), h(), data()); + id_ = fl_graphics_driver->cache(this); } return 0; } @@ -153,7 +153,7 @@ Fl_Image *Fl_Pixmap::copy(int W, int H) { return new Fl_Pixmap((char *const*)0); } // Optimize the simple copy where the width and height are the same... - if (W == w() && H == h()) { + if (W == pixel_w() && H == pixel_h()) { // Make an exact copy of the image and return it... new_image = new Fl_Pixmap(data()); new_image->copy_data(); @@ -185,10 +185,10 @@ Fl_Image *Fl_Pixmap::copy(int W, int H) { sprintf(new_info, "%d %d %d %d", W, H, ncolors, chars_per_pixel); // Figure out Bresenham step/modulus values... - xmod = w() % W; - xstep = (w() / W) * chars_per_pixel; - ymod = h() % H; - ystep = h() / H; + xmod = pixel_w() % W; + xstep = (pixel_w() / W) * chars_per_pixel; + ymod = pixel_h() % H; + ystep = pixel_h() / H; // Allocate memory for the new array... if (ncolors < 0) new_data = new char *[H + 2]; @@ -395,10 +395,6 @@ void Fl_Pixmap::desaturate() { } } -int Fl_Pixmap::draw_scaled(int X, int Y, int W, int H) { - return (W <= w() && H <= h()) ? fl_graphics_driver->draw_scaled(this, X, Y, W, H) : 0; -} - // // End of "$Id$". // diff --git a/src/Fl_SVG_Image.cxx b/src/Fl_SVG_Image.cxx index 3c528170c..a0116ba53 100644 --- a/src/Fl_SVG_Image.cxx +++ b/src/Fl_SVG_Image.cxx @@ -193,7 +193,6 @@ void Fl_SVG_Image::rasterize_(int W, int H) { rasterized_ = true; raster_w_ = W; raster_h_ = H; -//printf("rasterize to %dx%d\n",W, H); } @@ -235,10 +234,7 @@ void Fl_SVG_Image::resize(int width, int height) { void Fl_SVG_Image::draw(int X, int Y, int W, int H, int cx, int cy) { - float f = 1; - if (Fl_Surface_Device::surface() == Fl_Display_Device::display_device()) { - f = Fl::screen_driver()->retina_factor() * fl_graphics_driver->scale(); - } + float f = Fl::screen_driver()->retina_factor() * fl_graphics_driver->scale(); int w1 = w(), h1 = h(); /* When f > 1, there may be several pixels per FLTK unit in an area of size w() x h() of the display. This occurs, e.g., with Apple retina displays @@ -248,15 +244,8 @@ void Fl_SVG_Image::draw(int X, int Y, int W, int H, int cx, int cy) { the SVG image is drawn using the full resolution of the display. */ resize(f*w(), f*h()); - if (f == 1) { - Fl_RGB_Image::draw(X, Y, W, H, cx, cy); - } else { - bool need_clip = (cx || cy || W != w1 || H != h1); - if (need_clip) fl_push_clip(X, Y, W, H); - fl_graphics_driver->draw_scaled(this, X-cx, Y-cy, w1, h1); - if (need_clip) fl_pop_clip(); - w(w1); h(h1); // restore the previous image size - } + scale(w1, h1, 0, 1); + Fl_RGB_Image::draw(X, Y, W, H, cx, cy); } @@ -272,14 +261,6 @@ void Fl_SVG_Image::color_average(Fl_Color c, float i) { Fl_RGB_Image::color_average(c, i); } - -int Fl_SVG_Image::draw_scaled(int X, int Y, int W, int H) { - w(W); - h(H); - draw(X, Y, W, H, 0, 0); - return 1; -} - #endif // FLTK_USE_NANOSVG // diff --git a/src/Fl_Shared_Image.cxx b/src/Fl_Shared_Image.cxx index b2e00f6b3..e8cfb3fb9 100644 --- a/src/Fl_Shared_Image.cxx +++ b/src/Fl_Shared_Image.cxx @@ -123,7 +123,6 @@ Fl_Shared_Image::Fl_Shared_Image() : Fl_Image(0,0,0) { original_ = 0; image_ = 0; alloc_image_ = 0; - scaled_image_= 0; } @@ -144,7 +143,6 @@ Fl_Shared_Image::Fl_Shared_Image(const char *n, // I - Filename image_ = img; alloc_image_ = !img; original_ = 1; - scaled_image_= 0; if (!img) reload(); else update(); @@ -211,7 +209,6 @@ Fl_Shared_Image::update() { Fl_Shared_Image::~Fl_Shared_Image() { if (name_) delete[] (char *)name_; if (alloc_image_) delete image_; - delete scaled_image_; } @@ -357,7 +354,6 @@ Fl_Shared_Image::desaturate() { update(); } - // // 'Fl_Shared_Image::draw()' - Draw a shared image... // @@ -366,59 +362,14 @@ void Fl_Shared_Image::draw(int X, int Y, int W, int H, int cx, int cy) { Fl_Image::draw(X, Y, W, H, cx, cy); return; } - bool need_clip = (W != w() || H != h() || cx || cy); - if (need_clip) fl_push_clip(X, Y, W, H); - fl_graphics_driver->draw(this, X-cx, Y-cy); - if (need_clip) fl_pop_clip(); -} - - -/** Sets the drawing size of the shared image. - This function gives the shared image its own size, independently from the size of the original image - that is typically larger. - This can be useful to draw a shared image on a drawing surface with more than 1 pixel per - FLTK unit: all pixels of the original image become available to fill an area of the drawing surface - sized at width,height FLTK units. - Examples of such drawing surfaces: HiDPI displays, laser printers, PostScript files, PDF printers. - - \param width,height maximum width and height (in FLTK units) to use when drawing the shared image - \param proportional if not null, keep the width and height of the shared image proportional to those of its original image - \param can_expand if null, the width and height of the shared image will not exceed those of the original image - - \version 1.3.4 - - Example code: scale an image to fit in a box - \code - Fl_Box *b = ... // a box - Fl_Shared_Image *shared = Fl_Shared_Image::get("/path/to/picture.jpeg"); // read a picture file - shared->scale(b->w(), b->h()); // set the drawing size of the shared image to the size of the box - b->image(shared); // use the shared image as the box image - b->align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER | FL_ALIGN_CLIP); // the image is to be drawn centered in the box - \endcode - */ -void Fl_Shared_Image::scale(int width, int height, int proportional, int can_expand) -{ - w(width); - h(height); - if (!image_ || image_->fail()) return; - if (!proportional && can_expand) return; - if (!proportional && width <= image_->w() && height <= image_->h()) return; - float fw = image_->w() / float(width); - float fh = image_->h() / float(height); - if (proportional) { - if (fh > fw) fw = fh; - else fh = fw; - } - if (!can_expand) { - if (fw < 1) fw = 1; - if (fh < 1) fh = 1; - } - w(int(image_->w() / fw)); - h(int(image_->h() / fh)); + // transiently set the drawing size of image_ to that of the shared image + int width = image_->w(), height = image_->h(); + image_->scale(w(), h(), 0, 1); + image_->draw(X, Y, W, H, cx, cy); + image_->scale(width, height, 0, 1); } -Fl_RGB_Scaling Fl_Shared_Image::scaling_algorithm_ = FL_RGB_SCALING_BILINEAR; // diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver.H b/src/drivers/GDI/Fl_GDI_Graphics_Driver.H index 5bfd9b515..f6554a076 100644 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver.H +++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver.H @@ -72,9 +72,9 @@ public: virtual void draw_image_unscaled(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3); virtual void draw_image_mono_unscaled(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0); virtual void draw_image_mono_unscaled(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1); - fl_uintptr_t cache(Fl_Pixmap *img, int w, int h, const char *const*array); + fl_uintptr_t cache(Fl_Pixmap *img); virtual void uncache_pixmap(fl_uintptr_t p); - fl_uintptr_t cache(Fl_Bitmap *img, int w, int h, const uchar *array); + fl_uintptr_t cache(Fl_Bitmap *img); void uncache(Fl_RGB_Image *img, fl_uintptr_t &id_, fl_uintptr_t &mask_); virtual double width_unscaled(const char *str, int n); virtual double width_unscaled(unsigned int c); diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx index 31d308464..349775aad 100644 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx +++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx @@ -463,7 +463,7 @@ void Fl_GDI_Printer_Graphics_Driver::draw_unscaled(Fl_Bitmap *bm, float s, int X fl_end_offscreen(); // offscreen data is in tmp_id SelectObject(tempdc, (HGDIOBJ)tmp_id); // use offscreen data // draw it to printer context with background color as transparent - fl_TransparentBlt(gc_, X,Y,W,H, tempdc, cx, cy, bm->w(), bm->h(), RGB(r, g, b) ); + fl_TransparentBlt(gc_, X,Y,W,H, tempdc, cx, cy, bm->pixel_w(), bm->pixel_h(), RGB(r, g, b) ); fl_delete_offscreen(tmp_id); RestoreDC(tempdc, save); DeleteDC(tempdc); @@ -472,14 +472,14 @@ void Fl_GDI_Printer_Graphics_Driver::draw_unscaled(Fl_Bitmap *bm, float s, int X static Fl_Offscreen build_id(Fl_RGB_Image *img, void **pmask) { - Fl_Image_Surface *surface = new Fl_Image_Surface(img->w(), img->h()); + Fl_Image_Surface *surface = new Fl_Image_Surface(img->pixel_w(), img->pixel_h()); Fl_Surface_Device::push_current(surface); if ((img->d() == 2 || img->d() == 4) && fl_can_do_alpha_blending()) { - fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d()|FL_IMAGE_WITH_ALPHA, img->ld()); + fl_draw_image(img->array, 0, 0, img->pixel_w(), img->pixel_h(), img->d()|FL_IMAGE_WITH_ALPHA, img->ld()); } else { - fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d(), img->ld()); + fl_draw_image(img->array, 0, 0, img->pixel_w(), img->pixel_h(), img->d(), img->ld()); if (img->d() == 2 || img->d() == 4) { - *pmask = fl_create_alphamask(img->w(), img->h(), img->d(), img->ld(), img->array); + *pmask = fl_create_alphamask(img->pixel_w(), img->pixel_h(), img->d(), img->ld(), img->array); } } Fl_Surface_Device::pop_current(); @@ -494,6 +494,8 @@ void Fl_GDI_Graphics_Driver::draw_unscaled(Fl_RGB_Image *img, float s, int X, in Y = Y*s; cache_size(img, W, H); cx *= s; cy *= s; + if (W + cx > img->pixel_w()) W = img->pixel_w() - cx; + if (H + cy > img->pixel_h()) H = img->pixel_h() - cy; if (!*Fl_Graphics_Driver::id(img)) { *Fl_Graphics_Driver::id(img) = (fl_uintptr_t)build_id(img, (void**)(Fl_Graphics_Driver::mask(img))); *cache_scale(img) = 1; @@ -519,13 +521,13 @@ void Fl_GDI_Graphics_Driver::draw_unscaled(Fl_RGB_Image *img, float s, int X, in int Fl_GDI_Printer_Graphics_Driver::draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP) { XFORM old_tr, tr; GetWorldTransform(gc_, &old_tr); // storing old transform - tr.eM11 = float(WP)/float(img->w()); - tr.eM22 = float(HP)/float(img->h()); + tr.eM11 = float(WP)/float(img->pixel_w()); + tr.eM22 = float(HP)/float(img->pixel_h()); tr.eM12 = tr.eM21 = 0; tr.eDx = float(XP); tr.eDy = float(YP); ModifyWorldTransform(gc_, &tr, MWT_LEFTMULTIPLY); - img->draw(0, 0, img->w(), img->h(), 0, 0); + img->draw(0, 0, img->pixel_w(), img->pixel_h(), 0, 0); SetWorldTransform(gc_, &old_tr); return 1; } @@ -546,10 +548,10 @@ int Fl_GDI_Graphics_Driver::draw_scaled(Fl_Image *img, int XP, int YP, int WP, i int save = SaveDC(new_gc); SelectObject(new_gc, (HBITMAP)*Fl_Graphics_Driver::id(rgb)); if ( (rgb->d() % 2) == 0 ) { - alpha_blend_(XP*scale_, YP*scale_, WP, HP, new_gc, 0, 0, rgb->w(), rgb->h()); + alpha_blend_(XP*scale_, YP*scale_, WP, HP, new_gc, 0, 0, rgb->pixel_w(), rgb->pixel_h()); } else { SetStretchBltMode(gc_, HALFTONE); - StretchBlt(gc_, XP*scale_, YP*scale_, WP, HP, new_gc, 0, 0, rgb->w(), rgb->h(), SRCCOPY); + StretchBlt(gc_, XP*scale_, YP*scale_, WP, HP, new_gc, 0, 0, rgb->pixel_w(), rgb->pixel_h(), SRCCOPY); } RestoreDC(new_gc, save); DeleteDC(new_gc); @@ -597,9 +599,9 @@ static Fl_Bitmask fl_create_bitmap(int w, int h, const uchar *data) { return bm; } -fl_uintptr_t Fl_GDI_Graphics_Driver::cache(Fl_Bitmap *bm, int w, int h, const uchar *array) { +fl_uintptr_t Fl_GDI_Graphics_Driver::cache(Fl_Bitmap *bm) { *cache_scale(bm) = Fl_Scalable_Graphics_Driver::scale(); - return (fl_uintptr_t)fl_create_bitmap(w, h, array); + return (fl_uintptr_t)fl_create_bitmap(bm->pixel_w(), bm->pixel_h(), bm->array); } void Fl_GDI_Graphics_Driver::draw_unscaled(Fl_Pixmap *pxm, float s, int X, int Y, int W, int H, int cx, int cy) { @@ -643,16 +645,16 @@ void Fl_GDI_Printer_Graphics_Driver::draw_unscaled(Fl_Pixmap *pxm, float s, int } -fl_uintptr_t Fl_GDI_Graphics_Driver::cache(Fl_Pixmap *img, int w, int h, const char *const*data) { - Fl_Image_Surface *surf = new Fl_Image_Surface(w, h); +fl_uintptr_t Fl_GDI_Graphics_Driver::cache(Fl_Pixmap *img) { + Fl_Image_Surface *surf = new Fl_Image_Surface(img->pixel_w(), img->pixel_h()); Fl_Surface_Device::push_current(surf); uchar *bitmap = 0; Fl_Surface_Device::surface()->driver()->mask_bitmap(&bitmap); - fl_draw_pixmap(data, 0, 0, FL_BLACK); + fl_draw_pixmap(img->data(), 0, 0, FL_BLACK); *Fl_Graphics_Driver::pixmap_bg_color(img) = Fl_WinAPI_System_Driver::win_pixmap_bg_color; // computed by fl_draw_pixmap() Fl_Surface_Device::surface()->driver()->mask_bitmap(0); if (bitmap) { - *Fl_Graphics_Driver::mask(img) = (fl_uintptr_t)fl_create_bitmask(w, h, bitmap); + *Fl_Graphics_Driver::mask(img) = (fl_uintptr_t)fl_create_bitmask(img->pixel_w(), img->pixel_h(), bitmap); delete[] bitmap; } Fl_Surface_Device::pop_current(); diff --git a/src/drivers/PostScript/Fl_PostScript_image.cxx b/src/drivers/PostScript/Fl_PostScript_image.cxx index 579375ebc..49cb9cebe 100644 --- a/src/drivers/PostScript/Fl_PostScript_image.cxx +++ b/src/drivers/PostScript/Fl_PostScript_image.cxx @@ -572,33 +572,44 @@ void Fl_PostScript_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb call, void void Fl_PostScript_Graphics_Driver::draw(Fl_Pixmap * pxm,int XP, int YP, int WP, int HP, int cx, int cy){ - const char * const * di =pxm->data(); - int w,h; - if (!fl_measure_pixmap(di, w, h)) return; - mask=0; - mask_bitmap(&mask); - mx = WP; - my = HP; - push_clip(XP, YP, WP, HP); - fl_draw_pixmap(di,XP -cx, YP -cy, FL_BLACK ); - pop_clip(); - delete[] mask; - mask=0; - mask_bitmap(0); + int need_clip = cx || cy || WP != pxm->w() || HP != pxm->h(); + if (need_clip) push_clip(XP, YP, WP, HP); + if (pxm->w() != pxm->pixel_w() || pxm->h() != pxm->pixel_h()) { + draw_scaled(pxm, XP-cx, YP-cy, pxm->w(), pxm->h()); + } else { + const char * const * di =pxm->data(); + int w,h; + if (!fl_measure_pixmap(di, w, h)) return; + mask=0; + mask_bitmap(&mask); + mx = WP; + my = HP; + fl_draw_pixmap(di, XP -cx, YP -cy, FL_BLACK); + delete[] mask; + mask=0; + mask_bitmap(0); + } + if (need_clip) pop_clip(); } -void Fl_PostScript_Graphics_Driver::draw(Fl_RGB_Image * rgb,int XP, int YP, int WP, int HP, int cx, int cy){ - const uchar * di = rgb->array; - int w = rgb->w(); - int h = rgb->h(); - mask=0; - if (lang_level_>2) //when not true, not making alphamask, mixing colors instead... - if (alpha_mask(di, w, h, rgb->d(),rgb->ld())) return; //everthing masked, no need for painting! - push_clip(XP, YP, WP, HP); - draw_image(di, XP + cx, YP + cy, w, h, rgb->d(), rgb->ld()); - pop_clip(); - delete[]mask; - mask=0; +void Fl_PostScript_Graphics_Driver::draw(Fl_RGB_Image * rgb,int XP, int YP, int WP, int HP, int cx, int cy) +{ + int need_clip = cx || cy || WP != rgb->w() || HP != rgb->h(); + if (need_clip) push_clip(XP, YP, WP, HP); + if (rgb->w() != rgb->pixel_w() || rgb->h() != rgb->pixel_h()) { + draw_scaled(rgb, XP-cx, YP-cy, rgb->w(), rgb->h()); + } else { + const uchar * di = rgb->array; + int w = rgb->w(); + int h = rgb->h(); + mask=0; + if (lang_level_>2) //when not true, not making alphamask, mixing colors instead... + if (alpha_mask(di, w, h, rgb->d(),rgb->ld())) return; //everthing masked, no need for painting! + draw_image(di, XP + cx, YP + cy, w, h, rgb->d(), rgb->ld()); + delete[]mask; + mask=0; + } + if (need_clip) pop_clip(); } int Fl_PostScript_Graphics_Driver::draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP){ @@ -607,48 +618,55 @@ int Fl_PostScript_Graphics_Driver::draw_scaled(Fl_Image *img, int XP, int YP, in if (W == 0 || H == 0) return 1; push_no_clip(); // remove the FLTK clip that can't be rescaled clocale_printf("%d %d %i %i CL\n", X, Y, W, H); - clocale_printf("GS %d %d TR %f %f SC GS\n", XP, YP, float(WP)/img->w(), float(HP)/img->h()); - if (img->as_rgb_image()) draw(img->as_rgb_image(), 0, 0, img->w(), img->h(), 0, 0); - else img->draw(0, 0, img->w(), img->h(), 0, 0); + clocale_printf("GS %d %d TR %f %f SC GS\n", XP, YP, float(WP)/img->pixel_w(), float(HP)/img->pixel_h()); + int keep_w = img->w(), keep_h = img->h(); + img->scale(img->pixel_w(), img->pixel_h(), 0, 1); + img->draw(0, 0, img->pixel_w(), img->pixel_h(), 0, 0); clocale_printf("GR GR\n"); + img->scale(keep_w, keep_h, 0, 1); pop_clip(); // restore FLTK's clip return 1; } -void Fl_PostScript_Graphics_Driver::draw(Fl_Bitmap * bitmap,int XP, int YP, int WP, int HP, int cx, int cy){ - const uchar * di = bitmap->array; - int w,h; - int LD=(bitmap->w()+7)/8; - int xx; - - if (WP> bitmap->w() - cx){// to assure that it does not go out of bounds; - w = bitmap->w() - cx; - xx = (bitmap->w()+7)/8 - cx/8; //length of mask in bytes - }else{ - w =WP; - xx = (w+7)/8 - cx/8; - } - if ( HP > bitmap->h()-cy) - h = bitmap->h() - cy; - else - h = HP; - - di += cy*LD + cx/8; - int si = cx % 8; // small shift to be clipped, it is simpler than shifting whole mask - - int i,j; - push_clip(XP, YP, WP, HP); - fprintf(output , "%i %i %i %i %i %i MI\n", XP - si, YP + HP , WP , -HP , w , h); - - void *rle85 = prepare_rle85(); - for (j=0; jw() || HP != bitmap->h(); + if (need_clip) push_clip(XP, YP, WP, HP); + if (bitmap->w() != bitmap->pixel_w() || bitmap->h() != bitmap->pixel_h()) { + draw_scaled(bitmap, XP-cx, YP-cy, bitmap->w(), bitmap->h()); + } else { + const uchar * di = bitmap->array; + int w,h; + int LD=(bitmap->w()+7)/8; + int xx; + + if (WP> bitmap->w() - cx){// to assure that it does not go out of bounds; + w = bitmap->w() - cx; + xx = (bitmap->w()+7)/8 - cx/8; //length of mask in bytes + }else{ + w =WP; + xx = (w+7)/8 - cx/8; + } + if ( HP > bitmap->h()-cy) + h = bitmap->h() - cy; + else + h = HP; + + di += cy*LD + cx/8; + int si = cx % 8; // small shift to be clipped, it is simpler than shifting whole mask + + int i,j; + fprintf(output , "%i %i %i %i %i %i MI\n", XP - si, YP + HP , WP , -HP , w , h); + + void *rle85 = prepare_rle85(); + for (j=0; jd()<=2 ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB(); int ld = img->ld(); - if (!ld) ld = img->w() * img->d(); + if (!ld) ld = img->pixel_w() * img->d(); CGDataProviderRef src; if ( has_feature(PRINTER) ) { // When printing, the data at img->array are used when the printed page is completed, @@ -172,16 +172,16 @@ void Fl_Quartz_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, // is used to avoid repeating the copy operation if img is printed again. // The CGImage data provider deletes the copy at the latest of these two events: // deletion of img, and completion of the page where img was printed. - size_t total = ld * img->h(); + size_t total = ld * img->pixel_h(); uchar *copy = new uchar[total]; memcpy(copy, img->array, total); src = CGDataProviderCreateWithData(NULL, copy, total, dataReleaseCB); *Fl_Graphics_Driver::mask(img) = 1; } else { // the CGImage data provider must not release the image data. - src = CGDataProviderCreateWithData(NULL, img->array, ld * img->h(), NULL); + src = CGDataProviderCreateWithData(NULL, img->array, ld * img->pixel_h(), NULL); } - cgimg = CGImageCreate(img->w(), img->h(), 8, img->d()*8, ld, + cgimg = CGImageCreate(img->pixel_w(), img->pixel_h(), 8, img->d()*8, ld, lut, (img->d()&1)?kCGImageAlphaNone:kCGImageAlphaLast, src, 0L, false, kCGRenderingIntentDefault); *Fl_Graphics_Driver::id(img) = (fl_uintptr_t)cgimg; @@ -193,22 +193,6 @@ void Fl_Quartz_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, } } -int Fl_Quartz_Graphics_Driver::draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP) { - int X, Y, W, H; - fl_clip_box(XP,YP,WP,HP,X,Y,W,H); // X,Y,W,H will give the unclipped area of XP,YP,WP,HP - if (W == 0 || H == 0) return 1; - fl_push_no_clip(); // remove the FLTK clip that can't be rescaled - CGContextSaveGState(gc_); - CGContextClipToRect(gc_, CGRectMake(X, Y, W, H)); // this clip path will be rescaled & translated - CGContextTranslateCTM(gc_, XP, YP); - CGContextScaleCTM(gc_, float(WP)/img->w(), float(HP)/img->h()); - if (img->as_rgb_image()) draw(img->as_rgb_image(), 0, 0, img->w(), img->h(), 0, 0); - else img->draw(0, 0, img->w(), img->h(), 0, 0); - CGContextRestoreGState(gc_); - fl_pop_clip(); // restore FLTK's clip - return 1; -} - void Fl_Quartz_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) { int X, Y, W, H; if (Fl_Graphics_Driver::prepare(pxm, XP, YP, WP, HP, cx, cy, X, Y, W, H)) return; @@ -245,8 +229,8 @@ void Fl_Quartz_Graphics_Driver::uncache(Fl_RGB_Image*, fl_uintptr_t &id_, fl_uin } } -fl_uintptr_t Fl_Quartz_Graphics_Driver::cache(Fl_Bitmap*, int w, int h, const uchar *array) { - return (fl_uintptr_t)create_bitmask(w, h, array); +fl_uintptr_t Fl_Quartz_Graphics_Driver::cache(Fl_Bitmap *bm) { + return (fl_uintptr_t)create_bitmask(bm->pixel_w(), bm->pixel_h(), bm->array); } @@ -254,10 +238,10 @@ static void pmProviderRelease (void *ctxt, const void *data, size_t size) { CFRelease(ctxt); } -fl_uintptr_t Fl_Quartz_Graphics_Driver::cache(Fl_Pixmap *img, int w, int h, const char *const*data) { - Fl_Image_Surface *surf = new Fl_Image_Surface(w, h); +fl_uintptr_t Fl_Quartz_Graphics_Driver::cache(Fl_Pixmap *img) { + Fl_Image_Surface *surf = new Fl_Image_Surface(img->pixel_w(), img->pixel_h()); Fl_Surface_Device::push_current(surf); - fl_draw_pixmap(data, 0, 0, FL_BLACK); + fl_draw_pixmap(img->data(), 0, 0, FL_BLACK); CGContextRef src = surf->get_offscreen_before_delete(); Fl_Surface_Device::pop_current(); delete surf; diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H index a20ec1dd3..7d74b70e1 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H @@ -122,9 +122,9 @@ public: virtual void draw_unscaled(int angle, const char *str, int n, int x, int y); virtual void rtl_draw_unscaled(const char* str, int n, int x, int y); virtual void font_unscaled(Fl_Font face, Fl_Fontsize size); - fl_uintptr_t cache(Fl_Pixmap *img, int w, int h, const char *const*array); + fl_uintptr_t cache(Fl_Pixmap *img); virtual void uncache_pixmap(fl_uintptr_t p); - fl_uintptr_t cache(Fl_Bitmap *img, int w, int h, const uchar *array); + fl_uintptr_t cache(Fl_Bitmap *img); void uncache(Fl_RGB_Image *img, fl_uintptr_t &id_, fl_uintptr_t &mask_); virtual double width_unscaled(const char *str, int n); virtual double width_unscaled(unsigned int c); diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx index 901ec0078..baa0cc7c3 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx @@ -58,6 +58,8 @@ # include "../../flstring.h" #if HAVE_XRENDER #include +// set this to 1 to activate experimental way to cache RGB images with Xrender Picture instead of X11 Pixmap +#define USE_XRENDER_PICTURE 0 #endif static XImage xi; // template used to pass info to X @@ -643,7 +645,7 @@ void Fl_Xlib_Graphics_Driver::draw_unscaled(Fl_Bitmap *bm, float s, int X, int Y // alpha compositing... static void alpha_blend(Fl_RGB_Image *img, int X, int Y, int W, int H, int cx, int cy) { int ld = img->ld(); - if (ld == 0) ld = img->w() * img->d(); + if (ld == 0) ld = img->pixel_w() * img->d(); uchar *srcptr = (uchar*)img->array + cy * ld + cx * img->d(); int srcskip = ld - img->d() * W; @@ -700,19 +702,30 @@ static Fl_Offscreen cache_rgb(Fl_RGB_Image *img) { Fl_Image_Surface *surface; int depth = img->d(); if (depth == 1 || depth == 3) { - surface = new Fl_Image_Surface(img->w(), img->h()); + surface = new Fl_Image_Surface(img->pixel_w(), img->pixel_h()); } else if (fl_can_do_alpha_blending()) { - Fl_Offscreen pixmap = XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), img->w(), img->h(), 32); - surface = new Fl_Image_Surface(img->w(), img->h(), 0, pixmap); + Fl_Offscreen pixmap = XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), img->pixel_w(), img->pixel_h(), 32); + surface = new Fl_Image_Surface(img->pixel_w(), img->pixel_h(), 0, pixmap); depth |= FL_IMAGE_WITH_ALPHA; } else { return 0; } Fl_Surface_Device::push_current(surface); - fl_draw_image(img->array, 0, 0, img->w(), img->h(), depth, img->ld()); + fl_draw_image(img->array, 0, 0, img->pixel_w(), img->pixel_h(), depth, img->ld()); Fl_Surface_Device::pop_current(); Fl_Offscreen off = surface->get_offscreen_before_delete(); delete surface; +#if HAVE_XRENDER && USE_XRENDER_PICTURE + if (fl_can_do_alpha_blending()) { + XRenderPictureAttributes srcattr; + memset(&srcattr, 0, sizeof(XRenderPictureAttributes)); + static XRenderPictFormat *fmt32 = XRenderFindStandardFormat(fl_display, PictStandardARGB32); + static XRenderPictFormat *fmt24 = XRenderFindStandardFormat(fl_display, PictStandardRGB24); + Picture pict = XRenderCreatePicture(fl_display, off, (depth%2==0 ? fmt32:fmt24), 0, &srcattr); + XFreePixmap(fl_display, off); + off = pict; + } +#endif return off; } @@ -724,15 +737,24 @@ void Fl_Xlib_Graphics_Driver::draw_unscaled(Fl_RGB_Image *img, float s, int X, i Y = (Y+offset_y_)*s; cache_size(img, W, H); cx *= s; cy *= s; + if (W + cx > img->pixel_w()) W = img->pixel_w() - cx; + if (H + cy > img->pixel_h()) H = img->pixel_h() - cy; if (!*Fl_Graphics_Driver::id(img)) { *Fl_Graphics_Driver::id(img) = cache_rgb(img); *cache_scale(img) = 1; } Fl_Region r2 = scale_clip(s); if (*Fl_Graphics_Driver::id(img)) { - if (img->d() == 4 || img->d() == 2) { +#if HAVE_XRENDER && USE_XRENDER_PICTURE + int condition = can_do_alpha_blending(); +#else + int condition = 0; +#endif + if (img->d() == 4 || img->d() == 2 || condition) { #if HAVE_XRENDER + scale_ = 1; scale_and_render_pixmap(*Fl_Graphics_Driver::id(img), img->d(), 1, 1, cx, cy, X, Y, W, H); + scale_ = s; #endif } else { XCopyArea(fl_display, *Fl_Graphics_Driver::id(img), fl_window, gc_, cx, cy, W, H, X, Y); @@ -757,14 +779,18 @@ void Fl_Xlib_Graphics_Driver::draw_unscaled(Fl_RGB_Image *img, float s, int X, i void Fl_Xlib_Graphics_Driver::uncache(Fl_RGB_Image*, fl_uintptr_t &id_, fl_uintptr_t &mask_) { if (id_) { - XFreePixmap(fl_display, (Fl_Offscreen)id_); +#if HAVE_XRENDER && USE_XRENDER_PICTURE + if (can_do_alpha_blending()) XRenderFreePicture(fl_display, id_); + else +#endif + XFreePixmap(fl_display, (Fl_Offscreen)id_); id_ = 0; } } -fl_uintptr_t Fl_Xlib_Graphics_Driver::cache(Fl_Bitmap *bm, int w, int h, const uchar *array) { +fl_uintptr_t Fl_Xlib_Graphics_Driver::cache(Fl_Bitmap *bm) { *cache_scale(bm) = Fl_Scalable_Graphics_Driver::scale(); - return (fl_uintptr_t)create_bitmask(w, h, array); + return (fl_uintptr_t)create_bitmask(bm->pixel_w(), bm->pixel_h(), bm->array); } void Fl_Xlib_Graphics_Driver::draw_unscaled(Fl_Pixmap *pxm, float s, int X, int Y, int W, int H, int cx, int cy) { @@ -812,15 +838,15 @@ void Fl_Xlib_Graphics_Driver::draw_unscaled(Fl_Pixmap *pxm, float s, int X, int } -fl_uintptr_t Fl_Xlib_Graphics_Driver::cache(Fl_Pixmap *pxm, int w, int h, const char *const*data) { - Fl_Image_Surface *surf = new Fl_Image_Surface(w, h); +fl_uintptr_t Fl_Xlib_Graphics_Driver::cache(Fl_Pixmap *pxm) { + Fl_Image_Surface *surf = new Fl_Image_Surface(pxm->pixel_w(), pxm->pixel_h()); Fl_Surface_Device::push_current(surf); uchar *bitmap = 0; Fl_Surface_Device::surface()->driver()->mask_bitmap(&bitmap); - fl_draw_pixmap(data, 0, 0, FL_BLACK); + fl_draw_pixmap(pxm->data(), 0, 0, FL_BLACK); Fl_Surface_Device::surface()->driver()->mask_bitmap(0); if (bitmap) { - *Fl_Graphics_Driver::mask(pxm) = (fl_uintptr_t)create_bitmask(w, h, bitmap); + *Fl_Graphics_Driver::mask(pxm) = (fl_uintptr_t)create_bitmask(pxm->pixel_w(), pxm->pixel_h(), bitmap); delete[] bitmap; } Fl_Surface_Device::pop_current(); @@ -843,9 +869,13 @@ int Fl_Xlib_Graphics_Driver::scale_and_render_pixmap(Fl_Offscreen pixmap, int de bool has_alpha = (depth == 2 || depth == 4); XRenderPictureAttributes srcattr; memset(&srcattr, 0, sizeof(XRenderPictureAttributes)); - static XRenderPictFormat *fmt32 = XRenderFindStandardFormat(fl_display, PictStandardARGB32); static XRenderPictFormat *fmt24 = XRenderFindStandardFormat(fl_display, PictStandardRGB24); +#if USE_XRENDER_PICTURE + Picture src = pixmap; +#else + static XRenderPictFormat *fmt32 = XRenderFindStandardFormat(fl_display, PictStandardARGB32); Picture src = XRenderCreatePicture(fl_display, pixmap, has_alpha ?fmt32:fmt24, 0, &srcattr); +#endif Picture dst = XRenderCreatePicture(fl_display, fl_window, fmt24, 0, &srcattr); if (!src || !dst) { fprintf(stderr, "Failed to create Render pictures (%lu %lu)\n", src, dst); @@ -856,17 +886,23 @@ int Fl_Xlib_Graphics_Driver::scale_and_render_pixmap(Fl_Offscreen pixmap, int de if (clipr) XRenderSetPictureClipRegion(fl_display, dst, clipr); unscale_clip(r); +#if !USE_XRENDER_PICTURE if (scale_x != 1 || scale_y != 1) { +#endif XTransform mat = {{ { XDoubleToFixed( scale_x ), XDoubleToFixed( 0 ), XDoubleToFixed( 0 ) }, { XDoubleToFixed( 0 ), XDoubleToFixed( scale_y ), XDoubleToFixed( 0 ) }, { XDoubleToFixed( 0 ), XDoubleToFixed( 0 ), XDoubleToFixed( 1 ) } }}; XRenderSetPictureTransform(fl_display, src, &mat); +#if !USE_XRENDER_PICTURE } +#endif XRenderComposite(fl_display, (has_alpha ? PictOpOver : PictOpSrc), src, None, dst, srcx, srcy, 0, 0, XP, YP, WP, HP); +#if !USE_XRENDER_PICTURE XRenderFreePicture(fl_display, src); +#endif XRenderFreePicture(fl_display, dst); return 1; } @@ -881,7 +917,7 @@ int Fl_Xlib_Graphics_Driver::draw_scaled(Fl_Image *img, int XP, int YP, int WP, } cache_size(img, WP, HP); return scale_and_render_pixmap( *Fl_Graphics_Driver::id(rgb), rgb->d(), - rgb->w() / double(WP), rgb->h() / double(HP), 0, 0, (XP + offset_x_)*scale_, (YP + offset_y_)*scale_, WP, HP); + rgb->pixel_w() / double(WP), rgb->pixel_h() / double(HP), 0, 0, (XP + offset_x_)*scale_, (YP + offset_y_)*scale_, WP, HP); } #endif // HAVE_XRENDER -- cgit v1.2.3