diff options
Diffstat (limited to 'src/plugins/platforms/windows/pixmaputils.cpp')
-rw-r--r-- | src/plugins/platforms/windows/pixmaputils.cpp | 316 |
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 |