Add Fl_Shared_Image *Fl_Image_Surface::highres_image() to draw into high-resolution bitmap.
This new member function returns a high resolution bitmap image scaled to the adequate drawing size. This allows to create a bitmap image able to fill all pixels of a high resolution display. This is functional only for the Mac OS platform and with FL_ABI_VERSION >= 10304. On other platforms, the new member function returns an unscaled bitmap. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@11156 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
parent
90a2d680e5
commit
249e2e9b00
@ -21,6 +21,7 @@
|
||||
|
||||
#include <FL/Fl_Copy_Surface.H>
|
||||
#include <FL/Fl_Image.H>
|
||||
#include <FL/Fl_Shared_Image.H>
|
||||
|
||||
|
||||
/** Directs all graphics requests to an Fl_Image.
|
||||
@ -45,6 +46,7 @@
|
||||
*/
|
||||
class FL_EXPORT Fl_Image_Surface : public Fl_Surface_Device {
|
||||
private:
|
||||
void prepare_(int w, int h, int highres);
|
||||
Fl_Offscreen offscreen;
|
||||
int width;
|
||||
int height;
|
||||
@ -63,12 +65,18 @@ private:
|
||||
public:
|
||||
static const char *class_id;
|
||||
const char *class_name() {return class_id;};
|
||||
#if FLTK_ABI_VERSION >= 10304 || defined(FL_DOXYGEN)
|
||||
Fl_Image_Surface(int w, int h, int highres = 0);
|
||||
#else
|
||||
Fl_Image_Surface(int w, int h, int highres);
|
||||
Fl_Image_Surface(int w, int h);
|
||||
#endif
|
||||
~Fl_Image_Surface();
|
||||
void set_current();
|
||||
void draw(Fl_Widget*, int delta_x = 0, int delta_y = 0);
|
||||
void draw_decorated_window(Fl_Window* win, int delta_x = 0, int delta_y = 0);
|
||||
Fl_RGB_Image *image();
|
||||
Fl_Shared_Image *highres_image();
|
||||
};
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
@ -20,19 +20,43 @@
|
||||
#include <FL/Fl_Printer.H>
|
||||
#include <FL/Fl.H>
|
||||
|
||||
#ifdef __APPLE__
|
||||
class Fl_Quartz_Scaled_Graphics_Driver_ : public Fl_Quartz_Graphics_Driver {
|
||||
protected:
|
||||
virtual void push_clip(int x, int y, int w, int h) {
|
||||
CGContextRestoreGState(fl_gc);
|
||||
CGContextSaveGState(fl_gc);
|
||||
CGContextTranslateCTM(fl_gc, 0, CGBitmapContextGetHeight(fl_gc)/2);
|
||||
CGContextScaleCTM(fl_gc, 1.0f, -1.0f);
|
||||
CGContextClipToRect(fl_gc, CGRectMake(x, y, w, h));
|
||||
}
|
||||
virtual void pop_clip() {
|
||||
CGContextRestoreGState(fl_gc);
|
||||
CGContextSaveGState(fl_gc);
|
||||
CGContextTranslateCTM(fl_gc, 0, CGBitmapContextGetHeight(fl_gc)/2);
|
||||
CGContextScaleCTM(fl_gc, 1.0f, -1.0f);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
const char *Fl_Image_Surface::class_id = "Fl_Image_Surface";
|
||||
|
||||
/** The constructor.
|
||||
\param w and \param h give the size in pixels of the resulting image.
|
||||
*/
|
||||
Fl_Image_Surface::Fl_Image_Surface(int w, int h) : Fl_Surface_Device(NULL) {
|
||||
void Fl_Image_Surface::prepare_(int w, int h, int highres) {
|
||||
width = w;
|
||||
height = h;
|
||||
#if FL_ABI_VERSION < 10304
|
||||
highres = 0;
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
offscreen = fl_create_offscreen(w, h);
|
||||
helper = new Fl_Quartz_Flipped_Surface_(width, height);
|
||||
offscreen = fl_create_offscreen(highres ? 2*w : w, highres ? 2*h : h);
|
||||
helper = new Fl_Quartz_Flipped_Surface_(w, h);
|
||||
if (highres) {
|
||||
delete helper->driver();
|
||||
helper->driver(new Fl_Quartz_Scaled_Graphics_Driver_);
|
||||
CGContextScaleCTM(offscreen, 2, 2);
|
||||
}
|
||||
driver(helper->driver());
|
||||
CGContextSetShouldAntialias(offscreen, false);
|
||||
CGContextSaveGState(offscreen);
|
||||
CGContextTranslateCTM(offscreen, 0, height);
|
||||
CGContextScaleCTM(offscreen, 1.0f, -1.0f);
|
||||
@ -55,6 +79,24 @@ Fl_Image_Surface::Fl_Image_Surface(int w, int h) : Fl_Surface_Device(NULL) {
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Constructor with optional high resolution.
|
||||
\param w and \param h give the size in pixels of the resulting image.
|
||||
\param highres if non-zero, the surface pixel size is twice as high and wide as w and h,
|
||||
which is useful to draw it later on a high resolution display (e.g., retina display).
|
||||
This is implemented for the Mac OS platform only.
|
||||
If \p highres is non-zero, use Fl_Image_Surface::highres_image() to get the image data.
|
||||
\version 1.3.4 and requires compilation with -DFL_ABI_VERSION=10304 (1.3.3 without the highres parameter)
|
||||
*/
|
||||
Fl_Image_Surface::Fl_Image_Surface(int w, int h, int highres) : Fl_Surface_Device(NULL) {
|
||||
prepare_(w, h, highres);
|
||||
}
|
||||
#if FLTK_ABI_VERSION < 10304
|
||||
Fl_Image_Surface::Fl_Image_Surface(int w, int h) : Fl_Surface_Device(NULL) {
|
||||
prepare_(w, h, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/** The destructor.
|
||||
*/
|
||||
Fl_Image_Surface::~Fl_Image_Surface() {
|
||||
@ -75,14 +117,19 @@ Fl_Image_Surface::~Fl_Image_Surface() {
|
||||
|
||||
/** Returns an image made of all drawings sent to the Fl_Image_Surface object.
|
||||
The returned object contains its own copy of the RGB data.
|
||||
Prefer Fl_Image_Surface::highres_image() if the surface was
|
||||
constructed with the highres option on.
|
||||
*/
|
||||
Fl_RGB_Image* Fl_Image_Surface::image()
|
||||
{
|
||||
unsigned char *data;
|
||||
int depth = 3, ld = 0;
|
||||
int W = width, H = height;
|
||||
#ifdef __APPLE__
|
||||
CGContextFlush(offscreen);
|
||||
data = fl_read_image(NULL, 0, 0, width, height, 0);
|
||||
W = CGBitmapContextGetWidth(offscreen);
|
||||
H = CGBitmapContextGetHeight(offscreen);
|
||||
Fl_X::set_high_resolution(0);
|
||||
data = fl_read_image(NULL, 0, 0, W, H, 0);
|
||||
fl_gc = 0;
|
||||
#elif defined(WIN32)
|
||||
fl_pop_clip();
|
||||
@ -98,11 +145,24 @@ Fl_RGB_Image* Fl_Image_Surface::image()
|
||||
fl_window = pre_window;
|
||||
previous->set_current();
|
||||
#endif
|
||||
Fl_RGB_Image *image = new Fl_RGB_Image(data, width, height, depth, ld);
|
||||
Fl_RGB_Image *image = new Fl_RGB_Image(data, W, H);
|
||||
image->alloc_array = 1;
|
||||
return image;
|
||||
}
|
||||
|
||||
/** Returns a possibly high resolution image made of all drawings sent to the Fl_Image_Surface object.
|
||||
The Fl_Image_Surface object should have been constructed with Fl_Image_Surface(W, H, 1).
|
||||
The returned image is scaled to a size of WxH drawing units and may have a pixel size twice as wide and high.
|
||||
The returned object should be deallocated with Fl_Shared_Image::release() after use.
|
||||
\version 1.3.4 and requires compilation with -DFL_ABI_VERSION=10304
|
||||
*/
|
||||
Fl_Shared_Image* Fl_Image_Surface::highres_image()
|
||||
{
|
||||
Fl_Shared_Image *s_img = Fl_Shared_Image::get(image());
|
||||
s_img->scale(width, height);
|
||||
return s_img;
|
||||
}
|
||||
|
||||
/** Draws a widget in the image surface
|
||||
|
||||
\param widget any FLTK widget (e.g., standard, custom, window, GL view) to draw in the image
|
||||
@ -120,6 +180,7 @@ void Fl_Image_Surface::set_current()
|
||||
#if defined(__APPLE__)
|
||||
fl_gc = offscreen; fl_window = 0;
|
||||
Fl_Surface_Device::set_current();
|
||||
Fl_X::set_high_resolution( CGBitmapContextGetWidth(offscreen) > width );
|
||||
#elif defined(WIN32)
|
||||
_sgc=fl_gc;
|
||||
_sw=fl_window;
|
||||
|
||||
@ -3379,9 +3379,31 @@ void Fl_X::q_begin_image(CGRect &rect, int cx, int cy, int w, int h) {
|
||||
r2.origin.x -= 0.5f;
|
||||
r2.origin.y -= 0.5f;
|
||||
CGContextClipToRect(fl_gc, r2);
|
||||
// move graphics context to origin of vertically reversed image
|
||||
// move graphics context to origin of vertically reversed image
|
||||
// The 0.5 here cancels the 0.5 offset present in Quartz graphics contexts.
|
||||
// Thus, image and surface pixels are in phase if there's no scaling.
|
||||
// Below, we handle x2 and /2 scalings that occur when drawing to
|
||||
// a double-resolution bitmap, and when drawing a double-resolution bitmap to display.
|
||||
CGContextTranslateCTM(fl_gc, rect.origin.x - cx - 0.5, rect.origin.y - cy + h - 0.5);
|
||||
CGContextScaleCTM(fl_gc, 1, -1);
|
||||
CGAffineTransform at = CGContextGetCTM(fl_gc);
|
||||
if (at.a == at.d && at.b == 0 && at.c == 0) { // proportional scaling, no rotation
|
||||
// phase image with display pixels
|
||||
CGFloat deltax = 0, deltay = 0;
|
||||
if (at.a == 2) { // make .tx and .ty have even values
|
||||
deltax = (at.tx/2 - round(at.tx/2));
|
||||
deltay = (at.ty/2 - round(at.ty/2));
|
||||
} else if (at.a == 0.5) {
|
||||
if (Fl_Display_Device::high_resolution()) { // make .tx and .ty have int or half-int values
|
||||
deltax = (at.tx*2 - round(at.tx*2));
|
||||
deltay = (at.ty*2 - round(at.ty*2));
|
||||
} else { // make .tx and .ty have integral values
|
||||
deltax = (at.tx - round(at.tx))*2;
|
||||
deltay = (at.ty - round(at.ty))*2;
|
||||
}
|
||||
}
|
||||
CGContextTranslateCTM(fl_gc, -deltax, -deltay);
|
||||
}
|
||||
rect.origin.x = rect.origin.y = 0;
|
||||
rect.size.width = w;
|
||||
rect.size.height = h;
|
||||
@ -4403,7 +4425,10 @@ void Fl_X::draw_layer_to_context(void *layer, CGContextRef gc, int w, int h)
|
||||
Fl_X::clip_to_rounded_corners(gc, w, h);
|
||||
CGContextSetRGBFillColor(gc, .79, .79, .79, 1.); // equiv. to FL_DARK1
|
||||
CGContextFillRect(gc, CGRectMake(0, 0, w, h));
|
||||
CGContextSaveGState(gc);
|
||||
CGContextSetShouldAntialias(gc, true);
|
||||
[(CALayer*)layer renderInContext:gc]; // 10.5
|
||||
CGContextRestoreGState(gc);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -563,13 +563,13 @@ void copy(Fl_Widget *, void *data) {
|
||||
H = target->h();
|
||||
decorated = 0;
|
||||
}
|
||||
rgb_surf = new Fl_Image_Surface(W, H);
|
||||
rgb_surf = new Fl_Image_Surface(W, H, 1);
|
||||
rgb_surf->set_current();
|
||||
if (decorated)
|
||||
rgb_surf->draw_decorated_window(target->as_window());
|
||||
else
|
||||
rgb_surf->draw(target);
|
||||
Fl_Image *img = rgb_surf->image();
|
||||
Fl_Image *img = rgb_surf->highres_image();
|
||||
delete rgb_surf;
|
||||
Fl_Display_Device::display_device()->set_current();
|
||||
Fl_Window* g2 = new Fl_Window(img->w()+10, img->h()+10);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user