src/gui/image/qpixmap_win.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qpixmap.h"
       
    43 #include "qpixmap_raster_p.h"
       
    44 
       
    45 #include "qbitmap.h"
       
    46 #include "qimage.h"
       
    47 #include "qwidget.h"
       
    48 #include "qpainter.h"
       
    49 #include "qdatastream.h"
       
    50 #include "qbuffer.h"
       
    51 #include "qapplication.h"
       
    52 #include "qevent.h"
       
    53 #include "qfile.h"
       
    54 #include "qfileinfo.h"
       
    55 #include "qdatetime.h"
       
    56 #include "qpixmapcache.h"
       
    57 #include "qimagereader.h"
       
    58 #include "qimagewriter.h"
       
    59 #include "qdebug.h"
       
    60 #include "qt_windows.h"
       
    61 
       
    62 #if defined(Q_WS_WINCE)
       
    63 #include <winbase.h>
       
    64 #include "qguifunctions_wince.h"
       
    65 extern bool qt_wince_is_high_dpi();
       
    66 extern bool qt_wince_is_pocket_pc();
       
    67 #endif
       
    68 
       
    69 #ifndef CAPTUREBLT
       
    70 #define CAPTUREBLT ((DWORD)0x40000000)
       
    71 #endif
       
    72 
       
    73 QT_BEGIN_NAMESPACE
       
    74 
       
    75 QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h )
       
    76 {
       
    77     RECT r;
       
    78     GetClientRect(winId, &r);
       
    79 
       
    80     if (w < 0) w = r.right - r.left;
       
    81     if (h < 0) h = r.bottom - r.top;
       
    82 
       
    83 #ifdef Q_WS_WINCE_WM
       
    84     if (qt_wince_is_pocket_pc()) {
       
    85         QWidget *widget = QWidget::find(winId);
       
    86         if (qobject_cast<QDesktopWidget *>(widget)) {
       
    87             RECT rect = {0,0,0,0};
       
    88             AdjustWindowRectEx(&rect, WS_BORDER | WS_CAPTION, FALSE, 0);
       
    89             int magicNumber = qt_wince_is_high_dpi() ? 4 : 2;
       
    90             y += rect.top - magicNumber;
       
    91         }
       
    92     }
       
    93 #endif
       
    94 
       
    95     // Create and setup bitmap
       
    96     HDC display_dc = GetDC(0);
       
    97     HDC bitmap_dc = CreateCompatibleDC(display_dc);
       
    98     HBITMAP bitmap = CreateCompatibleBitmap(display_dc, w, h);
       
    99     HGDIOBJ null_bitmap = SelectObject(bitmap_dc, bitmap);
       
   100 
       
   101     // copy data
       
   102     HDC window_dc = GetDC(winId);
       
   103     BitBlt(bitmap_dc, 0, 0, w, h, window_dc, x, y, SRCCOPY
       
   104 #ifndef Q_WS_WINCE
       
   105                                     | CAPTUREBLT
       
   106 #endif
       
   107             );
       
   108 
       
   109     // clean up all but bitmap
       
   110     ReleaseDC(winId, window_dc);
       
   111     SelectObject(bitmap_dc, null_bitmap);
       
   112     DeleteDC(bitmap_dc);
       
   113 
       
   114     QPixmap pixmap = QPixmap::fromWinHBITMAP(bitmap);
       
   115 
       
   116     DeleteObject(bitmap);
       
   117     ReleaseDC(0, display_dc);
       
   118 
       
   119     return pixmap;
       
   120 }
       
   121 
       
   122 HBITMAP QPixmap::toWinHBITMAP(HBitmapFormat format) const
       
   123 {
       
   124     HBITMAP bitmap = 0;
       
   125     if (data->classId() == QPixmapData::RasterClass) {
       
   126         QRasterPixmapData* d = static_cast<QRasterPixmapData*>(data.data());
       
   127         int w = d->image.width();
       
   128         int h = d->image.height();
       
   129 
       
   130         HDC display_dc = GetDC(0);
       
   131 
       
   132         // Define the header
       
   133         BITMAPINFO bmi;
       
   134         memset(&bmi, 0, sizeof(bmi));
       
   135         bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
       
   136         bmi.bmiHeader.biWidth       = w;
       
   137         bmi.bmiHeader.biHeight      = -h;
       
   138         bmi.bmiHeader.biPlanes      = 1;
       
   139         bmi.bmiHeader.biBitCount    = 32;
       
   140         bmi.bmiHeader.biCompression = BI_RGB;
       
   141         bmi.bmiHeader.biSizeImage   = w * h * 4;
       
   142 
       
   143         // Create the pixmap
       
   144         uchar *pixels = 0;
       
   145         bitmap = CreateDIBSection(display_dc, &bmi, DIB_RGB_COLORS, (void **) &pixels, 0, 0);
       
   146         ReleaseDC(0, display_dc);
       
   147         if (!bitmap) {
       
   148             qErrnoWarning("QPixmap::toWinHBITMAP(), failed to create dibsection");
       
   149             return 0;
       
   150         }
       
   151         if (!pixels) {
       
   152             qErrnoWarning("QPixmap::toWinHBITMAP(), did not allocate pixel data");
       
   153             return 0;
       
   154         }
       
   155 
       
   156         // Copy over the data
       
   157         QImage::Format imageFormat = QImage::Format_ARGB32;
       
   158         if (format == NoAlpha)
       
   159             imageFormat = QImage::Format_RGB32;
       
   160         else if (format == PremultipliedAlpha)
       
   161             imageFormat = QImage::Format_ARGB32_Premultiplied;
       
   162         const QImage image = d->image.convertToFormat(imageFormat);
       
   163         int bytes_per_line = w * 4;
       
   164         for (int y=0; y<h; ++y)
       
   165             memcpy(pixels + y * bytes_per_line, image.scanLine(y), bytes_per_line);
       
   166 
       
   167     } else {
       
   168         QPixmapData *data = new QRasterPixmapData(depth() == 1 ?
       
   169                                                   QPixmapData::BitmapType : QPixmapData::PixmapType);
       
   170         data->fromImage(toImage(), Qt::AutoColor);
       
   171         return QPixmap(data).toWinHBITMAP(format);
       
   172     }
       
   173     return bitmap;
       
   174 }
       
   175 
       
   176 QPixmap QPixmap::fromWinHBITMAP(HBITMAP bitmap, HBitmapFormat format)
       
   177 {
       
   178     // Verify size
       
   179     BITMAP bitmap_info;
       
   180     memset(&bitmap_info, 0, sizeof(BITMAP));
       
   181 
       
   182     int res = GetObject(bitmap, sizeof(BITMAP), &bitmap_info);
       
   183     if (!res) {
       
   184         qErrnoWarning("QPixmap::fromWinHBITMAP(), failed to get bitmap info");
       
   185         return QPixmap();
       
   186     }
       
   187     int w = bitmap_info.bmWidth;
       
   188     int h = bitmap_info.bmHeight;
       
   189 
       
   190     BITMAPINFO bmi;
       
   191     memset(&bmi, 0, sizeof(bmi));
       
   192     bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
       
   193     bmi.bmiHeader.biWidth       = w;
       
   194     bmi.bmiHeader.biHeight      = -h;
       
   195     bmi.bmiHeader.biPlanes      = 1;
       
   196     bmi.bmiHeader.biBitCount    = 32;
       
   197     bmi.bmiHeader.biCompression = BI_RGB;
       
   198     bmi.bmiHeader.biSizeImage   = w * h * 4;
       
   199 
       
   200     QImage result;
       
   201     // Get bitmap bits
       
   202     uchar *data = (uchar *) qMalloc(bmi.bmiHeader.biSizeImage);
       
   203 
       
   204     HDC display_dc = GetDC(0);
       
   205     if (GetDIBits(display_dc, bitmap, 0, h, data, &bmi, DIB_RGB_COLORS)) {
       
   206 
       
   207         QImage::Format imageFormat = QImage::Format_ARGB32_Premultiplied;
       
   208         uint mask = 0;
       
   209         if (format == NoAlpha) {
       
   210             imageFormat = QImage::Format_RGB32;
       
   211             mask = 0xff000000;
       
   212         }
       
   213 
       
   214         // Create image and copy data into image.
       
   215         QImage image(w, h, imageFormat);
       
   216         if (!image.isNull()) { // failed to alloc?
       
   217             int bytes_per_line = w * sizeof(QRgb);
       
   218             for (int y=0; y<h; ++y) {
       
   219                 QRgb *dest = (QRgb *) image.scanLine(y);
       
   220                 const QRgb *src = (const QRgb *) (data + y * bytes_per_line);
       
   221                 for (int x=0; x<w; ++x) {
       
   222                     const uint pixel = src[x];
       
   223                     if ((pixel & 0xff000000) == 0 && (pixel & 0x00ffffff) != 0)
       
   224                         dest[x] = pixel | 0xff000000;
       
   225                     else
       
   226                         dest[x] = pixel | mask;
       
   227                 }
       
   228             }
       
   229         }
       
   230         result = image;
       
   231     } else {
       
   232         qWarning("QPixmap::fromWinHBITMAP(), failed to get bitmap bits");
       
   233     }
       
   234     ReleaseDC(0, display_dc);
       
   235     qFree(data);
       
   236     return fromImage(result);
       
   237 }
       
   238 
       
   239 HBITMAP qt_createIconMask(const QBitmap &bitmap)
       
   240 {
       
   241     QImage bm = bitmap.toImage().convertToFormat(QImage::Format_Mono);
       
   242     int w = bm.width();
       
   243     int h = bm.height();
       
   244     int bpl = ((w+15)/16)*2;                        // bpl, 16 bit alignment
       
   245     uchar *bits = new uchar[bpl*h];
       
   246     bm.invertPixels();
       
   247     for (int y=0; y<h; y++)
       
   248         memcpy(bits+y*bpl, bm.scanLine(y), bpl);
       
   249     HBITMAP hbm = CreateBitmap(w, h, 1, 1, bits);
       
   250     delete [] bits;
       
   251     return hbm;
       
   252 }
       
   253 
       
   254 HICON QPixmap::toWinHICON() const
       
   255 {
       
   256     QBitmap maskBitmap = mask();
       
   257     if (maskBitmap.isNull()) {
       
   258         maskBitmap= QBitmap(size());
       
   259         maskBitmap.fill(Qt::color1);
       
   260     }
       
   261 
       
   262     ICONINFO ii;
       
   263     ii.fIcon    = true;
       
   264     ii.hbmMask  = qt_createIconMask(maskBitmap);
       
   265     ii.hbmColor = toWinHBITMAP(QPixmap::Alpha);
       
   266     ii.xHotspot = 0;
       
   267     ii.yHotspot = 0;
       
   268 
       
   269     HICON hIcon = CreateIconIndirect(&ii);
       
   270 
       
   271     DeleteObject(ii.hbmColor);
       
   272     DeleteObject(ii.hbmMask);
       
   273 
       
   274     return hIcon;
       
   275 }
       
   276 
       
   277 #ifdef Q_WS_WIN
       
   278 #ifndef Q_WS_WINCE
       
   279 
       
   280 static QImage qt_fromWinHBITMAP(HDC hdc, HBITMAP bitmap, int w, int h)
       
   281 {
       
   282     BITMAPINFO bmi;
       
   283     memset(&bmi, 0, sizeof(bmi));
       
   284     bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
       
   285     bmi.bmiHeader.biWidth       = w;
       
   286     bmi.bmiHeader.biHeight      = -h;
       
   287     bmi.bmiHeader.biPlanes      = 1;
       
   288     bmi.bmiHeader.biBitCount    = 32;
       
   289     bmi.bmiHeader.biCompression = BI_RGB;
       
   290     bmi.bmiHeader.biSizeImage   = w * h * 4;
       
   291 
       
   292     QImage image(w, h, QImage::Format_ARGB32_Premultiplied);
       
   293     if (image.isNull())
       
   294         return image;
       
   295 
       
   296     // Get bitmap bits
       
   297     uchar *data = (uchar *) qMalloc(bmi.bmiHeader.biSizeImage);
       
   298 
       
   299     if (GetDIBits(hdc, bitmap, 0, h, data, &bmi, DIB_RGB_COLORS)) {
       
   300         // Create image and copy data into image.
       
   301         for (int y=0; y<h; ++y) {
       
   302             void *dest = (void *) image.scanLine(y);
       
   303             void *src = data + y * image.bytesPerLine();
       
   304             memcpy(dest, src, image.bytesPerLine());
       
   305         }
       
   306     } else {
       
   307         qWarning("qt_fromWinHBITMAP(), failed to get bitmap bits");
       
   308     }
       
   309     qFree(data);
       
   310 
       
   311     return image;
       
   312 }
       
   313 
       
   314 QPixmap QPixmap::fromWinHICON(HICON icon)
       
   315 {
       
   316     bool foundAlpha = false;
       
   317     HDC screenDevice = GetDC(0);
       
   318     HDC hdc = CreateCompatibleDC(screenDevice);
       
   319     ReleaseDC(0, screenDevice);
       
   320 
       
   321     ICONINFO iconinfo;
       
   322     bool result = GetIconInfo(icon, &iconinfo); //x and y Hotspot describes the icon center
       
   323     if (!result)
       
   324         qWarning("QPixmap::fromWinHICON(), failed to GetIconInfo()");
       
   325 
       
   326     int w = iconinfo.xHotspot * 2;
       
   327     int h = iconinfo.yHotspot * 2;
       
   328 
       
   329     BITMAPINFOHEADER bitmapInfo;
       
   330     bitmapInfo.biSize        = sizeof(BITMAPINFOHEADER);
       
   331     bitmapInfo.biWidth       = w;
       
   332     bitmapInfo.biHeight      = h;
       
   333     bitmapInfo.biPlanes      = 1;
       
   334     bitmapInfo.biBitCount    = 32;
       
   335     bitmapInfo.biCompression = BI_RGB;
       
   336     bitmapInfo.biSizeImage   = 0;
       
   337     bitmapInfo.biXPelsPerMeter = 0;
       
   338     bitmapInfo.biYPelsPerMeter = 0;
       
   339     bitmapInfo.biClrUsed       = 0;
       
   340     bitmapInfo.biClrImportant  = 0;
       
   341     DWORD* bits;
       
   342 
       
   343     HBITMAP winBitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bitmapInfo, DIB_RGB_COLORS, (VOID**)&bits, NULL, 0);
       
   344     HGDIOBJ oldhdc = (HBITMAP)SelectObject(hdc, winBitmap);
       
   345     DrawIconEx( hdc, 0, 0, icon, iconinfo.xHotspot * 2, iconinfo.yHotspot * 2, 0, 0, DI_NORMAL);
       
   346     QImage image = qt_fromWinHBITMAP(hdc, winBitmap, w, h);
       
   347 
       
   348     for (int y = 0 ; y < h && !foundAlpha ; y++) {
       
   349         QRgb *scanLine= reinterpret_cast<QRgb *>(image.scanLine(y));
       
   350         for (int x = 0; x < w ; x++) {
       
   351             if (qAlpha(scanLine[x]) != 0) {
       
   352                 foundAlpha = true;
       
   353                 break;
       
   354             }
       
   355         }
       
   356     }
       
   357     if (!foundAlpha) {
       
   358         //If no alpha was found, we use the mask to set alpha values
       
   359         DrawIconEx( hdc, 0, 0, icon, w, h, 0, 0, DI_MASK);
       
   360         QImage mask = qt_fromWinHBITMAP(hdc, winBitmap, w, h);
       
   361 
       
   362         for (int y = 0 ; y < h ; y++){
       
   363             QRgb *scanlineImage = reinterpret_cast<QRgb *>(image.scanLine(y));
       
   364             QRgb *scanlineMask = mask.isNull() ? 0 : reinterpret_cast<QRgb *>(mask.scanLine(y));
       
   365             for (int x = 0; x < w ; x++){
       
   366                 if (scanlineMask && qRed(scanlineMask[x]) != 0)
       
   367                     scanlineImage[x] = 0; //mask out this pixel
       
   368                 else
       
   369                     scanlineImage[x] |= 0xff000000; // set the alpha channel to 255
       
   370             }
       
   371         }
       
   372     }
       
   373     //dispose resources created by iconinfo call
       
   374     DeleteObject(iconinfo.hbmMask);
       
   375     DeleteObject(iconinfo.hbmColor);
       
   376 
       
   377     SelectObject(hdc, oldhdc); //restore state
       
   378     DeleteObject(winBitmap);
       
   379     DeleteDC(hdc);
       
   380     return QPixmap::fromImage(image);
       
   381 }
       
   382 #else //ifndef Q_WS_WINCE
       
   383 QPixmap QPixmap::fromWinHICON(HICON icon)
       
   384 {
       
   385     HDC screenDevice = GetDC(0);
       
   386     HDC hdc = CreateCompatibleDC(screenDevice);
       
   387     ReleaseDC(0, screenDevice);
       
   388 
       
   389     ICONINFO iconinfo;
       
   390     bool result = GetIconInfo(icon, &iconinfo);
       
   391     if (!result)
       
   392         qWarning("QPixmap::fromWinHICON(), failed to GetIconInfo()");
       
   393 
       
   394     int w = 0;
       
   395     int h = 0;
       
   396     if (!iconinfo.xHotspot || !iconinfo.yHotspot) {
       
   397         // We could not retrieve the icon size via GetIconInfo,
       
   398         // so we try again using the icon bitmap.
       
   399         BITMAP bm;
       
   400         int result = GetObject(iconinfo.hbmColor, sizeof(BITMAP), &bm);
       
   401         if (!result) result = GetObject(iconinfo.hbmMask, sizeof(BITMAP), &bm);
       
   402         if (!result) {
       
   403             qWarning("QPixmap::fromWinHICON(), failed to retrieve icon size");
       
   404             return QPixmap();
       
   405         }
       
   406         w = bm.bmWidth;
       
   407         h = bm.bmHeight;
       
   408     } else {
       
   409         // x and y Hotspot describes the icon center
       
   410         w = iconinfo.xHotspot * 2;
       
   411         h = iconinfo.yHotspot * 2;
       
   412     }
       
   413     const DWORD dwImageSize = w * h * 4;
       
   414 
       
   415     BITMAPINFO bmi;
       
   416     memset(&bmi, 0, sizeof(bmi));
       
   417     bmi.bmiHeader.biSize        = sizeof(BITMAPINFO);
       
   418     bmi.bmiHeader.biWidth       = w;
       
   419     bmi.bmiHeader.biHeight      = -h;
       
   420     bmi.bmiHeader.biPlanes      = 1;
       
   421     bmi.bmiHeader.biBitCount    = 32;
       
   422     bmi.bmiHeader.biCompression = BI_RGB;
       
   423     bmi.bmiHeader.biSizeImage   = dwImageSize;
       
   424 
       
   425     uchar* bits;
       
   426 
       
   427     HBITMAP winBitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**) &bits, 0, 0);
       
   428     if (winBitmap )
       
   429         memset(bits, 0xff, dwImageSize);
       
   430     if (!winBitmap) {
       
   431         qWarning("QPixmap::fromWinHICON(), failed to CreateDIBSection()");
       
   432         return QPixmap();
       
   433     }
       
   434 
       
   435     HGDIOBJ oldhdc = (HBITMAP)SelectObject(hdc, winBitmap);
       
   436     if (!DrawIconEx( hdc, 0, 0, icon, w, h, 0, 0, DI_NORMAL))
       
   437         qWarning("QPixmap::fromWinHICON(), failed to DrawIcon()");
       
   438 
       
   439     uint mask = 0xff000000;
       
   440     // Create image and copy data into image.
       
   441     QImage image(w, h, QImage::Format_ARGB32);
       
   442 
       
   443     if (!image.isNull()) { // failed to alloc?
       
   444         int bytes_per_line = w * sizeof(QRgb);
       
   445         for (int y=0; y < h; ++y) {
       
   446             QRgb *dest = (QRgb *) image.scanLine(y);
       
   447             const QRgb *src = (const QRgb *) (bits + y * bytes_per_line);
       
   448             for (int x=0; x < w; ++x) {
       
   449                 dest[x] = src[x];
       
   450             }
       
   451         }
       
   452     }
       
   453     if (!DrawIconEx( hdc, 0, 0, icon, w, h, 0, 0, DI_MASK))
       
   454         qWarning("QPixmap::fromWinHICON(), failed to DrawIcon()");
       
   455     if (!image.isNull()) { // failed to alloc?
       
   456         int bytes_per_line = w * sizeof(QRgb);
       
   457         for (int y=0; y < h; ++y) {
       
   458             QRgb *dest = (QRgb *) image.scanLine(y);
       
   459             const QRgb *src = (const QRgb *) (bits + y * bytes_per_line);
       
   460             for (int x=0; x < w; ++x) {
       
   461                 if (!src[x])
       
   462                     dest[x] = dest[x] | mask;
       
   463             }
       
   464         }
       
   465     }
       
   466     SelectObject(hdc, oldhdc); //restore state
       
   467     DeleteObject(winBitmap);
       
   468     DeleteDC(hdc);
       
   469     return QPixmap::fromImage(image);
       
   470 }
       
   471 #endif //ifndef Q_WS_WINCE
       
   472 #endif //ifdef Q_WS_WIN
       
   473 
       
   474 QT_END_NAMESPACE