|
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_draw_image_win32.cxx 8190 2011-01-05 10:21:45Z manolo $" 00003 // 00004 // WIN32 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 // I hope a simple and portable method of drawing color and monochrome 00029 // images. To keep this simple, only a single storage type is 00030 // supported: 8 bit unsigned data, byte order RGB, and pixels are 00031 // stored packed into rows with the origin at the top-left. It is 00032 // possible to alter the size of pixels with the "delta" argument, to 00033 // add alpha or other information per pixel. It is also possible to 00034 // change the origin and direction of the image data by messing with 00035 // the "delta" and "linedelta", making them negative, though this may 00036 // defeat some of the shortcuts in translating the image for X. 00037 00038 // Unbelievably (since it conflicts with how most PC software works) 00039 // Micro$oft picked a bottom-up and BGR storage format for their 00040 // DIB images. I'm pretty certain there is a way around this, but 00041 // I can't find any other than the brute-force method of drawing 00042 // each line as a separate image. This may also need to be done 00043 // if the delta is any amount other than 1, 3, or 4. 00044 00046 00047 #include <config.h> 00048 #include <FL/Fl.H> 00049 #include <FL/Fl_Printer.H> 00050 #include <FL/fl_draw.H> 00051 #include <FL/x.H> 00052 00053 #define MAXBUFFER 0x40000 // 256k 00054 00055 #if USE_COLORMAP 00056 00057 // error-diffusion dither into the FLTK colormap 00058 static void dither(uchar* to, const uchar* from, int w, int delta) { 00059 static int ri, gi, bi, dir; 00060 int r=ri, g=gi, b=bi; 00061 int d, td; 00062 if (dir) { 00063 dir = 0; 00064 from = from+(w-1)*delta; 00065 to = to+(w-1); 00066 d = -delta; 00067 td = -1; 00068 } else { 00069 dir = 1; 00070 d = delta; 00071 td = 1; 00072 } 00073 for (; w--; from += d, to += td) { 00074 r += from[0]; if (r < 0) r = 0; else if (r>255) r = 255; 00075 int rr = r*FL_NUM_RED/256; 00076 r -= rr*255/(FL_NUM_RED-1); 00077 g += from[1]; if (g < 0) g = 0; else if (g>255) g = 255; 00078 int gg = g*FL_NUM_GREEN/256; 00079 g -= gg*255/(FL_NUM_GREEN-1); 00080 b += from[2]; if (b < 0) b = 0; else if (b>255) b = 255; 00081 int bb = b*FL_NUM_BLUE/256; 00082 b -= bb*255/(FL_NUM_BLUE-1); 00083 *to = uchar(FL_COLOR_CUBE+(bb*FL_NUM_RED+rr)*FL_NUM_GREEN+gg); 00084 } 00085 ri = r; gi = g; bi = b; 00086 } 00087 00088 // error-diffusion dither into the FLTK colormap 00089 static void monodither(uchar* to, const uchar* from, int w, int delta) { 00090 static int ri,dir; 00091 int r=ri; 00092 int d, td; 00093 if (dir) { 00094 dir = 0; 00095 from = from+(w-1)*delta; 00096 to = to+(w-1); 00097 d = -delta; 00098 td = -1; 00099 } else { 00100 dir = 1; 00101 d = delta; 00102 td = 1; 00103 } 00104 for (; w--; from += d, to += td) { 00105 r += *from; if (r < 0) r = 0; else if (r>255) r = 255; 00106 int rr = r*FL_NUM_GRAY/256; 00107 r -= rr*255/(FL_NUM_GRAY-1); 00108 *to = uchar(FL_GRAY_RAMP+rr); 00109 } 00110 ri = r; 00111 } 00112 00113 #endif // USE_COLORMAP 00114 00115 static void innards(const uchar *buf, int X, int Y, int W, int H, 00116 int delta, int linedelta, int depth, 00117 Fl_Draw_Image_Cb cb, void* userdata) 00118 { 00119 char indexed = 0; 00120 00121 #if USE_COLORMAP 00122 indexed = (fl_palette != 0); 00123 #endif 00124 00125 if (depth==0) depth = 3; 00126 if (indexed || !fl_can_do_alpha_blending()) 00127 depth = (depth-1)|1; 00128 00129 if (!linedelta) linedelta = W*delta; 00130 00131 int x, y, w, h; 00132 fl_clip_box(X,Y,W,H,x,y,w,h); 00133 if (w<=0 || h<=0) return; 00134 if (buf) buf += (x-X)*delta + (y-Y)*linedelta; 00135 00136 static U32 bmibuffer[256+12]; 00137 BITMAPINFO &bmi = *((BITMAPINFO*)bmibuffer); 00138 if (!bmi.bmiHeader.biSize) { 00139 bmi.bmiHeader.biSize = sizeof(bmi)-4; // does it use this to determine type? 00140 bmi.bmiHeader.biPlanes = 1; 00141 bmi.bmiHeader.biCompression = BI_RGB; 00142 bmi.bmiHeader.biXPelsPerMeter = 0; 00143 bmi.bmiHeader.biYPelsPerMeter = 0; 00144 bmi.bmiHeader.biClrUsed = 0; 00145 bmi.bmiHeader.biClrImportant = 0; 00146 } 00147 #if USE_COLORMAP 00148 if (indexed) { 00149 for (short i=0; i<256; i++) { 00150 *((short*)(bmi.bmiColors)+i) = i; 00151 } 00152 } else 00153 #endif 00154 if (depth<3) { 00155 for (int i=0; i<256; i++) { 00156 bmi.bmiColors[i].rgbBlue = (uchar)i; 00157 bmi.bmiColors[i].rgbGreen = (uchar)i; 00158 bmi.bmiColors[i].rgbRed = (uchar)i; 00159 bmi.bmiColors[i].rgbReserved = (uchar)0; // must be zero 00160 } 00161 } 00162 bmi.bmiHeader.biWidth = w; 00163 #if USE_COLORMAP 00164 bmi.bmiHeader.biBitCount = indexed ? 8 : depth*8; 00165 int pixelsize = indexed ? 1 : depth; 00166 #else 00167 bmi.bmiHeader.biBitCount = depth*8; 00168 int pixelsize = depth; 00169 #endif 00170 if (depth==2) { // special case: gray with alpha 00171 bmi.bmiHeader.biBitCount = 32; 00172 pixelsize = 4; 00173 } 00174 int linesize = (pixelsize*w+3)&~3; 00175 00176 static U32* buffer; 00177 int blocking = h; 00178 {int size = linesize*h; 00179 if (size > MAXBUFFER) { 00180 size = MAXBUFFER; 00181 blocking = MAXBUFFER/linesize; 00182 } 00183 static long buffer_size; 00184 if (size > buffer_size) { 00185 delete[] buffer; 00186 buffer_size = size; 00187 buffer = new U32[(size+3)/4]; 00188 }} 00189 bmi.bmiHeader.biHeight = blocking; 00190 static U32* line_buffer; 00191 if (!buf) { 00192 int size = W*delta; 00193 static int line_buf_size; 00194 if (size > line_buf_size) { 00195 delete[] line_buffer; 00196 line_buf_size = size; 00197 line_buffer = new U32[(size+3)/4]; 00198 } 00199 } 00200 for (int j=0; j<h; ) { 00201 int k; 00202 for (k = 0; j<h && k<blocking; k++, j++) { 00203 const uchar* from; 00204 if (!buf) { // run the converter: 00205 cb(userdata, x-X, y-Y+j, w, (uchar*)line_buffer); 00206 from = (uchar*)line_buffer; 00207 } else { 00208 from = buf; 00209 buf += linedelta; 00210 } 00211 uchar *to = (uchar*)buffer+(blocking-k-1)*linesize; 00212 #if USE_COLORMAP 00213 if (indexed) { 00214 if (depth<3) 00215 monodither(to, from, w, delta); 00216 else 00217 dither(to, from, w, delta); 00218 to += w; 00219 } else 00220 #endif 00221 { 00222 int i; 00223 switch (depth) { 00224 case 1: 00225 for (i=w; i--; from += delta) *to++ = *from; 00226 break; 00227 case 2: 00228 for (i=w; i--; from += delta, to += 4) { 00229 uchar a = from[1]; 00230 uchar gray = (from[0]*a)>>8; 00231 to[0] = gray; 00232 to[1] = gray; 00233 to[2] = gray; 00234 to[3] = a; 00235 } 00236 break; 00237 case 3: 00238 for (i=w; i--; from += delta, to += 3) { 00239 uchar r = from[0]; 00240 to[0] = from[2]; 00241 to[1] = from[1]; 00242 to[2] = r; 00243 } 00244 break; 00245 case 4: 00246 for (i=w; i--; from += delta, to += 4) { 00247 uchar a = from[3]; 00248 uchar r = from[0]; 00249 to[0] = (from[2]*a)>>8; 00250 to[1] = (from[1]*a)>>8; 00251 to[2] = (r*a)>>8; 00252 to[3] = from[3]; 00253 } 00254 break; 00255 } 00256 } 00257 } 00258 if(Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id) { 00259 // if print context, device and logical units are not equal, so SetDIBitsToDevice 00260 // does not do the expected job, whereas StretchDIBits does it. 00261 StretchDIBits(fl_gc, x, y+j-k, w, k, 0, 0, w, k, 00262 (LPSTR)((uchar*)buffer+(blocking-k)*linesize), 00263 &bmi, 00264 #if USE_COLORMAP 00265 indexed ? DIB_PAL_COLORS : DIB_RGB_COLORS 00266 #else 00267 DIB_RGB_COLORS 00268 #endif 00269 , SRCCOPY ); 00270 } 00271 else { 00272 SetDIBitsToDevice(fl_gc, x, y+j-k, w, k, 0, 0, 0, k, 00273 (LPSTR)((uchar*)buffer+(blocking-k)*linesize), 00274 &bmi, 00275 #if USE_COLORMAP 00276 indexed ? DIB_PAL_COLORS : DIB_RGB_COLORS 00277 #else 00278 DIB_RGB_COLORS 00279 #endif 00280 ); 00281 } 00282 } 00283 } 00284 00285 static int fl_abs(int v) { return v<0 ? -v : v; } 00286 00287 void Fl_GDI_Graphics_Driver::draw_image(const uchar* buf, int x, int y, int w, int h, int d, int l){ 00288 if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { 00289 d ^= FL_IMAGE_WITH_ALPHA; 00290 innards(buf,x,y,w,h,d,l,fl_abs(d),0,0); 00291 } else { 00292 innards(buf,x,y,w,h,d,l,(d<3&&d>-3),0,0); 00293 } 00294 } 00295 00296 void Fl_GDI_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data, 00297 int x, int y, int w, int h,int d) { 00298 if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { 00299 d ^= FL_IMAGE_WITH_ALPHA; 00300 innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data); 00301 } else { 00302 innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data); 00303 } 00304 } 00305 00306 void Fl_GDI_Graphics_Driver::draw_image_mono(const uchar* buf, int x, int y, int w, int h, int d, int l){ 00307 if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { 00308 d ^= FL_IMAGE_WITH_ALPHA; 00309 innards(buf,x,y,w,h,d,l,1,0,0); 00310 } else { 00311 innards(buf,x,y,w,h,d,l,1,0,0); 00312 } 00313 } 00314 00315 void Fl_GDI_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb cb, void* data, 00316 int x, int y, int w, int h,int d) { 00317 if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { 00318 d ^= FL_IMAGE_WITH_ALPHA; 00319 innards(0,x,y,w,h,d,0,1,cb,data); 00320 } else { 00321 innards(0,x,y,w,h,d,0,1,cb,data); 00322 } 00323 } 00324 00325 void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) { 00326 #if USE_COLORMAP 00327 // use the error diffusion dithering code to produce a much nicer block: 00328 if (fl_palette) { 00329 uchar c[3]; 00330 c[0] = r; c[1] = g; c[2] = b; 00331 innards(c,x,y,w,h,0,0,0,0,0); 00332 return; 00333 } 00334 #endif 00335 fl_color(r,g,b); 00336 fl_rectf(x,y,w,h); 00337 } 00338 00339 // 00340 // End of "$Id: fl_draw_image_win32.cxx 8190 2011-01-05 10:21:45Z manolo $". 00341 //