DRC | 2ff39b8 | 2011-07-28 08:38:59 +0000 | [diff] [blame] | 1 | // |
| 2 | // "$Id: Fl_Image.cxx 8611 2011-04-20 14:01:04Z AlbrechtS $" |
| 3 | // |
| 4 | // Image drawing code for the Fast Light Tool Kit (FLTK). |
| 5 | // |
| 6 | // Copyright 1998-2010 by Bill Spitzak and others. |
| 7 | // |
| 8 | // This library is free software; you can redistribute it and/or |
| 9 | // modify it under the terms of the GNU Library General Public |
| 10 | // License as published by the Free Software Foundation; either |
| 11 | // version 2 of the License, or (at your option) any later version. |
| 12 | // |
| 13 | // This library is distributed in the hope that it will be useful, |
| 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 16 | // Library General Public License for more details. |
| 17 | // |
| 18 | // You should have received a copy of the GNU Library General Public |
| 19 | // License along with this library; if not, write to the Free Software |
| 20 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
| 21 | // USA. |
| 22 | // |
| 23 | // Please report all bugs and problems on the following page: |
| 24 | // |
| 25 | // http://www.fltk.org/str.php |
| 26 | // |
| 27 | |
| 28 | #include <FL/Fl.H> |
| 29 | #include <FL/fl_draw.H> |
| 30 | #include <FL/x.H> |
| 31 | #include <FL/Fl_Widget.H> |
| 32 | #include <FL/Fl_Menu_Item.H> |
| 33 | #include <FL/Fl_Image.H> |
| 34 | #include "flstring.h" |
| 35 | |
| 36 | #ifdef WIN32 |
| 37 | void fl_release_dc(HWND, HDC); // from Fl_win32.cxx |
| 38 | #endif |
| 39 | |
| 40 | void fl_restore_clip(); // from fl_rect.cxx |
| 41 | |
| 42 | // |
| 43 | // Base image class... |
| 44 | // |
| 45 | |
| 46 | /** |
| 47 | The destructor is a virtual method that frees all memory used |
| 48 | by the image. |
| 49 | */ |
| 50 | Fl_Image::~Fl_Image() { |
| 51 | } |
| 52 | |
| 53 | /** |
| 54 | If the image has been cached for display, delete the cache |
| 55 | data. This allows you to change the data used for the image and |
| 56 | then redraw it without recreating an image object. |
| 57 | */ |
| 58 | void Fl_Image::uncache() { |
| 59 | } |
| 60 | |
| 61 | void Fl_Image::draw(int XP, int YP, int, int, int, int) { |
| 62 | draw_empty(XP, YP); |
| 63 | } |
| 64 | |
| 65 | /** |
| 66 | The protected method draw_empty() draws a box with |
| 67 | an X in it. It can be used to draw any image that lacks image |
| 68 | data. |
| 69 | */ |
| 70 | void Fl_Image::draw_empty(int X, int Y) { |
| 71 | if (w() > 0 && h() > 0) { |
| 72 | fl_color(FL_FOREGROUND_COLOR); |
| 73 | fl_rect(X, Y, w(), h()); |
| 74 | fl_line(X, Y, X + w() - 1, Y + h() - 1); |
| 75 | fl_line(X, Y + h() - 1, X + w() - 1, Y); |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | /** |
| 80 | The copy() method creates a copy of the specified |
| 81 | image. If the width and height are provided, the image is |
| 82 | resized to the specified size. The image should be deleted (or in |
| 83 | the case of Fl_Shared_Image, released) when you are done |
| 84 | with it. |
| 85 | */ |
| 86 | Fl_Image *Fl_Image::copy(int W, int H) { |
| 87 | return new Fl_Image(W, H, d()); |
| 88 | } |
| 89 | |
| 90 | /** |
| 91 | The color_average() method averages the colors in |
| 92 | the image with the FLTK color value c. The i |
| 93 | argument specifies the amount of the original image to combine |
| 94 | with the color, so a value of 1.0 results in no color blend, and |
| 95 | a value of 0.0 results in a constant image of the specified |
| 96 | color. <I>The original image data is not altered by this |
| 97 | method.</I> |
| 98 | */ |
| 99 | void Fl_Image::color_average(Fl_Color, float) { |
| 100 | } |
| 101 | |
| 102 | /** |
| 103 | The desaturate() method converts an image to |
| 104 | grayscale. If the image contains an alpha channel (depth = 4), |
| 105 | the alpha channel is preserved. <I>This method does not alter |
| 106 | the original image data.</I> |
| 107 | */ |
| 108 | void Fl_Image::desaturate() { |
| 109 | } |
| 110 | |
| 111 | /** |
| 112 | The label() methods are an obsolete way to set the |
| 113 | image attribute of a widget or menu item. Use the |
| 114 | image() or deimage() methods of the |
| 115 | Fl_Widget and Fl_Menu_Item classes |
| 116 | instead. |
| 117 | */ |
| 118 | void Fl_Image::label(Fl_Widget* widget) { |
| 119 | widget->image(this); |
| 120 | } |
| 121 | |
| 122 | /** |
| 123 | The label() methods are an obsolete way to set the |
| 124 | image attribute of a widget or menu item. Use the |
| 125 | image() or deimage() methods of the |
| 126 | Fl_Widget and Fl_Menu_Item classes |
| 127 | instead. |
| 128 | */ |
| 129 | void Fl_Image::label(Fl_Menu_Item* m) { |
| 130 | Fl::set_labeltype(_FL_IMAGE_LABEL, labeltype, measure); |
| 131 | m->label(_FL_IMAGE_LABEL, (const char*)this); |
| 132 | } |
| 133 | |
| 134 | void |
| 135 | Fl_Image::labeltype(const Fl_Label *lo, // I - Label |
| 136 | int lx, // I - X position |
| 137 | int ly, // I - Y position |
| 138 | int lw, // I - Width of label |
| 139 | int lh, // I - Height of label |
| 140 | Fl_Align la) { // I - Alignment |
| 141 | Fl_Image *img; // Image pointer |
| 142 | int cx, cy; // Image position |
| 143 | |
| 144 | img = (Fl_Image *)(lo->value); |
| 145 | |
| 146 | if (la & FL_ALIGN_LEFT) cx = 0; |
| 147 | else if (la & FL_ALIGN_RIGHT) cx = img->w() - lw; |
| 148 | else cx = (img->w() - lw) / 2; |
| 149 | |
| 150 | if (la & FL_ALIGN_TOP) cy = 0; |
| 151 | else if (la & FL_ALIGN_BOTTOM) cy = img->h() - lh; |
| 152 | else cy = (img->h() - lh) / 2; |
| 153 | |
| 154 | fl_color((Fl_Color)lo->color); |
| 155 | |
| 156 | img->draw(lx, ly, lw, lh, cx, cy); |
| 157 | } |
| 158 | |
| 159 | void |
| 160 | Fl_Image::measure(const Fl_Label *lo, // I - Label |
| 161 | int &lw, // O - Width of image |
| 162 | int &lh) { // O - Height of image |
| 163 | Fl_Image *img; // Image pointer |
| 164 | |
| 165 | img = (Fl_Image *)(lo->value); |
| 166 | |
| 167 | lw = img->w(); |
| 168 | lh = img->h(); |
| 169 | } |
| 170 | |
| 171 | |
| 172 | // |
| 173 | // RGB image class... |
| 174 | // |
DRC | 685f17e | 2011-07-28 09:23:00 +0000 | [diff] [blame] | 175 | |
| 176 | int fl_convert_pixmap(const char*const* cdata, uchar* out, Fl_Color bg); |
| 177 | |
| 178 | /** The constructor creates a new RGBA image from the specified Fl_Pixmap. */ |
| 179 | Fl_RGB_Image::Fl_RGB_Image(const Fl_Pixmap *pxm, Fl_Color bg): |
| 180 | Fl_Image(pxm->w(), pxm->h(), 4), id_(0), mask_(0) |
| 181 | { |
| 182 | array = new uchar[w() * h() * d()]; |
| 183 | alloc_array = 1; |
| 184 | fl_convert_pixmap(pxm->data(), (uchar*)array, bg); |
| 185 | data((const char **)&array, 1); |
| 186 | } |
| 187 | |
DRC | 2ff39b8 | 2011-07-28 08:38:59 +0000 | [diff] [blame] | 188 | /** The destructor free all memory and server resources that are used by the image. */ |
| 189 | Fl_RGB_Image::~Fl_RGB_Image() { |
| 190 | uncache(); |
| 191 | if (alloc_array) delete[] (uchar *)array; |
| 192 | } |
| 193 | |
| 194 | void Fl_RGB_Image::uncache() { |
| 195 | #ifdef __APPLE_QUARTZ__ |
| 196 | if (id_) { |
| 197 | CGImageRelease((CGImageRef)id_); |
| 198 | id_ = 0; |
| 199 | } |
| 200 | #else |
| 201 | if (id_) { |
| 202 | fl_delete_offscreen((Fl_Offscreen)id_); |
| 203 | id_ = 0; |
| 204 | } |
| 205 | |
| 206 | if (mask_) { |
| 207 | fl_delete_bitmask((Fl_Bitmask)mask_); |
| 208 | mask_ = 0; |
| 209 | } |
| 210 | #endif |
| 211 | } |
| 212 | |
| 213 | Fl_Image *Fl_RGB_Image::copy(int W, int H) { |
| 214 | Fl_RGB_Image *new_image; // New RGB image |
| 215 | uchar *new_array; // New array for image data |
| 216 | |
| 217 | // Optimize the simple copy where the width and height are the same, |
| 218 | // or when we are copying an empty image... |
| 219 | if ((W == w() && H == h()) || |
| 220 | !w() || !h() || !d() || !array) { |
| 221 | if (array) { |
| 222 | // Make a copy of the image data and return a new Fl_RGB_Image... |
| 223 | new_array = new uchar[w() * h() * d()]; |
| 224 | if (ld() && ld()!=w()*d()) { |
| 225 | const uchar *src = array; |
| 226 | uchar *dst = new_array; |
| 227 | int dy, dh = h(), wd = w()*d(), wld = ld(); |
| 228 | for (dy=0; dy<dh; dy++) { |
| 229 | memcpy(dst, src, wd); |
| 230 | src += wld; |
| 231 | dst += wd; |
| 232 | } |
| 233 | } else { |
| 234 | memcpy(new_array, array, w() * h() * d()); |
| 235 | } |
| 236 | new_image = new Fl_RGB_Image(new_array, w(), h(), d()); |
| 237 | new_image->alloc_array = 1; |
| 238 | |
| 239 | return new_image; |
| 240 | } else return new Fl_RGB_Image(array, w(), h(), d(), ld()); |
| 241 | } |
| 242 | if (W <= 0 || H <= 0) return 0; |
| 243 | |
| 244 | // OK, need to resize the image data; allocate memory and |
| 245 | uchar *new_ptr; // Pointer into new array |
| 246 | const uchar *old_ptr; // Pointer into old array |
| 247 | int c, // Channel number |
| 248 | sy, // Source coordinate |
| 249 | dx, dy, // Destination coordinates |
| 250 | xerr, yerr, // X & Y errors |
| 251 | xmod, ymod, // X & Y moduli |
| 252 | xstep, ystep, // X & Y step increments |
| 253 | line_d; // stride from line to line |
| 254 | |
| 255 | |
| 256 | // Figure out Bresenheim step/modulus values... |
| 257 | xmod = w() % W; |
| 258 | xstep = (w() / W) * d(); |
| 259 | ymod = h() % H; |
| 260 | ystep = h() / H; |
| 261 | line_d = ld() ? ld() : w() * d(); |
| 262 | |
| 263 | // Allocate memory for the new image... |
| 264 | new_array = new uchar [W * H * d()]; |
| 265 | new_image = new Fl_RGB_Image(new_array, W, H, d()); |
| 266 | new_image->alloc_array = 1; |
| 267 | |
| 268 | // Scale the image using a nearest-neighbor algorithm... |
| 269 | for (dy = H, sy = 0, yerr = H, new_ptr = new_array; dy > 0; dy --) { |
| 270 | for (dx = W, xerr = W, old_ptr = array + sy * line_d; dx > 0; dx --) { |
| 271 | for (c = 0; c < d(); c ++) *new_ptr++ = old_ptr[c]; |
| 272 | |
| 273 | old_ptr += xstep; |
| 274 | xerr -= xmod; |
| 275 | |
| 276 | if (xerr <= 0) { |
| 277 | xerr += W; |
| 278 | old_ptr += d(); |
| 279 | } |
| 280 | } |
| 281 | |
| 282 | sy += ystep; |
| 283 | yerr -= ymod; |
| 284 | if (yerr <= 0) { |
| 285 | yerr += H; |
| 286 | sy ++; |
| 287 | } |
| 288 | } |
| 289 | |
| 290 | return new_image; |
| 291 | } |
| 292 | |
| 293 | void Fl_RGB_Image::color_average(Fl_Color c, float i) { |
| 294 | // Don't average an empty image... |
| 295 | if (!w() || !h() || !d() || !array) return; |
| 296 | |
| 297 | // Delete any existing pixmap/mask objects... |
| 298 | uncache(); |
| 299 | |
| 300 | // Allocate memory as needed... |
| 301 | uchar *new_array, |
| 302 | *new_ptr; |
| 303 | |
| 304 | if (!alloc_array) new_array = new uchar[h() * w() * d()]; |
| 305 | else new_array = (uchar *)array; |
| 306 | |
| 307 | // Get the color to blend with... |
| 308 | uchar r, g, b; |
| 309 | unsigned ia, ir, ig, ib; |
| 310 | |
| 311 | Fl::get_color(c, r, g, b); |
| 312 | if (i < 0.0f) i = 0.0f; |
| 313 | else if (i > 1.0f) i = 1.0f; |
| 314 | |
| 315 | ia = (unsigned)(256 * i); |
| 316 | ir = r * (256 - ia); |
| 317 | ig = g * (256 - ia); |
| 318 | ib = b * (256 - ia); |
| 319 | |
| 320 | // Update the image data to do the blend... |
| 321 | const uchar *old_ptr; |
| 322 | int x, y; |
| 323 | int line_i = ld() ? ld() - (w()*d()) : 0; // increment from line end to beginning of next line |
| 324 | |
| 325 | if (d() < 3) { |
| 326 | ig = (r * 31 + g * 61 + b * 8) / 100 * (256 - ia); |
| 327 | |
| 328 | for (new_ptr = new_array, old_ptr = array, y = 0; y < h(); y ++, old_ptr += line_i) |
| 329 | for (x = 0; x < w(); x ++) { |
| 330 | *new_ptr++ = (*old_ptr++ * ia + ig) >> 8; |
| 331 | if (d() > 1) *new_ptr++ = *old_ptr++; |
| 332 | } |
| 333 | } else { |
| 334 | for (new_ptr = new_array, old_ptr = array, y = 0; y < h(); y ++, old_ptr += line_i) |
| 335 | for (x = 0; x < w(); x ++) { |
| 336 | *new_ptr++ = (*old_ptr++ * ia + ir) >> 8; |
| 337 | *new_ptr++ = (*old_ptr++ * ia + ig) >> 8; |
| 338 | *new_ptr++ = (*old_ptr++ * ia + ib) >> 8; |
| 339 | if (d() > 3) *new_ptr++ = *old_ptr++; |
| 340 | } |
| 341 | } |
| 342 | |
| 343 | // Set the new pointers/values as needed... |
| 344 | if (!alloc_array) { |
| 345 | array = new_array; |
| 346 | alloc_array = 1; |
| 347 | |
| 348 | ld(0); |
| 349 | } |
| 350 | } |
| 351 | |
| 352 | void Fl_RGB_Image::desaturate() { |
| 353 | // Don't desaturate an empty image... |
| 354 | if (!w() || !h() || !d() || !array) return; |
| 355 | |
| 356 | // Can only desaturate color images... |
| 357 | if (d() < 3) return; |
| 358 | |
| 359 | // Delete any existing pixmap/mask objects... |
| 360 | uncache(); |
| 361 | |
| 362 | // Allocate memory for a grayscale image... |
| 363 | uchar *new_array, |
| 364 | *new_ptr; |
| 365 | int new_d; |
| 366 | |
| 367 | new_d = d() - 2; |
| 368 | new_array = new uchar[h() * w() * new_d]; |
| 369 | |
| 370 | // Copy the image data, converting to grayscale... |
| 371 | const uchar *old_ptr; |
| 372 | int x, y; |
| 373 | int line_i = ld() ? ld() - (w()*d()) : 0; // increment from line end to beginning of next line |
| 374 | |
| 375 | for (new_ptr = new_array, old_ptr = array, y = 0; y < h(); y ++, old_ptr += line_i) |
| 376 | for (x = 0; x < w(); x ++, old_ptr += d()) { |
| 377 | *new_ptr++ = (uchar)((31 * old_ptr[0] + 61 * old_ptr[1] + 8 * old_ptr[2]) / 100); |
| 378 | if (d() > 3) *new_ptr++ = old_ptr[3]; |
| 379 | } |
| 380 | |
| 381 | // Free the old array as needed, and then set the new pointers/values... |
| 382 | if (alloc_array) delete[] (uchar *)array; |
| 383 | |
| 384 | array = new_array; |
| 385 | alloc_array = 1; |
| 386 | |
| 387 | ld(0); |
| 388 | d(new_d); |
| 389 | } |
| 390 | |
| 391 | #if !defined(WIN32) && !defined(__APPLE_QUARTZ__) |
| 392 | // Composite an image with alpha on systems that don't have accelerated |
| 393 | // alpha compositing... |
| 394 | static void alpha_blend(Fl_RGB_Image *img, int X, int Y, int W, int H, int cx, int cy) { |
| 395 | int ld = img->ld(); |
| 396 | if (ld == 0) ld = img->w() * img->d(); |
| 397 | uchar *srcptr = (uchar*)img->array + cy * ld + cx * img->d(); |
| 398 | int srcskip = ld - img->d() * W; |
| 399 | |
| 400 | uchar *dst = new uchar[W * H * 3]; |
| 401 | uchar *dstptr = dst; |
| 402 | |
| 403 | fl_read_image(dst, X, Y, W, H, 0); |
| 404 | |
| 405 | uchar srcr, srcg, srcb, srca; |
| 406 | uchar dstr, dstg, dstb, dsta; |
| 407 | |
| 408 | if (img->d() == 2) { |
| 409 | // Composite grayscale + alpha over RGB... |
| 410 | for (int y = H; y > 0; y--, srcptr+=srcskip) |
| 411 | for (int x = W; x > 0; x--) { |
| 412 | srcg = *srcptr++; |
| 413 | srca = *srcptr++; |
| 414 | |
| 415 | dstr = dstptr[0]; |
| 416 | dstg = dstptr[1]; |
| 417 | dstb = dstptr[2]; |
| 418 | dsta = 255 - srca; |
| 419 | |
| 420 | *dstptr++ = (srcg * srca + dstr * dsta) >> 8; |
| 421 | *dstptr++ = (srcg * srca + dstg * dsta) >> 8; |
| 422 | *dstptr++ = (srcg * srca + dstb * dsta) >> 8; |
| 423 | } |
| 424 | } else { |
| 425 | // Composite RGBA over RGB... |
| 426 | for (int y = H; y > 0; y--, srcptr+=srcskip) |
| 427 | for (int x = W; x > 0; x--) { |
| 428 | srcr = *srcptr++; |
| 429 | srcg = *srcptr++; |
| 430 | srcb = *srcptr++; |
| 431 | srca = *srcptr++; |
| 432 | |
| 433 | dstr = dstptr[0]; |
| 434 | dstg = dstptr[1]; |
| 435 | dstb = dstptr[2]; |
| 436 | dsta = 255 - srca; |
| 437 | |
| 438 | *dstptr++ = (srcr * srca + dstr * dsta) >> 8; |
| 439 | *dstptr++ = (srcg * srca + dstg * dsta) >> 8; |
| 440 | *dstptr++ = (srcb * srca + dstb * dsta) >> 8; |
| 441 | } |
| 442 | } |
| 443 | |
| 444 | fl_draw_image(dst, X, Y, W, H, 3, 0); |
| 445 | |
| 446 | delete[] dst; |
| 447 | } |
| 448 | #endif // !WIN32 && !__APPLE_QUARTZ__ |
| 449 | |
| 450 | void Fl_RGB_Image::draw(int XP, int YP, int WP, int HP, int cx, int cy) { |
| 451 | fl_graphics_driver->draw(this, XP, YP, WP, HP, cx, cy); |
| 452 | } |
| 453 | |
| 454 | static int start(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int w, int h, int &cx, int &cy, |
| 455 | int &X, int &Y, int &W, int &H) |
| 456 | { |
| 457 | // account for current clip region (faster on Irix): |
| 458 | fl_clip_box(XP,YP,WP,HP,X,Y,W,H); |
| 459 | cx += X-XP; cy += Y-YP; |
| 460 | // clip the box down to the size of image, quit if empty: |
| 461 | if (cx < 0) {W += cx; X -= cx; cx = 0;} |
| 462 | if (cx+W > w) W = w-cx; |
| 463 | if (W <= 0) return 1; |
| 464 | if (cy < 0) {H += cy; Y -= cy; cy = 0;} |
| 465 | if (cy+H > h) H = h-cy; |
| 466 | if (H <= 0) return 1; |
| 467 | return 0; |
| 468 | } |
| 469 | |
| 470 | #ifdef __APPLE__ |
| 471 | void Fl_Quartz_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) { |
| 472 | int X, Y, W, H; |
| 473 | // Don't draw an empty image... |
| 474 | if (!img->d() || !img->array) { |
| 475 | img->draw_empty(XP, YP); |
| 476 | return; |
| 477 | } |
| 478 | if (start(img, XP, YP, WP, HP, img->w(), img->h(), cx, cy, X, Y, W, H)) { |
| 479 | return; |
| 480 | } |
| 481 | if (!img->id_) { |
| 482 | CGColorSpaceRef lut = 0; |
| 483 | if (img->d()<=2) |
| 484 | lut = CGColorSpaceCreateDeviceGray(); |
| 485 | else |
| 486 | lut = CGColorSpaceCreateDeviceRGB(); |
| 487 | CGDataProviderRef src = CGDataProviderCreateWithData( 0L, img->array, img->w()*img->h()*img->d(), 0L); |
| 488 | img->id_ = CGImageCreate( img->w(), img->h(), 8, img->d()*8, img->ld()?img->ld():img->w()*img->d(), |
| 489 | lut, (img->d()&1)?kCGImageAlphaNone:kCGImageAlphaLast, |
| 490 | src, 0L, false, kCGRenderingIntentDefault); |
| 491 | CGColorSpaceRelease(lut); |
| 492 | CGDataProviderRelease(src); |
| 493 | } |
| 494 | if (img->id_ && fl_gc) { |
| 495 | CGRect rect = { { X, Y }, { W, H } }; |
| 496 | Fl_X::q_begin_image(rect, cx, cy, img->w(), img->h()); |
| 497 | CGContextDrawImage(fl_gc, rect, (CGImageRef)img->id_); |
| 498 | Fl_X::q_end_image(); |
| 499 | } |
| 500 | } |
| 501 | |
| 502 | #elif defined(WIN32) |
| 503 | void Fl_GDI_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) { |
| 504 | int X, Y, W, H; |
| 505 | // Don't draw an empty image... |
| 506 | if (!img->d() || !img->array) { |
| 507 | img->draw_empty(XP, YP); |
| 508 | return; |
| 509 | } |
| 510 | if (start(img, XP, YP, WP, HP, img->w(), img->h(), cx, cy, X, Y, W, H)) { |
| 511 | return; |
| 512 | } |
| 513 | if (!img->id_) { |
| 514 | img->id_ = fl_create_offscreen(img->w(), img->h()); |
| 515 | if ((img->d() == 2 || img->d() == 4) && fl_can_do_alpha_blending()) { |
| 516 | fl_begin_offscreen((Fl_Offscreen)img->id_); |
| 517 | fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d()|FL_IMAGE_WITH_ALPHA, img->ld()); |
| 518 | fl_end_offscreen(); |
| 519 | } else { |
| 520 | fl_begin_offscreen((Fl_Offscreen)img->id_); |
| 521 | fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d(), img->ld()); |
| 522 | fl_end_offscreen(); |
| 523 | if (img->d() == 2 || img->d() == 4) { |
| 524 | img->mask_ = fl_create_alphamask(img->w(), img->h(), img->d(), img->ld(), img->array); |
| 525 | } |
| 526 | } |
| 527 | } |
| 528 | if (img->mask_) { |
| 529 | HDC new_gc = CreateCompatibleDC(fl_gc); |
| 530 | int save = SaveDC(new_gc); |
| 531 | SelectObject(new_gc, (void*)img->mask_); |
| 532 | BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCAND); |
| 533 | SelectObject(new_gc, (void*)img->id_); |
| 534 | BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCPAINT); |
| 535 | RestoreDC(new_gc,save); |
| 536 | DeleteDC(new_gc); |
| 537 | } else if (img->d()==2 || img->d()==4) { |
| 538 | fl_copy_offscreen_with_alpha(X, Y, W, H, (Fl_Offscreen)img->id_, cx, cy); |
| 539 | } else { |
| 540 | fl_copy_offscreen(X, Y, W, H, (Fl_Offscreen)img->id_, cx, cy); |
| 541 | } |
| 542 | } |
| 543 | |
| 544 | #else |
| 545 | void Fl_Xlib_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) { |
| 546 | int X, Y, W, H; |
| 547 | // Don't draw an empty image... |
| 548 | if (!img->d() || !img->array) { |
| 549 | img->draw_empty(XP, YP); |
| 550 | return; |
| 551 | } |
| 552 | if (start(img, XP, YP, WP, HP, img->w(), img->h(), cx, cy, X, Y, W, H)) { |
| 553 | return; |
| 554 | } |
| 555 | if (!img->id_) { |
| 556 | if (img->d() == 1 || img->d() == 3) { |
| 557 | img->id_ = fl_create_offscreen(img->w(), img->h()); |
| 558 | fl_begin_offscreen((Fl_Offscreen)img->id_); |
| 559 | fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d(), img->ld()); |
| 560 | fl_end_offscreen(); |
| 561 | } |
| 562 | } |
| 563 | if (img->id_) { |
| 564 | if (img->mask_) { |
| 565 | // I can't figure out how to combine a mask with existing region, |
| 566 | // so cut the image down to a clipped rectangle: |
| 567 | int nx, ny; fl_clip_box(X,Y,W,H,nx,ny,W,H); |
| 568 | cx += nx-X; X = nx; |
| 569 | cy += ny-Y; Y = ny; |
| 570 | // make X use the bitmap as a mask: |
| 571 | XSetClipMask(fl_display, fl_gc, img->mask_); |
| 572 | int ox = X-cx; if (ox < 0) ox += img->w(); |
| 573 | int oy = Y-cy; if (oy < 0) oy += img->h(); |
| 574 | XSetClipOrigin(fl_display, fl_gc, X-cx, Y-cy); |
| 575 | } |
| 576 | |
| 577 | fl_copy_offscreen(X, Y, W, H, img->id_, cx, cy); |
| 578 | |
| 579 | if (img->mask_) { |
| 580 | // put the old clip region back |
| 581 | XSetClipOrigin(fl_display, fl_gc, 0, 0); |
| 582 | fl_restore_clip(); |
| 583 | } |
| 584 | } else { |
| 585 | // Composite image with alpha manually each time... |
| 586 | alpha_blend(img, X, Y, W, H, cx, cy); |
| 587 | } |
| 588 | } |
| 589 | |
| 590 | #endif |
| 591 | |
| 592 | void Fl_RGB_Image::label(Fl_Widget* widget) { |
| 593 | widget->image(this); |
| 594 | } |
| 595 | |
| 596 | void Fl_RGB_Image::label(Fl_Menu_Item* m) { |
| 597 | Fl::set_labeltype(_FL_IMAGE_LABEL, labeltype, measure); |
| 598 | m->label(_FL_IMAGE_LABEL, (const char*)this); |
| 599 | } |
| 600 | |
| 601 | |
| 602 | // |
| 603 | // End of "$Id: Fl_Image.cxx 8611 2011-04-20 14:01:04Z AlbrechtS $". |
| 604 | // |