|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 // 00002 // "$Id: Fl_Image.cxx 7903 2010-11-28 21:06:39Z matt $" 00003 // 00004 // Image drawing code for the Fast Light Tool Kit (FLTK). 00005 // 00006 // Copyright 1998-2010 by Bill Spitzak and others. 00007 // 00008 // This library is free software; you can redistribute it and/or 00009 // modify it under the terms of the GNU Library General Public 00010 // License as published by the Free Software Foundation; either 00011 // version 2 of the License, or (at your option) any later version. 00012 // 00013 // This library is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 // Library General Public License for more details. 00017 // 00018 // You should have received a copy of the GNU Library General Public 00019 // License along with this library; if not, write to the Free Software 00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00021 // USA. 00022 // 00023 // Please report all bugs and problems on the following page: 00024 // 00025 // http://www.fltk.org/str.php 00026 // 00027 00028 #include <FL/Fl.H> 00029 #include <FL/fl_draw.H> 00030 #include <FL/x.H> 00031 #include <FL/Fl_Widget.H> 00032 #include <FL/Fl_Menu_Item.H> 00033 #include <FL/Fl_Image.H> 00034 #include "flstring.h" 00035 00036 #ifdef WIN32 00037 void fl_release_dc(HWND, HDC); // from Fl_win32.cxx 00038 #endif 00039 00040 void fl_restore_clip(); // from fl_rect.cxx 00041 00042 // 00043 // Base image class... 00044 // 00045 00050 Fl_Image::~Fl_Image() { 00051 } 00052 00058 void Fl_Image::uncache() { 00059 } 00060 00061 void Fl_Image::draw(int XP, int YP, int, int, int, int) { 00062 draw_empty(XP, YP); 00063 } 00064 00070 void Fl_Image::draw_empty(int X, int Y) { 00071 if (w() > 0 && h() > 0) { 00072 fl_color(FL_FOREGROUND_COLOR); 00073 fl_rect(X, Y, w(), h()); 00074 fl_line(X, Y, X + w() - 1, Y + h() - 1); 00075 fl_line(X, Y + h() - 1, X + w() - 1, Y); 00076 } 00077 } 00078 00086 Fl_Image *Fl_Image::copy(int W, int H) { 00087 return new Fl_Image(W, H, d()); 00088 } 00089 00099 void Fl_Image::color_average(Fl_Color, float) { 00100 } 00101 00108 void Fl_Image::desaturate() { 00109 } 00110 00118 void Fl_Image::label(Fl_Widget* widget) { 00119 widget->image(this); 00120 } 00121 00129 void Fl_Image::label(Fl_Menu_Item* m) { 00130 Fl::set_labeltype(_FL_IMAGE_LABEL, labeltype, measure); 00131 m->label(_FL_IMAGE_LABEL, (const char*)this); 00132 } 00133 00134 void 00135 Fl_Image::labeltype(const Fl_Label *lo, // I - Label 00136 int lx, // I - X position 00137 int ly, // I - Y position 00138 int lw, // I - Width of label 00139 int lh, // I - Height of label 00140 Fl_Align la) { // I - Alignment 00141 Fl_Image *img; // Image pointer 00142 int cx, cy; // Image position 00143 00144 img = (Fl_Image *)(lo->value); 00145 00146 if (la & FL_ALIGN_LEFT) cx = 0; 00147 else if (la & FL_ALIGN_RIGHT) cx = img->w() - lw; 00148 else cx = (img->w() - lw) / 2; 00149 00150 if (la & FL_ALIGN_TOP) cy = 0; 00151 else if (la & FL_ALIGN_BOTTOM) cy = img->h() - lh; 00152 else cy = (img->h() - lh) / 2; 00153 00154 fl_color((Fl_Color)lo->color); 00155 00156 img->draw(lx, ly, lw, lh, cx, cy); 00157 } 00158 00159 void 00160 Fl_Image::measure(const Fl_Label *lo, // I - Label 00161 int &lw, // O - Width of image 00162 int &lh) { // O - Height of image 00163 Fl_Image *img; // Image pointer 00164 00165 img = (Fl_Image *)(lo->value); 00166 00167 lw = img->w(); 00168 lh = img->h(); 00169 } 00170 00171 00172 // 00173 // RGB image class... 00174 // 00176 Fl_RGB_Image::~Fl_RGB_Image() { 00177 uncache(); 00178 if (alloc_array) delete[] (uchar *)array; 00179 } 00180 00181 void Fl_RGB_Image::uncache() { 00182 #ifdef __APPLE_QUARTZ__ 00183 if (id_) { 00184 CGImageRelease((CGImageRef)id_); 00185 id_ = 0; 00186 } 00187 #else 00188 if (id_) { 00189 fl_delete_offscreen((Fl_Offscreen)id_); 00190 id_ = 0; 00191 } 00192 00193 if (mask_) { 00194 fl_delete_bitmask((Fl_Bitmask)mask_); 00195 mask_ = 0; 00196 } 00197 #endif 00198 } 00199 00200 Fl_Image *Fl_RGB_Image::copy(int W, int H) { 00201 Fl_RGB_Image *new_image; // New RGB image 00202 uchar *new_array; // New array for image data 00203 00204 // Optimize the simple copy where the width and height are the same, 00205 // or when we are copying an empty image... 00206 if ((W == w() && H == h()) || 00207 !w() || !h() || !d() || !array) { 00208 if (array) { 00209 // Make a copy of the image data and return a new Fl_RGB_Image... 00210 new_array = new uchar[w() * h() * d()]; 00211 if (ld() && ld()!=w()*d()) { 00212 const uchar *src = array; 00213 uchar *dst = new_array; 00214 int dy, dh = h(), wd = w()*d(), wld = ld(); 00215 for (dy=0; dy<dh; dy++) { 00216 memcpy(dst, src, wd); 00217 src += wld; 00218 dst += wd; 00219 } 00220 } else { 00221 memcpy(new_array, array, w() * h() * d()); 00222 } 00223 new_image = new Fl_RGB_Image(new_array, w(), h(), d()); 00224 new_image->alloc_array = 1; 00225 00226 return new_image; 00227 } else return new Fl_RGB_Image(array, w(), h(), d(), ld()); 00228 } 00229 if (W <= 0 || H <= 0) return 0; 00230 00231 // OK, need to resize the image data; allocate memory and 00232 uchar *new_ptr; // Pointer into new array 00233 const uchar *old_ptr; // Pointer into old array 00234 int c, // Channel number 00235 sy, // Source coordinate 00236 dx, dy, // Destination coordinates 00237 xerr, yerr, // X & Y errors 00238 xmod, ymod, // X & Y moduli 00239 xstep, ystep, // X & Y step increments 00240 line_d; // stride from line to line 00241 00242 00243 // Figure out Bresenheim step/modulus values... 00244 xmod = w() % W; 00245 xstep = (w() / W) * d(); 00246 ymod = h() % H; 00247 ystep = h() / H; 00248 line_d = ld() ? ld() : w() * d(); 00249 00250 // Allocate memory for the new image... 00251 new_array = new uchar [W * H * d()]; 00252 new_image = new Fl_RGB_Image(new_array, W, H, d()); 00253 new_image->alloc_array = 1; 00254 00255 // Scale the image using a nearest-neighbor algorithm... 00256 for (dy = H, sy = 0, yerr = H, new_ptr = new_array; dy > 0; dy --) { 00257 for (dx = W, xerr = W, old_ptr = array + sy * line_d; dx > 0; dx --) { 00258 for (c = 0; c < d(); c ++) *new_ptr++ = old_ptr[c]; 00259 00260 old_ptr += xstep; 00261 xerr -= xmod; 00262 00263 if (xerr <= 0) { 00264 xerr += W; 00265 old_ptr += d(); 00266 } 00267 } 00268 00269 sy += ystep; 00270 yerr -= ymod; 00271 if (yerr <= 0) { 00272 yerr += H; 00273 sy ++; 00274 } 00275 } 00276 00277 return new_image; 00278 } 00279 00280 void Fl_RGB_Image::color_average(Fl_Color c, float i) { 00281 // Don't average an empty image... 00282 if (!w() || !h() || !d() || !array) return; 00283 00284 // Delete any existing pixmap/mask objects... 00285 uncache(); 00286 00287 // Allocate memory as needed... 00288 uchar *new_array, 00289 *new_ptr; 00290 00291 if (!alloc_array) new_array = new uchar[h() * w() * d()]; 00292 else new_array = (uchar *)array; 00293 00294 // Get the color to blend with... 00295 uchar r, g, b; 00296 unsigned ia, ir, ig, ib; 00297 00298 Fl::get_color(c, r, g, b); 00299 if (i < 0.0f) i = 0.0f; 00300 else if (i > 1.0f) i = 1.0f; 00301 00302 ia = (unsigned)(256 * i); 00303 ir = r * (256 - ia); 00304 ig = g * (256 - ia); 00305 ib = b * (256 - ia); 00306 00307 // Update the image data to do the blend... 00308 const uchar *old_ptr; 00309 int x, y; 00310 int line_i = ld() ? ld() - (w()*d()) : 0; // increment from line end to beginning of next line 00311 00312 if (d() < 3) { 00313 ig = (r * 31 + g * 61 + b * 8) / 100 * (256 - ia); 00314 00315 for (new_ptr = new_array, old_ptr = array, y = 0; y < h(); y ++, old_ptr += line_i) 00316 for (x = 0; x < w(); x ++) { 00317 *new_ptr++ = (*old_ptr++ * ia + ig) >> 8; 00318 if (d() > 1) *new_ptr++ = *old_ptr++; 00319 } 00320 } else { 00321 for (new_ptr = new_array, old_ptr = array, y = 0; y < h(); y ++, old_ptr += line_i) 00322 for (x = 0; x < w(); x ++) { 00323 *new_ptr++ = (*old_ptr++ * ia + ir) >> 8; 00324 *new_ptr++ = (*old_ptr++ * ia + ig) >> 8; 00325 *new_ptr++ = (*old_ptr++ * ia + ib) >> 8; 00326 if (d() > 3) *new_ptr++ = *old_ptr++; 00327 } 00328 } 00329 00330 // Set the new pointers/values as needed... 00331 if (!alloc_array) { 00332 array = new_array; 00333 alloc_array = 1; 00334 00335 ld(0); 00336 } 00337 } 00338 00339 void Fl_RGB_Image::desaturate() { 00340 // Don't desaturate an empty image... 00341 if (!w() || !h() || !d() || !array) return; 00342 00343 // Can only desaturate color images... 00344 if (d() < 3) return; 00345 00346 // Delete any existing pixmap/mask objects... 00347 uncache(); 00348 00349 // Allocate memory for a grayscale image... 00350 uchar *new_array, 00351 *new_ptr; 00352 int new_d; 00353 00354 new_d = d() - 2; 00355 new_array = new uchar[h() * w() * new_d]; 00356 00357 // Copy the image data, converting to grayscale... 00358 const uchar *old_ptr; 00359 int x, y; 00360 int line_i = ld() ? ld() - (w()*d()) : 0; // increment from line end to beginning of next line 00361 00362 for (new_ptr = new_array, old_ptr = array, y = 0; y < h(); y ++, old_ptr += line_i) 00363 for (x = 0; x < w(); x ++, old_ptr += d()) { 00364 *new_ptr++ = (uchar)((31 * old_ptr[0] + 61 * old_ptr[1] + 8 * old_ptr[2]) / 100); 00365 if (d() > 3) *new_ptr++ = old_ptr[3]; 00366 } 00367 00368 // Free the old array as needed, and then set the new pointers/values... 00369 if (alloc_array) delete[] (uchar *)array; 00370 00371 array = new_array; 00372 alloc_array = 1; 00373 00374 ld(0); 00375 d(new_d); 00376 } 00377 00378 #if !defined(WIN32) && !defined(__APPLE_QUARTZ__) 00379 // Composite an image with alpha on systems that don't have accelerated 00380 // alpha compositing... 00381 static void alpha_blend(Fl_RGB_Image *img, int X, int Y, int W, int H, int cx, int cy) { 00382 uchar *srcptr = (uchar*)img->array + img->d() * (img->w() * cy + cx); 00383 int srcskip = img->d() * (img->w() - W); 00384 00385 uchar *dst = new uchar[W * H * 3]; 00386 uchar *dstptr = dst; 00387 00388 fl_read_image(dst, X, Y, W, H, 0); 00389 00390 uchar srcr, srcg, srcb, srca; 00391 uchar dstr, dstg, dstb, dsta; 00392 00393 if (img->d() == 2) { 00394 // Composite grayscale + alpha over RGB... 00395 // Composite RGBA over RGB... 00396 for (int y = H; y > 0; y--, srcptr+=srcskip) 00397 for (int x = W; x > 0; x--) { 00398 srcg = *srcptr++; 00399 srca = *srcptr++; 00400 00401 dstr = dstptr[0]; 00402 dstg = dstptr[1]; 00403 dstb = dstptr[2]; 00404 dsta = 255 - srca; 00405 00406 *dstptr++ = (srcg * srca + dstr * dsta) >> 8; 00407 *dstptr++ = (srcg * srca + dstg * dsta) >> 8; 00408 *dstptr++ = (srcg * srca + dstb * dsta) >> 8; 00409 } 00410 } else { 00411 // Composite RGBA over RGB... 00412 for (int y = H; y > 0; y--, srcptr+=srcskip) 00413 for (int x = W; x > 0; x--) { 00414 srcr = *srcptr++; 00415 srcg = *srcptr++; 00416 srcb = *srcptr++; 00417 srca = *srcptr++; 00418 00419 dstr = dstptr[0]; 00420 dstg = dstptr[1]; 00421 dstb = dstptr[2]; 00422 dsta = 255 - srca; 00423 00424 *dstptr++ = (srcr * srca + dstr * dsta) >> 8; 00425 *dstptr++ = (srcg * srca + dstg * dsta) >> 8; 00426 *dstptr++ = (srcb * srca + dstb * dsta) >> 8; 00427 } 00428 } 00429 00430 fl_draw_image(dst, X, Y, W, H, 3, 0); 00431 00432 delete[] dst; 00433 } 00434 #endif // !WIN32 && !__APPLE_QUARTZ__ 00435 00436 void Fl_RGB_Image::draw(int XP, int YP, int WP, int HP, int cx, int cy) { 00437 fl_graphics_driver->draw(this, XP, YP, WP, HP, cx, cy); 00438 } 00439 00440 static int start(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int w, int h, int &cx, int &cy, 00441 int &X, int &Y, int &W, int &H) 00442 { 00443 // account for current clip region (faster on Irix): 00444 fl_clip_box(XP,YP,WP,HP,X,Y,W,H); 00445 cx += X-XP; cy += Y-YP; 00446 // clip the box down to the size of image, quit if empty: 00447 if (cx < 0) {W += cx; X -= cx; cx = 0;} 00448 if (cx+W > w) W = w-cx; 00449 if (W <= 0) return 1; 00450 if (cy < 0) {H += cy; Y -= cy; cy = 0;} 00451 if (cy+H > h) H = h-cy; 00452 if (H <= 0) return 1; 00453 return 0; 00454 } 00455 00456 #ifdef __APPLE__ 00457 void Fl_Quartz_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) { 00458 int X, Y, W, H; 00459 // Don't draw an empty image... 00460 if (!img->d() || !img->array) { 00461 img->draw_empty(XP, YP); 00462 return; 00463 } 00464 if (start(img, XP, YP, WP, HP, img->w(), img->h(), cx, cy, X, Y, W, H)) { 00465 return; 00466 } 00467 if (!img->id_) { 00468 CGColorSpaceRef lut = 0; 00469 if (img->d()<=2) 00470 lut = CGColorSpaceCreateDeviceGray(); 00471 else 00472 lut = CGColorSpaceCreateDeviceRGB(); 00473 CGDataProviderRef src = CGDataProviderCreateWithData( 0L, img->array, img->w()*img->h()*img->d(), 0L); 00474 img->id_ = CGImageCreate( img->w(), img->h(), 8, img->d()*8, img->ld()?img->ld():img->w()*img->d(), 00475 lut, (img->d()&1)?kCGImageAlphaNone:kCGImageAlphaLast, 00476 src, 0L, false, kCGRenderingIntentDefault); 00477 CGColorSpaceRelease(lut); 00478 CGDataProviderRelease(src); 00479 } 00480 if (img->id_ && fl_gc) { 00481 CGRect rect = { { X, Y }, { W, H } }; 00482 Fl_X::q_begin_image(rect, cx, cy, img->w(), img->h()); 00483 CGContextDrawImage(fl_gc, rect, (CGImageRef)img->id_); 00484 Fl_X::q_end_image(); 00485 } 00486 } 00487 00488 #elif defined(WIN32) 00489 void Fl_GDI_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) { 00490 int X, Y, W, H; 00491 // Don't draw an empty image... 00492 if (!img->d() || !img->array) { 00493 img->draw_empty(XP, YP); 00494 return; 00495 } 00496 if (start(img, XP, YP, WP, HP, img->w(), img->h(), cx, cy, X, Y, W, H)) { 00497 return; 00498 } 00499 if (!img->id_) { 00500 img->id_ = fl_create_offscreen(img->w(), img->h()); 00501 if ((img->d() == 2 || img->d() == 4) && fl_can_do_alpha_blending()) { 00502 fl_begin_offscreen((Fl_Offscreen)img->id_); 00503 fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d()|FL_IMAGE_WITH_ALPHA, img->ld()); 00504 fl_end_offscreen(); 00505 } else { 00506 fl_begin_offscreen((Fl_Offscreen)img->id_); 00507 fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d(), img->ld()); 00508 fl_end_offscreen(); 00509 if (img->d() == 2 || img->d() == 4) { 00510 img->mask_ = fl_create_alphamask(img->w(), img->h(), img->d(), img->ld(), img->array); 00511 } 00512 } 00513 } 00514 if (img->mask_) { 00515 HDC new_gc = CreateCompatibleDC(fl_gc); 00516 int save = SaveDC(new_gc); 00517 SelectObject(new_gc, (void*)img->mask_); 00518 BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCAND); 00519 SelectObject(new_gc, (void*)img->id_); 00520 BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCPAINT); 00521 RestoreDC(new_gc,save); 00522 DeleteDC(new_gc); 00523 } else if (img->d()==2 || img->d()==4) { 00524 fl_copy_offscreen_with_alpha(X, Y, W, H, (Fl_Offscreen)img->id_, cx, cy); 00525 } else { 00526 fl_copy_offscreen(X, Y, W, H, (Fl_Offscreen)img->id_, cx, cy); 00527 } 00528 } 00529 00530 #else 00531 void Fl_Xlib_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) { 00532 int X, Y, W, H; 00533 // Don't draw an empty image... 00534 if (!img->d() || !img->array) { 00535 img->draw_empty(XP, YP); 00536 return; 00537 } 00538 if (start(img, XP, YP, WP, HP, img->w(), img->h(), cx, cy, X, Y, W, H)) { 00539 return; 00540 } 00541 if (!img->id_) { 00542 if (img->d() == 1 || img->d() == 3) { 00543 img->id_ = fl_create_offscreen(img->w(), img->h()); 00544 fl_begin_offscreen((Fl_Offscreen)img->id_); 00545 fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d(), img->ld()); 00546 fl_end_offscreen(); 00547 } 00548 } 00549 if (img->id_) { 00550 if (img->mask_) { 00551 // I can't figure out how to combine a mask with existing region, 00552 // so cut the image down to a clipped rectangle: 00553 int nx, ny; fl_clip_box(X,Y,W,H,nx,ny,W,H); 00554 cx += nx-X; X = nx; 00555 cy += ny-Y; Y = ny; 00556 // make X use the bitmap as a mask: 00557 XSetClipMask(fl_display, fl_gc, img->mask_); 00558 int ox = X-cx; if (ox < 0) ox += img->w(); 00559 int oy = Y-cy; if (oy < 0) oy += img->h(); 00560 XSetClipOrigin(fl_display, fl_gc, X-cx, Y-cy); 00561 } 00562 00563 fl_copy_offscreen(X, Y, W, H, img->id_, cx, cy); 00564 00565 if (img->mask_) { 00566 // put the old clip region back 00567 XSetClipOrigin(fl_display, fl_gc, 0, 0); 00568 fl_restore_clip(); 00569 } 00570 } else { 00571 // Composite image with alpha manually each time... 00572 alpha_blend(img, X, Y, W, H, cx, cy); 00573 } 00574 } 00575 00576 #endif 00577 00578 void Fl_RGB_Image::label(Fl_Widget* widget) { 00579 widget->image(this); 00580 } 00581 00582 void Fl_RGB_Image::label(Fl_Menu_Item* m) { 00583 Fl::set_labeltype(_FL_IMAGE_LABEL, labeltype, measure); 00584 m->label(_FL_IMAGE_LABEL, (const char*)this); 00585 } 00586 00587 00588 // 00589 // End of "$Id: Fl_Image.cxx 7903 2010-11-28 21:06:39Z matt $". 00590 //