From ff4cafeb303cd8e9d24b62c45661f6da5067d556 Mon Sep 17 00:00:00 2001 From: Albrecht Schlosser Date: Thu, 16 Dec 2010 20:23:57 +0000 Subject: [PATCH] This new fl_read_image() function for Windows is *much* faster than reading individual pixels as before (STR #2387), but there is still room for improvement... git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@8048 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- CHANGES | 1 + src/fl_read_image_win32.cxx | 89 +++++++++++++++++++++++++++++++------ 2 files changed, 76 insertions(+), 14 deletions(-) diff --git a/CHANGES b/CHANGES index 24d7b8025..4dfdc7975 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,6 @@ CHANGES IN FLTK 1.3.0 + - Much faster fl_read_image() for Windows (STR #2387). - Added general Options dialog (STR #2471) - Fixed Compiling with mingw-w64 (STR #2308). - Fixed crashes when detecting illegal utf 8 sequences diff --git a/src/fl_read_image_win32.cxx b/src/fl_read_image_win32.cxx index 1531e2580..eb881d4a8 100644 --- a/src/fl_read_image_win32.cxx +++ b/src/fl_read_image_win32.cxx @@ -36,10 +36,8 @@ fl_read_image(uchar *p, // I - Pixel buffer or NULL to allocate int w, // I - Width of area to read int h, // I - Height of area to read int alpha) { // I - Alpha value for image (0 for none) - int x, y; // Looping vars - int d; // Depth of image - uchar *ptr; // Pointer in image data + int d; // Depth of image // Allocate the image data array as needed... d = alpha ? 4 : 3; @@ -49,24 +47,87 @@ fl_read_image(uchar *p, // I - Pixel buffer or NULL to allocate // Initialize the default colors/alpha in the whole image... memset(p, alpha, w * h * d); - // Grab all of the pixels in the image, one at a time... - // MRS: there has to be a better way than this! - for (y = 0, ptr = p; y < h; y ++) { - for (x = 0; x < w; x ++, ptr += d) { - COLORREF c = GetPixel(fl_gc, X + x, Y + y); + // Grab all of the pixels in the image... - ptr[0] = (uchar)c; - c >>= 8; - ptr[1] = (uchar)c; - c >>= 8; - ptr[2] = (uchar)c; + // Assure that we are not trying to read non-existing data. If it is so, the + // function should still work, but the out-of-bounds part of the image is + // untouched (initialized with the alpha value or 0 (black), resp.). + + int ww = w; // We need the original width for output data line size + + int shift_x = 0; // X target shift if X modified + int shift_y = 0; // Y target shift if X modified + + if (X < 0) { + shift_x = -X; + w += X; + X = 0; + } + if (Y < 0) { + shift_y = -Y; + h += Y; + Y = 0; + } + + if (h < 1 || w < 1) return p; // nothing to copy + + int line_size = ((3*w+3)/4) * 4; // each line is aligned on a DWORD (4 bytes) + uchar *dib = new uchar[line_size*h]; // create temporary buffer to read DIB + + // fill in bitmap info for GetDIBits + + BITMAPINFO bi; + bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi.bmiHeader.biWidth = w; + bi.bmiHeader.biHeight = -h; // negative => top-down DIB + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 24; // 24 bits RGB + bi.bmiHeader.biCompression = BI_RGB; + bi.bmiHeader.biSizeImage = 0; + bi.bmiHeader.biXPelsPerMeter = 0; + bi.bmiHeader.biYPelsPerMeter = 0; + bi.bmiHeader.biClrUsed = 0; + bi.bmiHeader.biClrImportant = 0; + + // copy bitmap from original DC (Window, Fl_Offscreen, ...) + + HDC hdc = CreateCompatibleDC(fl_gc); + HBITMAP hbm = CreateCompatibleBitmap(fl_gc,w,h); + + int save_dc = SaveDC(hdc); // save context for cleanup + SelectObject(hdc,hbm); // select bitmap + BitBlt(hdc,0,0,w,h,fl_gc,X,Y,SRCCOPY); // copy image section to DDB + + // copy RGB image data to the allocated DIB + + GetDIBits(hdc, hbm, 0, h, dib, (BITMAPINFO *)&bi, DIB_RGB_COLORS); + + // finally copy the image data to the user buffer + + for (int j = 0; j