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
This commit is contained in:
Manolo Gouy 2018-03-19 17:43:18 +00:00
parent c4f7c09b7b
commit 916b44e361
20 changed files with 339 additions and 359 deletions

View File

@ -18,6 +18,11 @@ Changes in FLTK 1.4.0 Released: ??? ?? 2017
New Features and Extensions
- (add new items here)
- New member function Fl_Image::scale(int width, int height) to set
the drawing size of an image independently from its pixel size. The
same function was previously available only for class Fl_Shared_Image
and with FL_ABI_VERSION >= 10304. New member functions Fl_Image::pixel_w()
and Fl_Image::pixel_h() give the size in pixels of an image.
- OpenGL draws text using textures on all platforms, when the necessary
hardware support is present (a backup mechanism is available in absence
of this support). Thus, all text drawable in Fl_Window's can be drawn

View File

@ -45,9 +45,6 @@ private:
/** for internal use */
fl_uintptr_t id_;
float cache_scale_; // graphics scaling value when id_ was computed
protected:
virtual int draw_scaled(int X, int Y, int W, int H);
public:
/** The constructors create a new bitmap from the specified bitmap data */

View File

@ -141,9 +141,9 @@ protected:
matrix *fl_matrix; /**< Points to the current coordinate transformation matrix */
virtual void global_gc();
/** Support function for Fl_Pixmap drawing */
virtual fl_uintptr_t cache(Fl_Pixmap *img, int w, int h, const char *const*array) { return 0; }
virtual fl_uintptr_t cache(Fl_Pixmap *img) { return 0; }
/** Support function for Fl_Bitmap drawing */
virtual fl_uintptr_t cache(Fl_Bitmap *img, int w, int h, const uchar *array) { return 0; }
virtual fl_uintptr_t cache(Fl_Bitmap *img) { return 0; }
/** Support function for Fl_RGB_Image drawing */
virtual void uncache(Fl_RGB_Image *img, fl_uintptr_t &id_, fl_uintptr_t &mask_) { }
// --- implementation is in src/drivers/xxx/Fl_xxx_Graphics_Driver_image.cxx
@ -173,7 +173,6 @@ protected:
the image offset by the cx and cy arguments.
*/
virtual void draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) {}
virtual void draw(Fl_Shared_Image *shared, int X, int Y);
virtual void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy);
/** Support function for image drawing */
@ -393,7 +392,7 @@ public:
virtual const char *font_name(int num) {return NULL;}
/** Support for Fl::set_font() */
virtual void font_name(int num, const char *name) {}
/** Support function for Fl_Shared_Image drawing */
// Draws an Fl_Image scaled to width W & height H
virtual int draw_scaled(Fl_Image *img, int X, int Y, int W, int H);
/** Support function for fl_overlay_rect() and scaled GUI.
Defaut implementation may be enough */
@ -460,7 +459,6 @@ protected:
virtual void draw_unscaled(Fl_Bitmap *bm, float s, int XP, int YP, int WP, int HP, int cx, int cy) {}
virtual void draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy);
virtual void draw_unscaled(Fl_RGB_Image *img, float s, int XP, int YP, int WP, int HP, int cx, int cy) {}
virtual void draw(Fl_Shared_Image *shared, int X, int Y);
virtual void point(int x, int y);
virtual void point_unscaled(float x, float y) {}
virtual void rect(int x, int y, int w, int h);

View File

@ -43,9 +43,9 @@ enum Fl_RGB_Scaling {
/**
\brief Base class for image caching and drawing.
\brief Base class for image caching, scaling and drawing.
Fl_Image is the base class used for caching and drawing all kinds of images
Fl_Image is the base class used for caching, scaling and drawing all kinds of images
in FLTK. This class keeps track of common image data such as the pixels,
colormap, width, height, and depth. Virtual methods are used to provide
type-specific image handling.
@ -63,9 +63,10 @@ public:
private:
int w_, h_, d_, ld_, count_;
int pixel_w_, pixel_h_;
const char * const *data_;
static Fl_RGB_Scaling RGB_scaling_;
static Fl_RGB_Scaling RGB_scaling_; // method used when copying RGB images
static Fl_RGB_Scaling scaling_algorithm_; // method used to rescale RGB source images before drawing
// Forbid use of copy constructor and assign operator
Fl_Image & operator=(const Fl_Image &);
Fl_Image(const Fl_Image &);
@ -75,11 +76,11 @@ protected:
/**
Sets the current image width in pixels.
*/
void w(int W) {w_ = W;}
void w(int W) {w_ = W; pixel_w_ = W;}
/**
Sets the current image height in pixels.
*/
void h(int H) {h_ = H;}
void h(int H) {h_ = H; pixel_h_ = H;}
/**
Sets the current image depth.
*/
@ -104,18 +105,30 @@ protected:
static void labeltype(const Fl_Label *lo, int lx, int ly, int lw, int lh, Fl_Align la);
static void measure(const Fl_Label *lo, int &lw, int &lh);
virtual int draw_scaled(int X, int Y, int W, int H);
int draw_scaled(int X, int Y, int W, int H);
public:
/**
Returns the current image width in pixels.
Returns the current image width in FLTK units.
The values of w() and pixel_w() are identical unless scale() has been called
after which they may differ.
*/
int w() const {return w_;}
/**
Returns the current image height in pixels.
Returns the current image height in FLTK units.
The values of h() and pixel_h() are identical unless scale() has been called
after which they may differ.
*/
int h() const {return h_;}
/**
Returns the image width in pixels.
*/
int pixel_w() {return pixel_w_;}
/**
Returns the image height in pixels.
*/
int pixel_h() {return pixel_h_;}
/**
Returns the current image depth.
The return value will be 0 for bitmaps, 1 for
@ -188,15 +201,28 @@ public:
// set RGB image scaling method
static void RGB_scaling(Fl_RGB_Scaling);
// get RGB image scaling method
static Fl_RGB_Scaling RGB_scaling();
/** Use this method if you have an Fl_Image object and want to know whether it is derived
from class Fl_RGB_Image.
If the method returns non-NULL, then the image in question is
derived from Fl_RGB_Image, and the returned value is a pointer to this image.
*/
virtual Fl_RGB_Image *as_rgb_image() {return NULL;}
// set the image drawing size
virtual void scale(int width, int height, int proportional = 1, int can_expand = 0);
/** Sets what algorithm is used when resizing a source image to draw it.
The default algorithm is FL_RGB_SCALING_BILINEAR.
Drawing an Fl_Image is sometimes performed by first resizing the source image
and then drawing the resized copy. This occurs, e.g., when drawing to screen under X11
without Xrender support after having called scale().
This function controls what method is used when the image to be resized is an Fl_RGB_Image.
\version 1.4
*/
static void scaling_algorithm(Fl_RGB_Scaling algorithm) {scaling_algorithm_ = algorithm; }
/** Gets what algorithm is used when resizing a source image to draw it. */
static Fl_RGB_Scaling scaling_algorithm() {return scaling_algorithm_;}
};
@ -229,9 +255,6 @@ private:
fl_uintptr_t mask_;
float cache_scale_; // graphics scaling value when id_ was computed
protected:
virtual int draw_scaled(int X, int Y, int W, int H);
public:
Fl_RGB_Image(const uchar *bits, int W, int H, int D=3, int LD=0);

View File

@ -45,7 +45,6 @@ class FL_EXPORT Fl_Pixmap : public Fl_Image {
protected:
void measure();
virtual int draw_scaled(int X, int Y, int W, int H);
public:

View File

@ -34,9 +34,8 @@ struct NSVGimage;
If the image has loaded correctly, w(), h(), and d() should return values greater than zero.
Rasterization is not done until the image is first drawn or resize() is called. Therefore,
\ref array is NULL until then. The delayed rasterization ensures an Fl_Shared_Image based on
an SVG image and scaled to its display size by Fl_Shared_Image::scale() will be
always rasterized to the exact screen resolution.
\ref array is NULL until then. The delayed rasterization ensures an Fl_SVG_Image is always rasterized
to the exact screen resolution at which it is drawn.
The Fl_SVG_Image class draws images computed by \c nanosvg: one known limitation is that text
within \c <text\></text\> blocks is not rendered.
@ -118,8 +117,6 @@ private:
void rasterize_(int W, int H);
void init_(const char *filename, const char *filedata, Fl_SVG_Image *copy_source);
Fl_SVG_Image(Fl_SVG_Image *source);
protected:
virtual int draw_scaled(int X, int Y, int W, int H);
public:
/** Set this to \c false to allow image re-scaling that alters the image aspect ratio.
Upon object creation, proportional is set to \c true, and the aspect ratio is kept constant.*/

View File

@ -31,7 +31,7 @@ typedef Fl_Image *(*Fl_Shared_Handler)(const char *name, uchar *header,
// Shared images class.
/**
This class supports caching, loading, scaling, and drawing of image files.
This class supports caching, loading, and drawing of image files.
Most applications will also want to link against the fltk_images library
and call the fl_register_images() function to support standard image
@ -54,9 +54,6 @@ class FL_EXPORT Fl_Shared_Image : public Fl_Image {
friend class Fl_PNG_Image;
friend class Fl_Graphics_Driver;
private:
static Fl_RGB_Scaling scaling_algorithm_; // method used to rescale RGB source images
Fl_Image *scaled_image_;
protected:
static Fl_Shared_Image **images_; // Shared images
@ -108,7 +105,6 @@ public:
virtual void desaturate();
virtual void draw(int X, int Y, int W, int H, int cx = 0, int cy = 0);
void draw(int X, int Y) { draw(X, Y, w(), h(), 0, 0); }
void scale(int width, int height, int proportional = 1, int can_expand = 0);
virtual void uncache();
static Fl_Shared_Image *find(const char *name, int W = 0, int H = 0);
@ -118,15 +114,6 @@ public:
static int num_images();
static void add_handler(Fl_Shared_Handler f);
static void remove_handler(Fl_Shared_Handler f);
/** Sets what algorithm is used when resizing a source image.
The default algorithm is FL_RGB_SCALING_BILINEAR.
Drawing an Fl_Shared_Image is sometimes performed by first resizing the source image
and then drawing the resized copy. This occurs, e.g., when drawing to screen under Linux
after having called Fl_Shared_Image::scale().
This function controls what method is used when the image to be resized is an Fl_RGB_Image.
\version 1.3.4
*/
static void scaling_algorithm(Fl_RGB_Scaling algorithm) {scaling_algorithm_ = algorithm; }
};
//

View File

@ -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$".
//

View File

@ -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);

View File

@ -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 <tt>width,height</tt> 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; dy<dh; dy++) {
memcpy(dst, src, wd);
src += wld;
dst += wd;
}
} else {
memcpy(new_array, array, w() * h() * d());
memcpy(new_array, array, pixel_w() * pixel_h() * d());
}
new_image = new Fl_RGB_Image(new_array, w(), h(), d());
new_image = new Fl_RGB_Image(new_array, pixel_w(), pixel_h(), d());
new_image->alloc_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$".
//

View File

@ -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$".
//

View File

@ -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
//

View File

@ -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();
// 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);
}
/** 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 <tt>width,height</tt> 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));
}
Fl_RGB_Scaling Fl_Shared_Image::scaling_algorithm_ = FL_RGB_SCALING_BILINEAR;
//

View File

@ -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);

View File

@ -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();

View File

@ -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; j<HP; j++){
for (i=0; i<xx; i++){
write_rle85(swap_byte(*di), rle85);
di++;
void Fl_PostScript_Graphics_Driver::draw(Fl_Bitmap * bitmap,int XP, int YP, int WP, int HP, int cx, int cy) {
int need_clip = cx || cy || WP != bitmap->w() || 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; j<HP; j++){
for (i=0; i<xx; i++){
write_rle85(swap_byte(*di), rle85);
di++;
}
}
close_rle85(rle85); fputc('\n', output);
}
close_rle85(rle85); fputc('\n', output);
pop_clip();
if (need_clip) pop_clip();
}
#endif // !defined(FL_DOXYGEN) && !defined(FL_NO_PRINT_SUPPORT)

View File

@ -70,13 +70,12 @@ public:
void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy);
void draw(Fl_Bitmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy);
void draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy);
int draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP);
void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0);
void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3);
void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0);
void draw_image_mono(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_Bitmap *img, int w, int h, const uchar *array);
fl_uintptr_t cache(Fl_Pixmap *img);
fl_uintptr_t cache(Fl_Bitmap *img);
void uncache(Fl_RGB_Image *img, fl_uintptr_t &id_, fl_uintptr_t &mask_);
void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy);
void draw_CGImage(CGImageRef cgimg, int x, int y, int w, int h, int srcx, int srcy, int sw, int sh);

View File

@ -162,7 +162,7 @@ void Fl_Quartz_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP,
if (!cgimg) {
CGColorSpaceRef lut = img->d()<=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;

View File

@ -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);

View File

@ -58,6 +58,8 @@
# include "../../flstring.h"
#if HAVE_XRENDER
#include <X11/extensions/Xrender.h>
// 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