summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/windows/pixmaputils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/windows/pixmaputils.cpp')
-rw-r--r--src/plugins/platforms/windows/pixmaputils.cpp316
1 files changed, 316 insertions, 0 deletions
diff --git a/src/plugins/platforms/windows/pixmaputils.cpp b/src/plugins/platforms/windows/pixmaputils.cpp
new file mode 100644
index 0000000000..111df5a4b9
--- /dev/null
+++ b/src/plugins/platforms/windows/pixmaputils.cpp
@@ -0,0 +1,316 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pixmaputils.h"
+
+#include <QtGui/QBitmap>
+#include <QtGui/QImage>
+#include <QtGui/QPlatformPixmap>
+#include <QtGui/private/qpixmap_raster_p.h>
+
+#include <QtCore/QScopedArrayPointer>
+#include <QtCore/QDebug>
+
+#include <string.h>
+
+QT_BEGIN_NAMESPACE
+
+HBITMAP createIconMask(const QBitmap &bitmap)
+{
+ QImage bm = bitmap.toImage().convertToFormat(QImage::Format_Mono);
+ const int w = bm.width();
+ const int h = bm.height();
+ const int bpl = ((w+15)/16)*2; // bpl, 16 bit alignment
+ QScopedArrayPointer<uchar> bits(new uchar[bpl * h]);
+ bm.invertPixels();
+ for (int y = 0; y < h; ++y)
+ memcpy(bits.data() + y * bpl, bm.scanLine(y), bpl);
+ HBITMAP hbm = CreateBitmap(w, h, 1, 1, bits.data());
+ return hbm;
+}
+
+HBITMAP qPixmapToWinHBITMAP(const QPixmap &p, HBitmapFormat format)
+{
+ if (p.isNull())
+ return 0;
+
+ HBITMAP bitmap = 0;
+ if (p.handle()->classId() != QPlatformPixmap::RasterClass) {
+ QRasterPlatformPixmap *data = new QRasterPlatformPixmap(p.depth() == 1 ?
+ QRasterPlatformPixmap::BitmapType : QRasterPlatformPixmap::PixmapType);
+ data->fromImage(p.toImage(), Qt::AutoColor);
+ return qPixmapToWinHBITMAP(QPixmap(data), format);
+ }
+
+ QRasterPlatformPixmap *d = static_cast<QRasterPlatformPixmap*>(p.handle());
+ const QImage *rasterImage = d->buffer();
+ const int w = rasterImage->width();
+ const int h = rasterImage->height();
+
+ HDC display_dc = GetDC(0);
+
+ // Define the header
+ BITMAPINFO bmi;
+ memset(&bmi, 0, sizeof(bmi));
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = w;
+ bmi.bmiHeader.biHeight = -h;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = w * h * 4;
+
+ // Create the pixmap
+ uchar *pixels = 0;
+ bitmap = CreateDIBSection(display_dc, &bmi, DIB_RGB_COLORS, (void **) &pixels, 0, 0);
+ ReleaseDC(0, display_dc);
+ if (!bitmap) {
+ qErrnoWarning("%s, failed to create dibsection", __FUNCTION__);
+ return 0;
+ }
+ if (!pixels) {
+ qErrnoWarning("%s, did not allocate pixel data", __FUNCTION__);
+ return 0;
+ }
+
+ // Copy over the data
+ QImage::Format imageFormat = QImage::Format_ARGB32;
+ if (format == HBitmapAlpha)
+ imageFormat = QImage::Format_RGB32;
+ else if (format == HBitmapPremultipliedAlpha)
+ imageFormat = QImage::Format_ARGB32_Premultiplied;
+ const QImage image = rasterImage->convertToFormat(imageFormat);
+ const int bytes_per_line = w * 4;
+ for (int y=0; y < h; ++y)
+ memcpy(pixels + y * bytes_per_line, image.scanLine(y), bytes_per_line);
+
+ return bitmap;
+}
+
+QPixmap qPixmapFromWinHBITMAP(HBITMAP bitmap, HBitmapFormat format)
+{
+ // Verify size
+ BITMAP bitmap_info;
+ memset(&bitmap_info, 0, sizeof(BITMAP));
+
+ const int res = GetObject(bitmap, sizeof(BITMAP), &bitmap_info);
+ if (!res) {
+ qErrnoWarning("QPixmap::fromWinHBITMAP(), failed to get bitmap info");
+ return QPixmap();
+ }
+ const int w = bitmap_info.bmWidth;
+ const int h = bitmap_info.bmHeight;
+
+ BITMAPINFO bmi;
+ memset(&bmi, 0, sizeof(bmi));
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = w;
+ bmi.bmiHeader.biHeight = -h;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = w * h * 4;
+
+ // Get bitmap bits
+ QScopedArrayPointer<uchar> data(new uchar[bmi.bmiHeader.biSizeImage]);
+ HDC display_dc = GetDC(0);
+ if (!GetDIBits(display_dc, bitmap, 0, h, data.data(), &bmi, DIB_RGB_COLORS)) {
+ ReleaseDC(0, display_dc);
+ qWarning("%s, failed to get bitmap bits", __FUNCTION__);
+ return QPixmap();
+ }
+
+ QImage::Format imageFormat = QImage::Format_ARGB32_Premultiplied;
+ uint mask = 0;
+ if (format == HBitmapNoAlpha) {
+ imageFormat = QImage::Format_RGB32;
+ mask = 0xff000000;
+ }
+
+ // Create image and copy data into image.
+ QImage image(w, h, imageFormat);
+ if (image.isNull()) { // failed to alloc?
+ ReleaseDC(0, display_dc);
+ qWarning("%s, failed create image of %dx%d", __FUNCTION__, w, h);
+ return QPixmap();
+ }
+ const int bytes_per_line = w * sizeof(QRgb);
+ for (int y = 0; y < h; ++y) {
+ QRgb *dest = (QRgb *) image.scanLine(y);
+ const QRgb *src = (const QRgb *) (data.data() + y * bytes_per_line);
+ for (int x = 0; x < w; ++x) {
+ const uint pixel = src[x];
+ if ((pixel & 0xff000000) == 0 && (pixel & 0x00ffffff) != 0)
+ dest[x] = pixel | 0xff000000;
+ else
+ dest[x] = pixel | mask;
+ }
+ }
+ ReleaseDC(0, display_dc);
+ return QPixmap::fromImage(image);
+}
+
+HICON qPixmapToWinHICON(const QPixmap &p)
+{
+ QBitmap maskBitmap = p.mask();
+ if (maskBitmap.isNull()) {
+ maskBitmap = QBitmap(p.size());
+ maskBitmap.fill(Qt::color1);
+ }
+
+ ICONINFO ii;
+ ii.fIcon = true;
+ ii.hbmMask = createIconMask(maskBitmap);
+ ii.hbmColor = qPixmapToWinHBITMAP(p, HBitmapAlpha);
+ ii.xHotspot = 0;
+ ii.yHotspot = 0;
+
+ HICON hIcon = CreateIconIndirect(&ii);
+
+ DeleteObject(ii.hbmColor);
+ DeleteObject(ii.hbmMask);
+
+ return hIcon;
+}
+
+static QImage qImageFromWinHBITMAP(HDC hdc, HBITMAP bitmap, int w, int h)
+{
+ BITMAPINFO bmi;
+ memset(&bmi, 0, sizeof(bmi));
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = w;
+ bmi.bmiHeader.biHeight = -h;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = w * h * 4;
+
+ QImage image(w, h, QImage::Format_ARGB32_Premultiplied);
+ if (image.isNull())
+ return image;
+
+ // Get bitmap bits
+ QScopedPointer<uchar> data(new uchar [bmi.bmiHeader.biSizeImage]);
+ if (!GetDIBits(hdc, bitmap, 0, h, data.data(), &bmi, DIB_RGB_COLORS)) {
+ qErrnoWarning("%s: failed to get bitmap bits", __FUNCTION__);
+ return QImage();
+ }
+ // Create image and copy data into image.
+ for (int y = 0; y < h; ++y) {
+ void *dest = (void *) image.scanLine(y);
+ void *src = data.data() + y * image.bytesPerLine();
+ memcpy(dest, src, image.bytesPerLine());
+ }
+ return image;
+}
+
+QPixmap qPixmapFromWinHICON(HICON icon)
+{
+ bool foundAlpha = false;
+ HDC screenDevice = GetDC(0);
+ HDC hdc = CreateCompatibleDC(screenDevice);
+ ReleaseDC(0, screenDevice);
+
+ ICONINFO iconinfo;
+ const bool result = GetIconInfo(icon, &iconinfo); //x and y Hotspot describes the icon center
+ if (!result) {
+ qErrnoWarning("QPixmap::fromWinHICON(), failed to GetIconInfo()");
+ return QPixmap();
+ }
+
+ const int w = iconinfo.xHotspot * 2;
+ const int h = iconinfo.yHotspot * 2;
+
+ BITMAPINFOHEADER bitmapInfo;
+ bitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
+ bitmapInfo.biWidth = w;
+ bitmapInfo.biHeight = h;
+ bitmapInfo.biPlanes = 1;
+ bitmapInfo.biBitCount = 32;
+ bitmapInfo.biCompression = BI_RGB;
+ bitmapInfo.biSizeImage = 0;
+ bitmapInfo.biXPelsPerMeter = 0;
+ bitmapInfo.biYPelsPerMeter = 0;
+ bitmapInfo.biClrUsed = 0;
+ bitmapInfo.biClrImportant = 0;
+ DWORD* bits;
+
+ HBITMAP winBitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bitmapInfo, DIB_RGB_COLORS, (VOID**)&bits, NULL, 0);
+ HGDIOBJ oldhdc = (HBITMAP)SelectObject(hdc, winBitmap);
+ DrawIconEx( hdc, 0, 0, icon, iconinfo.xHotspot * 2, iconinfo.yHotspot * 2, 0, 0, DI_NORMAL);
+ QImage image = qImageFromWinHBITMAP(hdc, winBitmap, w, h);
+
+ for (int y = 0 ; y < h && !foundAlpha ; y++) {
+ const QRgb *scanLine= reinterpret_cast<const QRgb *>(image.scanLine(y));
+ for (int x = 0; x < w ; x++) {
+ if (qAlpha(scanLine[x]) != 0) {
+ foundAlpha = true;
+ break;
+ }
+ }
+ }
+ if (!foundAlpha) {
+ //If no alpha was found, we use the mask to set alpha values
+ DrawIconEx( hdc, 0, 0, icon, w, h, 0, 0, DI_MASK);
+ const QImage mask = qImageFromWinHBITMAP(hdc, winBitmap, w, h);
+
+ for (int y = 0 ; y < h ; y++){
+ QRgb *scanlineImage = reinterpret_cast<QRgb *>(image.scanLine(y));
+ const QRgb *scanlineMask = mask.isNull() ? 0 : reinterpret_cast<const QRgb *>(mask.scanLine(y));
+ for (int x = 0; x < w ; x++){
+ if (scanlineMask && qRed(scanlineMask[x]) != 0)
+ scanlineImage[x] = 0; //mask out this pixel
+ else
+ scanlineImage[x] |= 0xff000000; // set the alpha channel to 255
+ }
+ }
+ }
+ //dispose resources created by iconinfo call
+ DeleteObject(iconinfo.hbmMask);
+ DeleteObject(iconinfo.hbmColor);
+
+ SelectObject(hdc, oldhdc); //restore state
+ DeleteObject(winBitmap);
+ DeleteDC(hdc);
+ return QPixmap::fromImage(image);
+}
+
+QT_END_NAMESPACE