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. On other platforms, 
 the new member function returns an unscaled bitmap.

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3-porting@11158 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Manolo Gouy
2016-02-12 11:49:32 +00:00
parent 50ee3bcd66
commit bc83464b64
4 changed files with 84 additions and 9 deletions
+3 -1
View File
@@ -21,6 +21,7 @@
#include <FL/Fl_Copy_Surface.H> #include <FL/Fl_Copy_Surface.H>
#include <FL/Fl_Image.H> #include <FL/Fl_Image.H>
#include <FL/Fl_Shared_Image.H>
/** Directs all graphics requests to an Fl_Image. /** Directs all graphics requests to an Fl_Image.
@@ -65,12 +66,13 @@ private:
public: public:
static const char *class_id; static const char *class_id;
const char *class_name() {return class_id;}; const char *class_name() {return class_id;};
Fl_Image_Surface(int w, int h); Fl_Image_Surface(int w, int h, int highres = 0);
~Fl_Image_Surface(); ~Fl_Image_Surface();
void set_current(); void set_current();
void draw(Fl_Widget*, int delta_x = 0, int delta_y = 0); void draw(Fl_Widget*, int delta_x = 0, int delta_y = 0);
Fl_RGB_Image *image(); Fl_RGB_Image *image();
void draw_decorated_window(Fl_Window* win, int delta_x = 0, int delta_y = 0); void draw_decorated_window(Fl_Window* win, int delta_x = 0, int delta_y = 0);
Fl_Shared_Image *highres_image();
}; };
#ifdef __APPLE__ // PORTME: platform surface driver #ifdef __APPLE__ // PORTME: platform surface driver
+55 -5
View File
@@ -32,18 +32,48 @@
#else #else
#endif #endif
#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"; const char *Fl_Image_Surface::class_id = "Fl_Image_Surface";
/** The constructor. /** Constructor with optional high resolution.
\param w and \param h give the size in pixels of the resulting image. \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 (1.3.3 without the highres parameter)
*/ */
Fl_Image_Surface::Fl_Image_Surface(int w, int h) : Fl_Surface_Device(NULL) { Fl_Image_Surface::Fl_Image_Surface(int w, int h, int highres) : Fl_Surface_Device(NULL) {
width = w; width = w;
height = h; height = h;
#ifdef __APPLE__ // PORTME: platform image surface #ifdef __APPLE__ // PORTME: platform image surface
offscreen = fl_create_offscreen(w, h); offscreen = fl_create_offscreen(highres ? 2*w : w, highres ? 2*h : h);
helper = new Fl_Quartz_Flipped_Surface_(width, height); helper = new Fl_Quartz_Flipped_Surface_(width, height);
if (highres) {
delete helper->driver();
helper->driver(new Fl_Quartz_Scaled_Graphics_Driver_);
CGContextScaleCTM(offscreen, 2, 2);
}
driver(helper->driver()); driver(helper->driver());
CGContextSetShouldAntialias(offscreen, false);
CGContextSaveGState(offscreen); CGContextSaveGState(offscreen);
CGContextTranslateCTM(offscreen, 0, height); CGContextTranslateCTM(offscreen, 0, height);
CGContextScaleCTM(offscreen, 1.0f, -1.0f); CGContextScaleCTM(offscreen, 1.0f, -1.0f);
@@ -95,9 +125,13 @@ Fl_Image_Surface::~Fl_Image_Surface() {
Fl_RGB_Image* Fl_Image_Surface::image() Fl_RGB_Image* Fl_Image_Surface::image()
{ {
unsigned char *data; unsigned char *data;
int W = width, H = height;
#ifdef __APPLE__ // PORTME: platform image surface #ifdef __APPLE__ // PORTME: platform image surface
CGContextFlush(offscreen); 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; fl_gc = 0;
#elif defined(WIN32) #elif defined(WIN32)
fl_pop_clip(); fl_pop_clip();
@@ -115,11 +149,26 @@ Fl_RGB_Image* Fl_Image_Surface::image()
fl_window = pre_window; fl_window = pre_window;
previous->set_current(); previous->set_current();
#endif #endif
Fl_RGB_Image *image = new Fl_RGB_Image(data, width, height); Fl_RGB_Image *image = new Fl_RGB_Image(data, W, H);
image->alloc_array = 1; image->alloc_array = 1;
return image; 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
*/
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 /** Draws a widget in the image surface
\param widget any FLTK widget (e.g., standard, custom, window, GL view) to draw in the image \param widget any FLTK widget (e.g., standard, custom, window, GL view) to draw in the image
@@ -137,6 +186,7 @@ void Fl_Image_Surface::set_current()
#if defined(__APPLE__) // PORTME: platform image surface #if defined(__APPLE__) // PORTME: platform image surface
fl_gc = offscreen; fl_window = 0; fl_gc = offscreen; fl_window = 0;
Fl_Surface_Device::set_current(); Fl_Surface_Device::set_current();
Fl_X::set_high_resolution( CGBitmapContextGetWidth(offscreen) > width );
#elif defined(WIN32) #elif defined(WIN32)
_sgc=fl_gc; _sgc=fl_gc;
_sw=fl_window; _sw=fl_window;
+24 -1
View File
@@ -3345,9 +3345,31 @@ void Fl_X::q_begin_image(CGRect &rect, int cx, int cy, int w, int h) {
r2.origin.x -= 0.5f; r2.origin.x -= 0.5f;
r2.origin.y -= 0.5f; r2.origin.y -= 0.5f;
CGContextClipToRect(fl_gc, r2); 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); CGContextTranslateCTM(fl_gc, rect.origin.x - cx - 0.5, rect.origin.y - cy + h - 0.5);
CGContextScaleCTM(fl_gc, 1, -1); 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.origin.x = rect.origin.y = 0;
rect.size.width = w; rect.size.width = w;
rect.size.height = h; rect.size.height = h;
@@ -4368,6 +4390,7 @@ static void draw_layer_to_context(CALayer *layer, CGContextRef gc, int w, int h)
Fl_X::clip_to_rounded_corners(gc, w, h); Fl_X::clip_to_rounded_corners(gc, w, h);
CGContextSetRGBFillColor(gc, .79, .79, .79, 1.); // equiv. to FL_DARK1 CGContextSetRGBFillColor(gc, .79, .79, .79, 1.); // equiv. to FL_DARK1
CGContextFillRect(gc, CGRectMake(0, 0, w, h)); CGContextFillRect(gc, CGRectMake(0, 0, w, h));
CGContextSetShouldAntialias(gc, true);
[layer renderInContext:gc]; // 10.5 [layer renderInContext:gc]; // 10.5
CGContextRestoreGState(gc); CGContextRestoreGState(gc);
#endif #endif
+2 -2
View File
@@ -563,13 +563,13 @@ void copy(Fl_Widget *, void *data) {
H = target->h(); H = target->h();
decorated = 0; decorated = 0;
} }
rgb_surf = new Fl_Image_Surface(W, H); rgb_surf = new Fl_Image_Surface(W, H, 1);
rgb_surf->set_current(); rgb_surf->set_current();
if (decorated) if (decorated)
rgb_surf->draw_decorated_window(target->as_window()); rgb_surf->draw_decorated_window(target->as_window());
else else
rgb_surf->draw(target); rgb_surf->draw(target);
Fl_Image *img = rgb_surf->image(); Fl_Image *img = rgb_surf->highres_image();
delete rgb_surf; delete rgb_surf;
Fl_Display_Device::display_device()->set_current(); Fl_Display_Device::display_device()->set_current();
Fl_Window* g2 = new Fl_Window(img->w()+10, img->h()+10); Fl_Window* g2 = new Fl_Window(img->w()+10, img->h()+10);