mirror of https://github.com/fltk/fltk
New member function Fl_Image_Surface::mask(Fl_RGB_Image*)
This commit is contained in:
parent
b9ac6bd728
commit
3e61ec7044
|
@ -82,6 +82,7 @@ public:
|
||||||
int printable_rect(int *w, int *h) FL_OVERRIDE;
|
int printable_rect(int *w, int *h) FL_OVERRIDE;
|
||||||
Fl_Offscreen offscreen();
|
Fl_Offscreen offscreen();
|
||||||
void rescale();
|
void rescale();
|
||||||
|
void mask(const Fl_RGB_Image *);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -107,11 +108,15 @@ protected:
|
||||||
int external_offscreen;
|
int external_offscreen;
|
||||||
Fl_Image_Surface_Driver(int w, int h, int /*high_res*/, Fl_Offscreen off) : Fl_Widget_Surface(NULL), width(w), height(h), offscreen(off) {external_offscreen = (off != 0);}
|
Fl_Image_Surface_Driver(int w, int h, int /*high_res*/, Fl_Offscreen off) : Fl_Widget_Surface(NULL), width(w), height(h), offscreen(off) {external_offscreen = (off != 0);}
|
||||||
virtual ~Fl_Image_Surface_Driver() {}
|
virtual ~Fl_Image_Surface_Driver() {}
|
||||||
|
static void copy_with_mask(Fl_RGB_Image* mask, uchar *dib_dst, uchar *dib_src,
|
||||||
|
int line_size, bool bottom_to_top);
|
||||||
|
static Fl_RGB_Image *RGB3_to_RGB1(const Fl_RGB_Image *rgb3, int W, int H);
|
||||||
void set_current() FL_OVERRIDE = 0;
|
void set_current() FL_OVERRIDE = 0;
|
||||||
void translate(int x, int y) FL_OVERRIDE = 0;
|
void translate(int x, int y) FL_OVERRIDE = 0;
|
||||||
void untranslate() FL_OVERRIDE = 0;
|
void untranslate() FL_OVERRIDE = 0;
|
||||||
int printable_rect(int *w, int *h) FL_OVERRIDE;
|
int printable_rect(int *w, int *h) FL_OVERRIDE;
|
||||||
virtual Fl_RGB_Image *image() = 0;
|
virtual Fl_RGB_Image *image() = 0;
|
||||||
|
virtual void mask(const Fl_RGB_Image *) {}
|
||||||
/** Each platform implements this function its own way.
|
/** Each platform implements this function its own way.
|
||||||
It returns an object implementing all virtual functions
|
It returns an object implementing all virtual functions
|
||||||
of class Fl_Image_Surface_Driver for the plaform.
|
of class Fl_Image_Surface_Driver for the plaform.
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 197 KiB |
|
@ -90,15 +90,63 @@ int Fl_Image_Surface_Driver::printable_rect(int *w, int *h) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// used by the Windows and X11(no Cairo) platforms
|
||||||
|
void Fl_Image_Surface_Driver::copy_with_mask(Fl_RGB_Image* mask, uchar *dib_dst,
|
||||||
|
uchar *dib_src, int line_size,
|
||||||
|
bool bottom_to_top) {
|
||||||
|
int w = mask->data_w(), h = mask->data_h();
|
||||||
|
for (int i = 0; i < h; i++) {
|
||||||
|
const uchar* alpha = (const uchar*)mask->array +
|
||||||
|
(bottom_to_top ? (h-i-1) : i) * w;
|
||||||
|
uchar *src = dib_src + i * line_size;
|
||||||
|
uchar *dst = dib_dst + i * line_size;
|
||||||
|
for (int j = 0; j < w; j++) {
|
||||||
|
// mix src and dst into dst weighted by mask pixel's value
|
||||||
|
uchar u = *alpha++, v = 255 - u;
|
||||||
|
*dst = ((*dst) * v + (*src) * u)/255;
|
||||||
|
dst++; src++;
|
||||||
|
*dst = ((*dst) * v + (*src) * u)/255;
|
||||||
|
dst++; src++;
|
||||||
|
*dst = ((*dst) * v + (*src) * u)/255;
|
||||||
|
dst++; src++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Fl_RGB_Image *Fl_Image_Surface_Driver::RGB3_to_RGB1(const Fl_RGB_Image *rgb3, int W, int H) {
|
||||||
|
bool need_copy = false;
|
||||||
|
if (W != rgb3->data_w() || H != rgb3->data_h()) {
|
||||||
|
rgb3 = (Fl_RGB_Image*)rgb3->copy(W, H);
|
||||||
|
need_copy = true;
|
||||||
|
}
|
||||||
|
uchar *data = new uchar[W * H];
|
||||||
|
int i, j, ld = rgb3->ld();
|
||||||
|
if (!ld) ld = 3 * W;
|
||||||
|
uchar *p = data;
|
||||||
|
for (i = 0; i < H; i++) {
|
||||||
|
const uchar* alpha = rgb3->array + i * ld;
|
||||||
|
for (j = 0; j < W; j++) {
|
||||||
|
*p++ = (*alpha + *(alpha+1) + *(alpha+2)) / 3;
|
||||||
|
alpha += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Fl_RGB_Image *rgb1 = new Fl_RGB_Image(data, W, H, 1);
|
||||||
|
rgb1->alloc_array = 1;
|
||||||
|
if (need_copy) delete rgb3;
|
||||||
|
return rgb1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\}
|
\}
|
||||||
\endcond
|
\endcond
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Returns a depth 3 image made of all drawings sent to the Fl_Image_Surface object.
|
/** Returns a depth-3 image made of all drawings sent to the Fl_Image_Surface object.
|
||||||
|
The returned object contains its own copy of the RGB data;
|
||||||
The returned object contains its own copy of the RGB data.
|
the caller is responsible for deleting it.
|
||||||
The caller is responsible for deleting the image.
|
|
||||||
|
\see Fl_Image_Surface::mask(Fl_RGB_Image*)
|
||||||
*/
|
*/
|
||||||
Fl_RGB_Image *Fl_Image_Surface::image() {
|
Fl_RGB_Image *Fl_Image_Surface::image() {
|
||||||
bool need_push = (Fl_Surface_Device::surface() != platform_surface);
|
bool need_push = (Fl_Surface_Device::surface() != platform_surface);
|
||||||
|
@ -152,6 +200,44 @@ void Fl_Image_Surface::rescale() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Defines a mask applied to drawings made after use of this function.
|
||||||
|
The mask is an Fl_RGB_Image made of a white scene drawn on a solid black
|
||||||
|
background; the drawable part of the image surface is reduced to the white areas of the mask
|
||||||
|
after this member function gets called. If necessary, the \p mask image is internally
|
||||||
|
replaced by a copy resized to the surface's pixel size.
|
||||||
|
Overall, the image returned by Fl_Image_Surface::image() contains all drawings made
|
||||||
|
until the mask() method assigned a mask, at which point subsequent drawing operations
|
||||||
|
to the image surface were passed through the white areas of the mask.
|
||||||
|
On some platforms, shades of gray in the mask image control the blending of
|
||||||
|
foreground and background pixels; mask pixels closer in color to white produce image pixels
|
||||||
|
closer to the image surface pixel, those closer to black produce image pixels closer to what the
|
||||||
|
image surface pixel was before the call to mask().
|
||||||
|
|
||||||
|
The mask is easily constructed using an Fl_Image_Surface object,
|
||||||
|
drawing white areas on a black background there, and calling Fl_Image_Surface::image().
|
||||||
|
\param mask A depth-3 image determining the drawable areas of the image surface.
|
||||||
|
The \p mask object is not used after return from this member function.
|
||||||
|
\note The image surface must not be the current drawing surface when this function
|
||||||
|
gets called. The mask can have any size but is best when it has the size of the image surface.
|
||||||
|
A typical procedure is to use the image surface to draw first the mask (using white over black),
|
||||||
|
call Fl_Image_Surface::image() to obtain the mask, then draw the background, call
|
||||||
|
Fl_Image_Surface::mask(mask), draw the foreground, and finally get the resulting
|
||||||
|
image from Fl_Image_Surface::image().
|
||||||
|
It's possible to use several masks in succession on the same image surface provided
|
||||||
|
member function Fl_Image_Surface::image() is called between successive calls to
|
||||||
|
Fl_Image_Surface::mask(Fl_RGB_Image*).
|
||||||
|
|
||||||
|
This diagram depicts operations involved in the construction of a masked image:
|
||||||
|
\image html masked_image.png "Construction of a masked image"
|
||||||
|
\image latex masked_image.png "Construction of a masked image" width=8cm
|
||||||
|
|
||||||
|
\since 1.4.0
|
||||||
|
*/
|
||||||
|
void Fl_Image_Surface::mask(const Fl_RGB_Image *mask) {
|
||||||
|
platform_surface->mask(mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// implementation of the fl_XXX_offscreen() functions
|
// implementation of the fl_XXX_offscreen() functions
|
||||||
|
|
||||||
static Fl_Image_Surface **offscreen_api_surface = NULL;
|
static Fl_Image_Surface **offscreen_api_surface = NULL;
|
||||||
|
|
|
@ -68,6 +68,7 @@ public:
|
||||||
cairo_t *cr() { return cairo_; }
|
cairo_t *cr() { return cairo_; }
|
||||||
PangoLayout *pango_layout() {return pango_layout_;}
|
PangoLayout *pango_layout() {return pango_layout_;}
|
||||||
void set_cairo(cairo_t *c, float f = 0);
|
void set_cairo(cairo_t *c, float f = 0);
|
||||||
|
static cairo_pattern_t *calc_cairo_mask(const Fl_RGB_Image *rgb);
|
||||||
|
|
||||||
void check_status(void);
|
void check_status(void);
|
||||||
|
|
||||||
|
|
|
@ -1517,4 +1517,41 @@ void Fl_Cairo_Graphics_Driver::focus_rect(int x, int y, int w, int h)
|
||||||
surface_needs_commit();
|
surface_needs_commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cairo_pattern_t *Fl_Cairo_Graphics_Driver::calc_cairo_mask(const Fl_RGB_Image *rgb) {
|
||||||
|
int i, j, d = rgb->d(), w = rgb->data_w(), h = rgb->data_h(), ld = rgb->ld();
|
||||||
|
int bytesperrow = cairo_format_stride_for_width(CAIRO_FORMAT_A1, w);
|
||||||
|
if (!ld) ld = d * w;
|
||||||
|
unsigned u;
|
||||||
|
uchar byte, onebit;
|
||||||
|
// build a CAIRO_FORMAT_A1 surface covering the non-black part of the image
|
||||||
|
uchar* bits = new uchar[h*bytesperrow]; // to store the surface data
|
||||||
|
for (i = 0; i < h; i++) {
|
||||||
|
const uchar* alpha = (const uchar*)*rgb->data() + i * ld;
|
||||||
|
uchar *p = (uchar*)bits + i * bytesperrow;
|
||||||
|
byte = 0;
|
||||||
|
onebit = 1;
|
||||||
|
for (j = 0; j < w; j++) {
|
||||||
|
u = *alpha;
|
||||||
|
u += *(alpha+1);
|
||||||
|
u += *(alpha+2);
|
||||||
|
if (u > 0) { // if the pixel is not black
|
||||||
|
byte |= onebit; // turn on the corresponding bit of the bitmap
|
||||||
|
}
|
||||||
|
onebit = onebit << 1; // move the single set bit one position to the left
|
||||||
|
if (onebit == 0 || j == w-1) {
|
||||||
|
onebit = 1;
|
||||||
|
*p++ = byte; // store in bitmap one pack of bits
|
||||||
|
byte = 0;
|
||||||
|
}
|
||||||
|
alpha += d; // point to next rgb pixel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cairo_surface_t *mask_surf = cairo_image_surface_create_for_data(bits,
|
||||||
|
CAIRO_FORMAT_A1, w, h, bytesperrow);
|
||||||
|
cairo_pattern_t *mask_pattern = cairo_pattern_create_for_surface(mask_surf);
|
||||||
|
cairo_surface_destroy(mask_surf);
|
||||||
|
return mask_pattern;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // USE_PANGO
|
#endif // USE_PANGO
|
||||||
|
|
|
@ -70,6 +70,7 @@ public:
|
||||||
|
|
||||||
// --- bitmap stuff
|
// --- bitmap stuff
|
||||||
static HBITMAP create_bitmask(int w, int h, const uchar *array); // NOT virtual
|
static HBITMAP create_bitmask(int w, int h, const uchar *array); // NOT virtual
|
||||||
|
static HBITMAP calc_HBITMAP_mask(Fl_RGB_Image *mask);
|
||||||
void delete_bitmask(fl_uintptr_t bm) FL_OVERRIDE;
|
void delete_bitmask(fl_uintptr_t bm) FL_OVERRIDE;
|
||||||
HBITMAP create_alphamask(int w, int h, int d, int ld, const uchar *array);
|
HBITMAP create_alphamask(int w, int h, int d, int ld, const uchar *array);
|
||||||
void draw_unscaled(const char* str, int n, int x, int y) FL_OVERRIDE;
|
void draw_unscaled(const char* str, int n, int x, int y) FL_OVERRIDE;
|
||||||
|
|
|
@ -26,6 +26,12 @@ class Fl_GDI_Image_Surface_Driver : public Fl_Image_Surface_Driver {
|
||||||
public:
|
public:
|
||||||
HWND pre_window;
|
HWND pre_window;
|
||||||
int _savedc;
|
int _savedc;
|
||||||
|
void mask(const Fl_RGB_Image *) FL_OVERRIDE;
|
||||||
|
struct shape_data_type {
|
||||||
|
HBITMAP background;
|
||||||
|
uchar *vBits;
|
||||||
|
Fl_RGB_Image* mask;
|
||||||
|
} *shape_data_;
|
||||||
Fl_GDI_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off);
|
Fl_GDI_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off);
|
||||||
~Fl_GDI_Image_Surface_Driver();
|
~Fl_GDI_Image_Surface_Driver();
|
||||||
void set_current() FL_OVERRIDE;
|
void set_current() FL_OVERRIDE;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "../WinAPI/Fl_WinAPI_Screen_Driver.H"
|
#include "../WinAPI/Fl_WinAPI_Screen_Driver.H"
|
||||||
#include "Fl_GDI_Image_Surface_Driver.H"
|
#include "Fl_GDI_Image_Surface_Driver.H"
|
||||||
#include <FL/platform.H>
|
#include <FL/platform.H>
|
||||||
|
#include <FL/Fl_Bitmap.H>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,10 +36,16 @@ Fl_GDI_Image_Surface_Driver::Fl_GDI_Image_Surface_Driver(int w, int h, int high_
|
||||||
driver(Fl_Graphics_Driver::newMainGraphicsDriver());
|
driver(Fl_Graphics_Driver::newMainGraphicsDriver());
|
||||||
if (d != 1 && high_res) ((Fl_GDI_Graphics_Driver*)driver())->scale(d);
|
if (d != 1 && high_res) ((Fl_GDI_Graphics_Driver*)driver())->scale(d);
|
||||||
origin.x = origin.y = 0;
|
origin.x = origin.y = 0;
|
||||||
|
shape_data_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Fl_GDI_Image_Surface_Driver::~Fl_GDI_Image_Surface_Driver() {
|
Fl_GDI_Image_Surface_Driver::~Fl_GDI_Image_Surface_Driver() {
|
||||||
|
if (shape_data_ && shape_data_->background) {
|
||||||
|
DeleteObject(shape_data_->background);
|
||||||
|
delete shape_data_->mask;
|
||||||
|
free(shape_data_);
|
||||||
|
}
|
||||||
if (offscreen && !external_offscreen) DeleteObject((HBITMAP)offscreen);
|
if (offscreen && !external_offscreen) DeleteObject((HBITMAP)offscreen);
|
||||||
delete driver();
|
delete driver();
|
||||||
}
|
}
|
||||||
|
@ -67,6 +74,43 @@ void Fl_GDI_Image_Surface_Driver::untranslate() {
|
||||||
|
|
||||||
Fl_RGB_Image* Fl_GDI_Image_Surface_Driver::image()
|
Fl_RGB_Image* Fl_GDI_Image_Surface_Driver::image()
|
||||||
{
|
{
|
||||||
|
if (shape_data_ && shape_data_->background) {
|
||||||
|
// get the offscreen size in pixels
|
||||||
|
HDC gc = fl_makeDC((HBITMAP)offscreen);
|
||||||
|
BITMAPINFO bmi;
|
||||||
|
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||||
|
bmi.bmiHeader.biCompression = BI_RGB;
|
||||||
|
bmi.bmiHeader.biPlanes = 1;
|
||||||
|
bmi.bmiHeader.biBitCount = 0;
|
||||||
|
bmi.bmiHeader.biSizeImage = 0;
|
||||||
|
GetDIBits(gc, (HBITMAP)offscreen, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
|
||||||
|
int W = bmi.bmiHeader.biWidth;
|
||||||
|
int H = bmi.bmiHeader.biHeight;
|
||||||
|
int line_size = ((3*W+3)/4) * 4;
|
||||||
|
|
||||||
|
// read bits of main offscreen
|
||||||
|
uchar *dib_src = new uchar[line_size * H];
|
||||||
|
bmi.bmiHeader.biWidth = W;
|
||||||
|
bmi.bmiHeader.biHeight = H;
|
||||||
|
bmi.bmiHeader.biCompression = BI_RGB;
|
||||||
|
bmi.bmiHeader.biBitCount = 24;
|
||||||
|
GetDIBits(gc, (HBITMAP)offscreen, 0, H,
|
||||||
|
dib_src, &bmi, DIB_RGB_COLORS);
|
||||||
|
|
||||||
|
// draw above the secondary offscreen the main offscreen masked by shape_data_->mask
|
||||||
|
GdiFlush();
|
||||||
|
Fl_Image_Surface_Driver::copy_with_mask(shape_data_->mask, shape_data_->vBits, dib_src, ((3*W+3)/4) * 4, true);
|
||||||
|
delete shape_data_->mask;
|
||||||
|
delete[] dib_src;
|
||||||
|
|
||||||
|
// write bits of main offscreen
|
||||||
|
SetDIBits(gc, (HBITMAP)offscreen, 0, H, shape_data_->vBits, &bmi, DIB_RGB_COLORS);
|
||||||
|
DeleteDC(gc);
|
||||||
|
DeleteObject(shape_data_->background);
|
||||||
|
shape_data_->background = NULL;
|
||||||
|
free(shape_data_);
|
||||||
|
shape_data_ = NULL;
|
||||||
|
}
|
||||||
Fl_RGB_Image *image = Fl::screen_driver()->read_win_rectangle( 0, 0, width, height, 0);
|
Fl_RGB_Image *image = Fl::screen_driver()->read_win_rectangle( 0, 0, width, height, 0);
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
@ -81,3 +125,45 @@ void Fl_GDI_Image_Surface_Driver::end_current()
|
||||||
fl_window = pre_window;
|
fl_window = pre_window;
|
||||||
Fl_Surface_Device::end_current();
|
Fl_Surface_Device::end_current();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Fl_GDI_Image_Surface_Driver::mask(const Fl_RGB_Image *mask) {
|
||||||
|
shape_data_ = (struct shape_data_type*)calloc(1, sizeof(struct shape_data_type));
|
||||||
|
// get the offscreen size in pixels
|
||||||
|
HDC gc = fl_makeDC((HBITMAP)offscreen);
|
||||||
|
BITMAPINFO bmi;
|
||||||
|
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||||
|
bmi.bmiHeader.biCompression = BI_RGB;
|
||||||
|
bmi.bmiHeader.biPlanes = 1;
|
||||||
|
bmi.bmiHeader.biBitCount = 0;
|
||||||
|
bmi.bmiHeader.biSizeImage = 0;
|
||||||
|
|
||||||
|
GetDIBits(gc, (HBITMAP)offscreen, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
|
||||||
|
int W = bmi.bmiHeader.biWidth;
|
||||||
|
int H = bmi.bmiHeader.biHeight;
|
||||||
|
|
||||||
|
shape_data_->mask = Fl_Image_Surface_Driver::RGB3_to_RGB1(mask, W, H);
|
||||||
|
|
||||||
|
// duplicate current offscreen content to new offscreen
|
||||||
|
int line_size = ((3*W+3)/4) * 4;
|
||||||
|
uchar *dib = new uchar[line_size * H]; // create temporary buffer to read DIB
|
||||||
|
bmi.bmiHeader.biWidth = W;
|
||||||
|
bmi.bmiHeader.biHeight = H;
|
||||||
|
bmi.bmiHeader.biCompression = BI_RGB;
|
||||||
|
bmi.bmiHeader.biBitCount = 24;
|
||||||
|
|
||||||
|
GetDIBits(gc, (HBITMAP)offscreen, 0, H, dib, &bmi, DIB_RGB_COLORS);
|
||||||
|
|
||||||
|
HDC background_gc = CreateCompatibleDC(gc);
|
||||||
|
shape_data_->background =
|
||||||
|
CreateDIBSection(background_gc, &bmi, DIB_RGB_COLORS,
|
||||||
|
(void**)&shape_data_->vBits, NULL, 0);
|
||||||
|
if (!shape_data_->background) {
|
||||||
|
Fl::error("CreateDIBSection error=%lu", GetLastError());
|
||||||
|
}
|
||||||
|
memcpy(shape_data_->vBits, dib, H * line_size);
|
||||||
|
delete[] dib;
|
||||||
|
DeleteDC(background_gc);
|
||||||
|
DeleteDC(gc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,11 @@
|
||||||
#include <FL/platform.H>
|
#include <FL/platform.H>
|
||||||
|
|
||||||
class Fl_Quartz_Image_Surface_Driver : public Fl_Image_Surface_Driver {
|
class Fl_Quartz_Image_Surface_Driver : public Fl_Image_Surface_Driver {
|
||||||
|
private:
|
||||||
|
# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
|
||||||
|
CGImageRef mask_;
|
||||||
|
void mask(const Fl_RGB_Image *) FL_OVERRIDE;
|
||||||
|
#endif
|
||||||
void end_current() FL_OVERRIDE;
|
void end_current() FL_OVERRIDE;
|
||||||
public:
|
public:
|
||||||
FLWindow *pre_window;
|
FLWindow *pre_window;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// Draw-to-image code for the Fast Light Tool Kit (FLTK).
|
// Draw-to-image code for the Fast Light Tool Kit (FLTK).
|
||||||
//
|
//
|
||||||
// Copyright 1998-2018 by Bill Spitzak and others.
|
// Copyright 1998-2023 by Bill Spitzak and others.
|
||||||
//
|
//
|
||||||
// This library is free software. Distribution and use rights are outlined in
|
// This library is free software. Distribution and use rights are outlined in
|
||||||
// the file "COPYING" which should have been included with this file. If this
|
// the file "COPYING" which should have been included with this file. If this
|
||||||
|
@ -23,6 +23,9 @@
|
||||||
|
|
||||||
|
|
||||||
Fl_Quartz_Image_Surface_Driver::Fl_Quartz_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off) : Fl_Image_Surface_Driver(w, h, high_res, off) {
|
Fl_Quartz_Image_Surface_Driver::Fl_Quartz_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off) : Fl_Image_Surface_Driver(w, h, high_res, off) {
|
||||||
|
# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
|
||||||
|
mask_ = NULL;
|
||||||
|
#endif
|
||||||
int W = w, H = h;
|
int W = w, H = h;
|
||||||
float s = 1;
|
float s = 1;
|
||||||
if (high_res) {
|
if (high_res) {
|
||||||
|
@ -49,6 +52,12 @@ Fl_Quartz_Image_Surface_Driver::Fl_Quartz_Image_Surface_Driver(int w, int h, int
|
||||||
}
|
}
|
||||||
|
|
||||||
Fl_Quartz_Image_Surface_Driver::~Fl_Quartz_Image_Surface_Driver() {
|
Fl_Quartz_Image_Surface_Driver::~Fl_Quartz_Image_Surface_Driver() {
|
||||||
|
# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
|
||||||
|
if (mask_) {
|
||||||
|
CGImageRelease(mask_);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (offscreen) CGContextRestoreGState((CGContextRef)offscreen);
|
||||||
if (offscreen && !external_offscreen) {
|
if (offscreen && !external_offscreen) {
|
||||||
void *data = CGBitmapContextGetData((CGContextRef)offscreen);
|
void *data = CGBitmapContextGetData((CGContextRef)offscreen);
|
||||||
free(data);
|
free(data);
|
||||||
|
@ -56,6 +65,7 @@ Fl_Quartz_Image_Surface_Driver::~Fl_Quartz_Image_Surface_Driver() {
|
||||||
}
|
}
|
||||||
delete driver();
|
delete driver();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Fl_Quartz_Image_Surface_Driver::set_current() {
|
void Fl_Quartz_Image_Surface_Driver::set_current() {
|
||||||
Fl_Surface_Device::set_current();
|
Fl_Surface_Device::set_current();
|
||||||
|
@ -63,6 +73,15 @@ void Fl_Quartz_Image_Surface_Driver::set_current() {
|
||||||
driver()->gc((CGContextRef)offscreen);
|
driver()->gc((CGContextRef)offscreen);
|
||||||
fl_window = 0;
|
fl_window = 0;
|
||||||
((Fl_Quartz_Graphics_Driver*)driver())->high_resolution( CGBitmapContextGetWidth((CGContextRef)offscreen) > (size_t)width );
|
((Fl_Quartz_Graphics_Driver*)driver())->high_resolution( CGBitmapContextGetWidth((CGContextRef)offscreen) > (size_t)width );
|
||||||
|
# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
|
||||||
|
if (mask_) {
|
||||||
|
int W, H;
|
||||||
|
printable_rect(&W, &H);
|
||||||
|
CGContextSaveGState((CGContextRef)offscreen);
|
||||||
|
CGContextClipToMask((CGContextRef)offscreen, CGRectMake(0,0,W,H), mask_); // 10.4
|
||||||
|
CGContextSaveGState((CGContextRef)offscreen);
|
||||||
|
}
|
||||||
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fl_Quartz_Image_Surface_Driver::translate(int x, int y) {
|
void Fl_Quartz_Image_Surface_Driver::translate(int x, int y) {
|
||||||
|
@ -79,6 +98,13 @@ void Fl_Quartz_Image_Surface_Driver::untranslate() {
|
||||||
Fl_RGB_Image* Fl_Quartz_Image_Surface_Driver::image()
|
Fl_RGB_Image* Fl_Quartz_Image_Surface_Driver::image()
|
||||||
{
|
{
|
||||||
CGContextFlush((CGContextRef)offscreen);
|
CGContextFlush((CGContextRef)offscreen);
|
||||||
|
# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
|
||||||
|
if (mask_) {
|
||||||
|
CGContextRestoreGState((CGContextRef)offscreen);
|
||||||
|
CGImageRelease(mask_);
|
||||||
|
mask_ = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
int W = (int)CGBitmapContextGetWidth((CGContextRef)offscreen);
|
int W = (int)CGBitmapContextGetWidth((CGContextRef)offscreen);
|
||||||
int H = (int)CGBitmapContextGetHeight((CGContextRef)offscreen);
|
int H = (int)CGBitmapContextGetHeight((CGContextRef)offscreen);
|
||||||
int bpr = (int)CGBitmapContextGetBytesPerRow((CGContextRef)offscreen);
|
int bpr = (int)CGBitmapContextGetBytesPerRow((CGContextRef)offscreen);
|
||||||
|
@ -101,6 +127,54 @@ Fl_RGB_Image* Fl_Quartz_Image_Surface_Driver::image()
|
||||||
|
|
||||||
void Fl_Quartz_Image_Surface_Driver::end_current()
|
void Fl_Quartz_Image_Surface_Driver::end_current()
|
||||||
{
|
{
|
||||||
|
# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
|
||||||
|
if (mask_) {
|
||||||
|
CGContextRestoreGState((CGContextRef)offscreen);
|
||||||
|
CGContextRestoreGState((CGContextRef)offscreen);
|
||||||
|
}
|
||||||
|
# endif
|
||||||
fl_window = pre_window;
|
fl_window = pre_window;
|
||||||
Fl_Surface_Device::end_current();
|
Fl_Surface_Device::end_current();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
|
||||||
|
|
||||||
|
static void MyProviderReleaseData (void *info, const void *data, size_t size) {
|
||||||
|
delete[] (uchar*)data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Fl_Quartz_Image_Surface_Driver::mask(const Fl_RGB_Image *img) {
|
||||||
|
if (!&CGContextClipToMask) return;
|
||||||
|
int W = (int)CGBitmapContextGetWidth((CGContextRef)offscreen);
|
||||||
|
int H = (int)CGBitmapContextGetHeight((CGContextRef)offscreen);
|
||||||
|
bool using_copy = false;
|
||||||
|
if (W != img->data_w() || H != img->data_h()) {
|
||||||
|
Fl_RGB_Image *copy = (Fl_RGB_Image*)img->copy(W, H);
|
||||||
|
img = copy;
|
||||||
|
using_copy = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i, d = img->d(), w = img->data_w(), h = img->data_h();
|
||||||
|
// reverse top and bottom and convert to gray scale if img->d() == 3 and complement bits
|
||||||
|
int bytes_per_row = (img->ld() ? img->ld() : w * d);
|
||||||
|
uchar *from = new uchar[w * h];
|
||||||
|
for ( i = 0; i < h; i++) {
|
||||||
|
const uchar *p = img->array + bytes_per_row * i;
|
||||||
|
const uchar *last = p + bytes_per_row;
|
||||||
|
uchar *q = from + (h - 1 - i) * w;
|
||||||
|
while (p < last) {
|
||||||
|
unsigned u = *p++;
|
||||||
|
u += *p++;
|
||||||
|
u += *p++;
|
||||||
|
*q++ = ~(u/3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, from, w * h, MyProviderReleaseData);
|
||||||
|
mask_ = CGImageMaskCreate(w, h, 8, 8, w, provider, NULL, false);
|
||||||
|
CFRelease(provider);
|
||||||
|
if (using_copy) delete img;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -25,6 +25,12 @@ class Fl_Wayland_Image_Surface_Driver : public Fl_Image_Surface_Driver {
|
||||||
public:
|
public:
|
||||||
Fl_Wayland_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off);
|
Fl_Wayland_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off);
|
||||||
~Fl_Wayland_Image_Surface_Driver();
|
~Fl_Wayland_Image_Surface_Driver();
|
||||||
|
void mask(const Fl_RGB_Image *) FL_OVERRIDE;
|
||||||
|
struct shape_data_type {
|
||||||
|
double scale;
|
||||||
|
cairo_pattern_t *mask_pattern_;
|
||||||
|
cairo_t *bg_cr;
|
||||||
|
} *shape_data_;
|
||||||
void set_current() FL_OVERRIDE;
|
void set_current() FL_OVERRIDE;
|
||||||
void translate(int x, int y) FL_OVERRIDE;
|
void translate(int x, int y) FL_OVERRIDE;
|
||||||
void untranslate() FL_OVERRIDE;
|
void untranslate() FL_OVERRIDE;
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
Fl_Wayland_Image_Surface_Driver::Fl_Wayland_Image_Surface_Driver(int w, int h,
|
Fl_Wayland_Image_Surface_Driver::Fl_Wayland_Image_Surface_Driver(int w, int h,
|
||||||
int high_res, Fl_Offscreen off) : Fl_Image_Surface_Driver(w, h, high_res, off) {
|
int high_res, Fl_Offscreen off) : Fl_Image_Surface_Driver(w, h, high_res, off) {
|
||||||
|
shape_data_ = NULL;
|
||||||
float s = 1;
|
float s = 1;
|
||||||
int d = 1;
|
int d = 1;
|
||||||
if (!off) {
|
if (!off) {
|
||||||
|
@ -51,6 +52,19 @@ Fl_Wayland_Image_Surface_Driver::Fl_Wayland_Image_Surface_Driver(int w, int h,
|
||||||
|
|
||||||
|
|
||||||
Fl_Wayland_Image_Surface_Driver::~Fl_Wayland_Image_Surface_Driver() {
|
Fl_Wayland_Image_Surface_Driver::~Fl_Wayland_Image_Surface_Driver() {
|
||||||
|
if (shape_data_) {
|
||||||
|
cairo_surface_t *surf;
|
||||||
|
cairo_pattern_get_surface(shape_data_->mask_pattern_, &surf);
|
||||||
|
unsigned char *bits = cairo_image_surface_get_data(surf);
|
||||||
|
cairo_pattern_destroy(shape_data_->mask_pattern_);
|
||||||
|
delete[] bits;
|
||||||
|
struct Fl_Wayland_Graphics_Driver::draw_buffer *off_ =
|
||||||
|
Fl_Wayland_Graphics_Driver::offscreen_buffer((Fl_Offscreen)shape_data_->bg_cr);
|
||||||
|
delete[] off_->buffer;
|
||||||
|
free(off_);
|
||||||
|
cairo_destroy(shape_data_->bg_cr);
|
||||||
|
free(shape_data_);
|
||||||
|
}
|
||||||
if (offscreen && !external_offscreen) {
|
if (offscreen && !external_offscreen) {
|
||||||
struct Fl_Wayland_Graphics_Driver::draw_buffer *buffer =
|
struct Fl_Wayland_Graphics_Driver::draw_buffer *buffer =
|
||||||
Fl_Wayland_Graphics_Driver::offscreen_buffer(offscreen);
|
Fl_Wayland_Graphics_Driver::offscreen_buffer(offscreen);
|
||||||
|
@ -91,10 +105,38 @@ void Fl_Wayland_Image_Surface_Driver::untranslate() {
|
||||||
|
|
||||||
|
|
||||||
Fl_RGB_Image* Fl_Wayland_Image_Surface_Driver::image() {
|
Fl_RGB_Image* Fl_Wayland_Image_Surface_Driver::image() {
|
||||||
|
if (shape_data_ && shape_data_->mask_pattern_) {
|
||||||
|
// draw above the secondary offscreen the main offscreen masked by mask_pattern_
|
||||||
|
cairo_t *c = ((Fl_Cairo_Graphics_Driver*)driver())->cr();
|
||||||
|
cairo_pattern_t *paint_pattern = cairo_pattern_create_for_surface(cairo_get_target(c));
|
||||||
|
cairo_set_source(shape_data_->bg_cr, paint_pattern);
|
||||||
|
cairo_mask(shape_data_->bg_cr, shape_data_->mask_pattern_);
|
||||||
|
cairo_pattern_destroy(paint_pattern);
|
||||||
|
// copy secondary offscreen to the main offscreen
|
||||||
|
cairo_pattern_t *pat = cairo_pattern_create_for_surface(cairo_get_target(shape_data_->bg_cr));
|
||||||
|
cairo_scale(c, shape_data_->scale, shape_data_->scale);
|
||||||
|
cairo_set_source(c, pat),
|
||||||
|
cairo_paint(c);
|
||||||
|
cairo_pattern_destroy(pat);
|
||||||
|
// delete secondary offscreen
|
||||||
|
cairo_surface_t *surf;
|
||||||
|
cairo_pattern_get_surface(shape_data_->mask_pattern_, &surf);
|
||||||
|
unsigned char *bits = cairo_image_surface_get_data(surf);
|
||||||
|
cairo_pattern_destroy(shape_data_->mask_pattern_);
|
||||||
|
delete[] bits;
|
||||||
|
struct Fl_Wayland_Graphics_Driver::draw_buffer *off_ =
|
||||||
|
Fl_Wayland_Graphics_Driver::offscreen_buffer((Fl_Offscreen)shape_data_->bg_cr);
|
||||||
|
delete[] off_->buffer;
|
||||||
|
free(off_);
|
||||||
|
cairo_destroy(shape_data_->bg_cr);
|
||||||
|
free(shape_data_);
|
||||||
|
shape_data_ = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Convert depth-4 image in draw_buffer to a depth-3 image while exchanging R and B colors
|
// Convert depth-4 image in draw_buffer to a depth-3 image while exchanging R and B colors
|
||||||
struct Fl_Wayland_Graphics_Driver::draw_buffer *off_buf =
|
struct Fl_Wayland_Graphics_Driver::draw_buffer *off_buf =
|
||||||
Fl_Wayland_Graphics_Driver::offscreen_buffer(offscreen);
|
Fl_Wayland_Graphics_Driver::offscreen_buffer(offscreen);
|
||||||
int height = off_buf->data_size / off_buf->stride;
|
int height = int(off_buf->data_size / off_buf->stride);
|
||||||
uchar *rgb = new uchar[off_buf->width * height * 3];
|
uchar *rgb = new uchar[off_buf->width * height * 3];
|
||||||
uchar *p = rgb;
|
uchar *p = rgb;
|
||||||
uchar *q;
|
uchar *q;
|
||||||
|
@ -111,3 +153,34 @@ Fl_RGB_Image* Fl_Wayland_Image_Surface_Driver::image() {
|
||||||
image->alloc_array = 1;
|
image->alloc_array = 1;
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Fl_Wayland_Image_Surface_Driver::mask(const Fl_RGB_Image *mask) {
|
||||||
|
bool using_copy = false;
|
||||||
|
shape_data_ = (struct shape_data_type*)calloc(1, sizeof(struct shape_data_type));
|
||||||
|
int W, H;
|
||||||
|
struct Fl_Wayland_Graphics_Driver::draw_buffer *off_buf =
|
||||||
|
Fl_Wayland_Graphics_Driver::offscreen_buffer(offscreen);
|
||||||
|
W = off_buf->width;
|
||||||
|
H = (int)(off_buf->data_size / off_buf->stride);
|
||||||
|
if (W != mask->data_w() || H != mask->data_h()) {
|
||||||
|
Fl_RGB_Image *copy = (Fl_RGB_Image*)mask->copy(W, H);
|
||||||
|
mask = copy;
|
||||||
|
using_copy = true;
|
||||||
|
}
|
||||||
|
shape_data_->mask_pattern_ = Fl_Cairo_Graphics_Driver::calc_cairo_mask(mask);
|
||||||
|
//duplicate current offscreen content to new cairo_t* shape_data_->bg_cr
|
||||||
|
int width, height;
|
||||||
|
printable_rect(&width, &height);
|
||||||
|
struct Fl_Wayland_Graphics_Driver::draw_buffer *off_ =
|
||||||
|
(struct Fl_Wayland_Graphics_Driver::draw_buffer*)calloc(1,
|
||||||
|
sizeof(struct Fl_Wayland_Graphics_Driver::draw_buffer));
|
||||||
|
Fl_Wayland_Graphics_Driver::cairo_init(off_, W, H,
|
||||||
|
cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, W),
|
||||||
|
CAIRO_FORMAT_RGB24);
|
||||||
|
cairo_set_user_data(off_->cairo_, &Fl_Wayland_Graphics_Driver::key, off_, NULL);
|
||||||
|
shape_data_->bg_cr = off_->cairo_;
|
||||||
|
memcpy(off_->buffer, off_buf->buffer, off_buf->data_size);
|
||||||
|
shape_data_->scale = double(width) / W;
|
||||||
|
if (using_copy) delete mask;
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// Draw-to-image code for the Fast Light Tool Kit (FLTK).
|
// Draw-to-image code for the Fast Light Tool Kit (FLTK).
|
||||||
//
|
//
|
||||||
// Copyright 2022 by Bill Spitzak and others.
|
// Copyright 2022-2023 by Bill Spitzak and others.
|
||||||
//
|
//
|
||||||
// This library is free software. Distribution and use rights are outlined in
|
// This library is free software. Distribution and use rights are outlined in
|
||||||
// the file "COPYING" which should have been included with this file. If this
|
// the file "COPYING" which should have been included with this file. If this
|
||||||
|
@ -32,8 +32,19 @@ public:
|
||||||
void translate(int x, int y) FL_OVERRIDE;
|
void translate(int x, int y) FL_OVERRIDE;
|
||||||
void untranslate() FL_OVERRIDE;
|
void untranslate() FL_OVERRIDE;
|
||||||
Fl_RGB_Image *image() FL_OVERRIDE;
|
Fl_RGB_Image *image() FL_OVERRIDE;
|
||||||
|
void mask(const Fl_RGB_Image *) FL_OVERRIDE;
|
||||||
#if FLTK_USE_CAIRO
|
#if FLTK_USE_CAIRO
|
||||||
cairo_t *cairo_;
|
cairo_t *cairo_;
|
||||||
|
struct shape_data_type {
|
||||||
|
double scale;
|
||||||
|
cairo_pattern_t *mask_pattern_;
|
||||||
|
cairo_t *bg_cr;
|
||||||
|
} *shape_data_;
|
||||||
|
#else
|
||||||
|
struct shape_data_type {
|
||||||
|
Pixmap background;
|
||||||
|
Fl_RGB_Image* mask;
|
||||||
|
} *shape_data_;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <FL/platform.H>
|
#include <FL/platform.H>
|
||||||
#include "Fl_Xlib_Image_Surface_Driver.H"
|
#include "Fl_Xlib_Image_Surface_Driver.H"
|
||||||
#include "../../Fl_Screen_Driver.H"
|
#include "../../Fl_Screen_Driver.H"
|
||||||
|
#include <stdlib.h>
|
||||||
#if FLTK_USE_CAIRO
|
#if FLTK_USE_CAIRO
|
||||||
# include <cairo-xlib.h>
|
# include <cairo-xlib.h>
|
||||||
# include "../Cairo/Fl_X11_Cairo_Graphics_Driver.H"
|
# include "../Cairo/Fl_X11_Cairo_Graphics_Driver.H"
|
||||||
|
@ -37,6 +38,7 @@ Fl_Xlib_Image_Surface_Driver::Fl_Xlib_Image_Surface_Driver(int w, int h, int hig
|
||||||
}
|
}
|
||||||
offscreen = (Fl_Offscreen)XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), w, h, fl_visual->depth);
|
offscreen = (Fl_Offscreen)XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), w, h, fl_visual->depth);
|
||||||
}
|
}
|
||||||
|
shape_data_ = NULL;
|
||||||
#if FLTK_USE_CAIRO
|
#if FLTK_USE_CAIRO
|
||||||
driver(new Fl_X11_Cairo_Graphics_Driver());
|
driver(new Fl_X11_Cairo_Graphics_Driver());
|
||||||
cairo_surface_t *s = cairo_xlib_surface_create(fl_display, offscreen, fl_visual->visual, w, h);
|
cairo_surface_t *s = cairo_xlib_surface_create(fl_display, offscreen, fl_visual->visual, w, h);
|
||||||
|
@ -52,7 +54,24 @@ Fl_Xlib_Image_Surface_Driver::Fl_Xlib_Image_Surface_Driver(int w, int h, int hig
|
||||||
|
|
||||||
Fl_Xlib_Image_Surface_Driver::~Fl_Xlib_Image_Surface_Driver() {
|
Fl_Xlib_Image_Surface_Driver::~Fl_Xlib_Image_Surface_Driver() {
|
||||||
#if FLTK_USE_CAIRO
|
#if FLTK_USE_CAIRO
|
||||||
|
if (shape_data_) {
|
||||||
|
cairo_surface_t *surf;
|
||||||
|
cairo_pattern_get_surface(shape_data_->mask_pattern_, &surf);
|
||||||
|
unsigned char *bits = cairo_image_surface_get_data(surf);
|
||||||
|
cairo_pattern_destroy(shape_data_->mask_pattern_);
|
||||||
|
delete[] bits;
|
||||||
|
Pixmap p = cairo_xlib_surface_get_drawable(cairo_get_target(shape_data_->bg_cr));
|
||||||
|
XFreePixmap(fl_display, p);
|
||||||
|
cairo_destroy(shape_data_->bg_cr);
|
||||||
|
free(shape_data_);
|
||||||
|
}
|
||||||
cairo_destroy(cairo_);
|
cairo_destroy(cairo_);
|
||||||
|
#else
|
||||||
|
if (shape_data_) {
|
||||||
|
XFreePixmap(fl_display, shape_data_->background);
|
||||||
|
delete shape_data_->mask;
|
||||||
|
free(shape_data_);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (offscreen && !external_offscreen) XFreePixmap(fl_display, (Pixmap)offscreen);
|
if (offscreen && !external_offscreen) XFreePixmap(fl_display, (Pixmap)offscreen);
|
||||||
delete driver();
|
delete driver();
|
||||||
|
@ -84,14 +103,117 @@ void Fl_Xlib_Image_Surface_Driver::untranslate() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Fl_RGB_Image* Fl_Xlib_Image_Surface_Driver::image()
|
Fl_RGB_Image* Fl_Xlib_Image_Surface_Driver::image()
|
||||||
{
|
{
|
||||||
|
if (shape_data_) {
|
||||||
|
#if FLTK_USE_CAIRO
|
||||||
|
// draw above the secondary offscreen the main offscreen masked by mask_pattern_
|
||||||
|
cairo_t *c = ((Fl_Cairo_Graphics_Driver*)driver())->cr();
|
||||||
|
cairo_pattern_t *paint_pattern = cairo_pattern_create_for_surface(cairo_get_target(c));
|
||||||
|
cairo_set_source(shape_data_->bg_cr, paint_pattern);
|
||||||
|
cairo_mask(shape_data_->bg_cr, shape_data_->mask_pattern_);
|
||||||
|
cairo_pattern_destroy(paint_pattern);
|
||||||
|
// copy secondary offscreen to the main offscreen
|
||||||
|
cairo_pattern_t *pat = cairo_pattern_create_for_surface(cairo_get_target(shape_data_->bg_cr));
|
||||||
|
cairo_scale(c, shape_data_->scale, shape_data_->scale);
|
||||||
|
cairo_set_source(c, pat),
|
||||||
|
cairo_paint(c);
|
||||||
|
cairo_pattern_destroy(pat);
|
||||||
|
// delete secondary offscreen
|
||||||
|
cairo_surface_t *surf;
|
||||||
|
cairo_pattern_get_surface(shape_data_->mask_pattern_, &surf);
|
||||||
|
unsigned char *bits = cairo_image_surface_get_data(surf);
|
||||||
|
cairo_pattern_destroy(shape_data_->mask_pattern_);
|
||||||
|
delete[] bits;
|
||||||
|
Pixmap p = cairo_xlib_surface_get_drawable(cairo_get_target(shape_data_->bg_cr));
|
||||||
|
XFreePixmap(fl_display, p);
|
||||||
|
cairo_destroy(shape_data_->bg_cr);
|
||||||
|
#else // !FLTK_USE_CAIRO
|
||||||
|
// draw the main offscreen masked by shape_data_->mask above the background offscreen
|
||||||
|
int w, h;
|
||||||
|
printable_rect(&w, &h);
|
||||||
|
Fl_RGB_Image *img_main = Fl::screen_driver()->read_win_rectangle(0, 0, w, h, 0);
|
||||||
|
fl_window = shape_data_->background; // temporary change
|
||||||
|
Fl_RGB_Image *img_background = Fl::screen_driver()->read_win_rectangle(0, 0, w, h, 0);
|
||||||
|
fl_window = offscreen;
|
||||||
|
Fl_Image_Surface_Driver::copy_with_mask(shape_data_->mask,
|
||||||
|
(uchar*)img_background->array,
|
||||||
|
(uchar*)img_main->array,
|
||||||
|
3 * shape_data_->mask->w(), false);
|
||||||
|
delete img_main;
|
||||||
|
// copy background offscreen to main offscreen
|
||||||
|
float s = driver()->scale();
|
||||||
|
driver()->scale(1);
|
||||||
|
fl_draw_image(img_background->array, 0, 0,
|
||||||
|
img_background->data_w(), img_background->data_h());
|
||||||
|
driver()->scale(s);
|
||||||
|
delete img_background;
|
||||||
|
// delete background offscreen
|
||||||
|
XFreePixmap(fl_display, shape_data_->background);
|
||||||
|
delete shape_data_->mask;
|
||||||
|
#endif // FLTK_USE_CAIRO
|
||||||
|
free(shape_data_);
|
||||||
|
shape_data_ = NULL;
|
||||||
|
}
|
||||||
Fl_RGB_Image *image = Fl::screen_driver()->read_win_rectangle(0, 0, width, height, 0);
|
Fl_RGB_Image *image = Fl::screen_driver()->read_win_rectangle(0, 0, width, height, 0);
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Fl_Xlib_Image_Surface_Driver::end_current()
|
void Fl_Xlib_Image_Surface_Driver::end_current()
|
||||||
{
|
{
|
||||||
fl_window = pre_window;
|
fl_window = pre_window;
|
||||||
Fl_Surface_Device::end_current();
|
Fl_Surface_Device::end_current();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if FLTK_USE_CAIRO
|
||||||
|
|
||||||
|
void Fl_Xlib_Image_Surface_Driver::mask(const Fl_RGB_Image *mask) {
|
||||||
|
bool using_copy = false;
|
||||||
|
shape_data_ = (struct shape_data_type*)calloc(1, sizeof(struct shape_data_type));
|
||||||
|
int W, H;
|
||||||
|
cairo_t *c = ((Fl_Cairo_Graphics_Driver*)driver())->cr();
|
||||||
|
cairo_surface_t *c_surface = cairo_get_target(c);
|
||||||
|
W = cairo_xlib_surface_get_width(c_surface);
|
||||||
|
H = cairo_xlib_surface_get_height(c_surface);
|
||||||
|
if (W != mask->data_w() || H != mask->data_h()) {
|
||||||
|
Fl_RGB_Image *copy = (Fl_RGB_Image*)mask->copy(W, H);
|
||||||
|
mask = copy;
|
||||||
|
using_copy = true;
|
||||||
|
}
|
||||||
|
shape_data_->mask_pattern_ = Fl_Cairo_Graphics_Driver::calc_cairo_mask(mask);
|
||||||
|
//duplicate current offscreen content to new cairo_t* shape_data_->bg_cr
|
||||||
|
int width, height;
|
||||||
|
printable_rect(&width, &height);
|
||||||
|
Pixmap pxm = XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), W, H, fl_visual->depth);
|
||||||
|
cairo_surface_t *background = cairo_xlib_surface_create(fl_display, pxm, fl_visual->visual, W, H);
|
||||||
|
shape_data_->bg_cr = cairo_create(background);
|
||||||
|
cairo_surface_destroy(background);
|
||||||
|
cairo_surface_flush(c_surface);
|
||||||
|
cairo_pattern_t *pat = cairo_pattern_create_for_surface(c_surface);
|
||||||
|
cairo_set_source(shape_data_->bg_cr, pat),
|
||||||
|
cairo_paint(shape_data_->bg_cr);
|
||||||
|
cairo_pattern_destroy(pat);
|
||||||
|
shape_data_->scale = double(width) / W;
|
||||||
|
if (using_copy) delete mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
void Fl_Xlib_Image_Surface_Driver::mask(const Fl_RGB_Image *mask) {
|
||||||
|
shape_data_ = (struct shape_data_type*)calloc(1, sizeof(struct shape_data_type));
|
||||||
|
// get dimensions
|
||||||
|
int W, H;
|
||||||
|
Fl::screen_driver()->offscreen_size(offscreen, W, H);
|
||||||
|
// compute depth-1 mask
|
||||||
|
shape_data_->mask = Fl_Image_Surface_Driver::RGB3_to_RGB1(mask, W, H);
|
||||||
|
|
||||||
|
// duplicate current offscreen content to new, background offscreen
|
||||||
|
shape_data_->background = XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), W, H, fl_visual->depth);
|
||||||
|
driver()->restore_clip();
|
||||||
|
XCopyArea(fl_display, (Pixmap)offscreen, shape_data_->background, (GC)driver()->gc(), 0, 0, W, H, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FLTK_USE_CAIRO
|
||||||
|
|
|
@ -505,7 +505,7 @@ void copy(Fl_Widget *, void *data) {
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(operation, "Fl_Copy_Surface") == 0) {
|
if (strcmp(operation, "Fl_Copy_Surface") == 0) {
|
||||||
Fl_Copy_Surface *copy_surf;
|
Fl_Copy_Surface *copy_surf;
|
||||||
if (target->as_window() && !target->parent()) {
|
if (target->as_window() && !target->parent()) {
|
||||||
|
@ -521,8 +521,8 @@ void copy(Fl_Widget *, void *data) {
|
||||||
}
|
}
|
||||||
delete copy_surf;
|
delete copy_surf;
|
||||||
Fl_Surface_Device::pop_current();
|
Fl_Surface_Device::pop_current();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(operation, "Fl_Printer") == 0 || strcmp(operation, "Fl_PostScript_File_Device") == 0) {
|
if (strcmp(operation, "Fl_Printer") == 0 || strcmp(operation, "Fl_PostScript_File_Device") == 0) {
|
||||||
Fl_Paged_Device *p;
|
Fl_Paged_Device *p;
|
||||||
int err;
|
int err;
|
||||||
|
@ -549,7 +549,7 @@ void copy(Fl_Widget *, void *data) {
|
||||||
} else if (err > 1 && err_message) {fl_alert("%s", err_message); delete[] err_message;}
|
} else if (err > 1 && err_message) {fl_alert("%s", err_message); delete[] err_message;}
|
||||||
delete p;
|
delete p;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(operation, "Fl_EPS_File_Surface") == 0) {
|
if (strcmp(operation, "Fl_EPS_File_Surface") == 0) {
|
||||||
Fl_Native_File_Chooser fnfc;
|
Fl_Native_File_Chooser fnfc;
|
||||||
fnfc.title("Save a .eps file");
|
fnfc.title("Save a .eps file");
|
||||||
|
@ -575,7 +575,7 @@ void copy(Fl_Widget *, void *data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(operation, "Fl_SVG_File_Surface") == 0) {
|
if (strcmp(operation, "Fl_SVG_File_Surface") == 0) {
|
||||||
Fl_Native_File_Chooser fnfc;
|
Fl_Native_File_Chooser fnfc;
|
||||||
fnfc.title("Save a .svg file");
|
fnfc.title("Save a .svg file");
|
||||||
|
@ -602,7 +602,7 @@ void copy(Fl_Widget *, void *data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(operation, "fl_capture_window()") == 0) {
|
if (strcmp(operation, "fl_capture_window()") == 0) {
|
||||||
Fl_Window *win = target->as_window() ? target->as_window() : target->window();
|
Fl_Window *win = target->as_window() ? target->as_window() : target->window();
|
||||||
int X = target->as_window() ? 0 : target->x();
|
int X = target->as_window() ? 0 : target->x();
|
||||||
|
@ -618,6 +618,42 @@ void copy(Fl_Widget *, void *data) {
|
||||||
g2->show();
|
g2->show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strcmp(operation, "Fl_Image_Surface::mask()") == 0) {
|
||||||
|
Fl_Image_Surface *surf = new Fl_Image_Surface(target->w(), target->h(), 1);
|
||||||
|
Fl_Surface_Device::push_current(surf);
|
||||||
|
fl_color(FL_BLACK);
|
||||||
|
fl_rectf(0, 0, target->w(), target->h());
|
||||||
|
fl_color(FL_WHITE);
|
||||||
|
fl_pie(0, 0, target->w(), target->h(), 0, 360);
|
||||||
|
if (target->top_window() == target) {
|
||||||
|
fl_color(FL_BLACK);
|
||||||
|
int mini = (target->w() < target->h() ? target->w() : target->h()) * 0.66;
|
||||||
|
fl_pie(target->w()/2 - mini/2, target->h()/2 - mini/2, mini, mini, 0, 360);
|
||||||
|
fl_color(FL_WHITE);
|
||||||
|
fl_font(FL_TIMES_BOLD, 120);
|
||||||
|
int dx, dy, l, h;
|
||||||
|
fl_text_extents("FLTK", dx, dy, l, h);
|
||||||
|
fl_draw("FLTK", target->w()/2 - l/2, target->h()/2 + h/2);
|
||||||
|
}
|
||||||
|
Fl_RGB_Image *mask = surf->image();
|
||||||
|
fl_color(FL_YELLOW);
|
||||||
|
fl_rectf(0, 0, target->w(), target->h());
|
||||||
|
Fl_Surface_Device::pop_current();
|
||||||
|
surf->mask(mask);
|
||||||
|
delete mask;
|
||||||
|
Fl_Surface_Device::push_current(surf);
|
||||||
|
surf->draw(target, 0, 0);
|
||||||
|
mask = surf->image();
|
||||||
|
Fl_Surface_Device::pop_current();
|
||||||
|
delete surf;
|
||||||
|
Fl_Window *win = new Fl_Window(mask->w(), mask->h(), operation);
|
||||||
|
Fl_Box *box = new Fl_Box(0, 0, mask->w(), mask->h());
|
||||||
|
box->bind_image(mask);
|
||||||
|
win->end();
|
||||||
|
win->show();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class My_Button:public Fl_Button {
|
class My_Button:public Fl_Button {
|
||||||
|
@ -650,7 +686,7 @@ void operation_cb(Fl_Widget* wid, void *data)
|
||||||
|
|
||||||
int main(int argc, char ** argv) {
|
int main(int argc, char ** argv) {
|
||||||
|
|
||||||
Fl::scheme("plastic");
|
//Fl::scheme("plastic");
|
||||||
|
|
||||||
Fl_Window * w2 = new Fl_Window(500,568,"Graphics test");
|
Fl_Window * w2 = new Fl_Window(500,568,"Graphics test");
|
||||||
|
|
||||||
|
@ -730,6 +766,7 @@ int main(int argc, char ** argv) {
|
||||||
rb = new Fl_Radio_Round_Button(5,30,150,12, "Fl_EPS_File_Surface"); rb->callback(operation_cb, NULL); rb->labelsize(12);
|
rb = new Fl_Radio_Round_Button(5,30,150,12, "Fl_EPS_File_Surface"); rb->callback(operation_cb, NULL); rb->labelsize(12);
|
||||||
rb = new Fl_Radio_Round_Button(170,30,150,12, "Fl_SVG_File_Surface"); rb->callback(operation_cb, NULL); rb->labelsize(12);
|
rb = new Fl_Radio_Round_Button(170,30,150,12, "Fl_SVG_File_Surface"); rb->callback(operation_cb, NULL); rb->labelsize(12);
|
||||||
rb = new Fl_Radio_Round_Button(5,43,150,12, "fl_capture_window()"); rb->callback(operation_cb, NULL); rb->labelsize(12);
|
rb = new Fl_Radio_Round_Button(5,43,150,12, "fl_capture_window()"); rb->callback(operation_cb, NULL); rb->labelsize(12);
|
||||||
|
rb = new Fl_Radio_Round_Button(170,43,150,12, "Fl_Image_Surface::mask()"); rb->callback(operation_cb, NULL); rb->labelsize(12);
|
||||||
g1->end();
|
g1->end();
|
||||||
|
|
||||||
Fl_Group *g2 = new Fl_Group(0,0,w3->w(),w3->h());
|
Fl_Group *g2 = new Fl_Group(0,0,w3->w(),w3->h());
|
||||||
|
|
Loading…
Reference in New Issue