Windows: Fix qt_imageFromWinHBITMAP().
Factor out common code paths from the QPixmap/QImage conversion code and use the same algorithm for copying the image data with alpha correction as does qt_pixmapFromWinHBITMAP(). Rename the previous version of qt_imageFromWinHBITMAP() to qt_imageFromWinIconHBITMAP() since it is used for HICON conversion. Task-number: QTBUG-39084 Change-Id: Ia4042c33db485c3604461a5eafd6282968b36e3b Reviewed-by: Andy Shaw <andy.shaw@digia.com>
This commit is contained in:
parent
57d0ed8f1e
commit
d3d8ade87b
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
@ -133,6 +133,68 @@ int qt_wince_GetDIBits(HDC /*hdc*/ , HBITMAP hSourceBitmap, uint, uint, LPVOID l
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void initBitMapInfoHeader(int width, int height, bool topToBottom, BITMAPINFOHEADER *bih)
|
||||
{
|
||||
memset(bih, 0, sizeof(BITMAPINFOHEADER));
|
||||
bih->biSize = sizeof(BITMAPINFOHEADER);
|
||||
bih->biWidth = width;
|
||||
bih->biHeight = topToBottom ? -height : height;
|
||||
bih->biPlanes = 1;
|
||||
bih->biBitCount = 32;
|
||||
bih->biCompression = BI_RGB;
|
||||
bih->biSizeImage = width * height * 4;
|
||||
}
|
||||
|
||||
static inline void initBitMapInfo(int width, int height, bool topToBottom, BITMAPINFO *bmi)
|
||||
{
|
||||
initBitMapInfoHeader(width, height, topToBottom, &bmi->bmiHeader);
|
||||
memset(bmi->bmiColors, 0, sizeof(RGBQUAD));
|
||||
}
|
||||
|
||||
static inline uchar *getDiBits(HDC hdc, HBITMAP bitmap, int width, int height, bool topToBottom = true)
|
||||
{
|
||||
BITMAPINFO bmi;
|
||||
initBitMapInfo(width, height, topToBottom, &bmi);
|
||||
uchar *result = new uchar[bmi.bmiHeader.biSizeImage];
|
||||
if (!GetDIBits(hdc, bitmap, 0, height, result, &bmi, DIB_RGB_COLORS)) {
|
||||
delete [] result;
|
||||
qErrnoWarning("%s: GetDIBits() failed to get bitmap bits.", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void copyImageDataCreateAlpha(const uchar *data, QImage *target)
|
||||
{
|
||||
const uint mask = target->format() == QImage::Format_RGB32 ? 0xff000000 : 0;
|
||||
const int height = target->height();
|
||||
const int width = target->width();
|
||||
const int bytesPerLine = width * int(sizeof(QRgb));
|
||||
for (int y = 0; y < height; ++y) {
|
||||
QRgb *dest = reinterpret_cast<QRgb *>(target->scanLine(y));
|
||||
const QRgb *src = reinterpret_cast<const QRgb *>(data + y * bytesPerLine);
|
||||
for (int x = 0; x < width; ++x) {
|
||||
const uint pixel = src[x];
|
||||
if ((pixel & 0xff000000) == 0 && (pixel & 0x00ffffff) != 0)
|
||||
dest[x] = pixel | 0xff000000;
|
||||
else
|
||||
dest[x] = pixel | mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void copyImageData(const uchar *data, QImage *target)
|
||||
{
|
||||
const int height = target->height();
|
||||
const int bytesPerLine = target->bytesPerLine();
|
||||
for (int y = 0; y < height; ++y) {
|
||||
void *dest = static_cast<void *>(target->scanLine(y));
|
||||
const void *src = data + y * bytesPerLine;
|
||||
memcpy(dest, src, bytesPerLine);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum HBitmapFormat
|
||||
{
|
||||
HBitmapNoAlpha,
|
||||
@ -176,14 +238,7 @@ Q_GUI_EXPORT HBITMAP qt_pixmapToWinHBITMAP(const QPixmap &p, int hbitmapFormat =
|
||||
|
||||
// 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;
|
||||
initBitMapInfo(w, h, true, &bmi);
|
||||
|
||||
// Create the pixmap
|
||||
uchar *pixels = 0;
|
||||
@ -227,31 +282,16 @@ Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat =
|
||||
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)) {
|
||||
QScopedArrayPointer<uchar> data(getDiBits(display_dc, bitmap, w, h, true));
|
||||
if (data.isNull()) {
|
||||
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 (hbitmapFormat == HBitmapNoAlpha) {
|
||||
imageFormat = QImage::Format_RGB32;
|
||||
mask = 0xff000000;
|
||||
}
|
||||
const QImage::Format imageFormat = hbitmapFormat == HBitmapNoAlpha ?
|
||||
QImage::Format_RGB32 : QImage::Format_ARGB32_Premultiplied;
|
||||
|
||||
// Create image and copy data into image.
|
||||
QImage image(w, h, imageFormat);
|
||||
@ -260,18 +300,7 @@ Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat =
|
||||
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;
|
||||
}
|
||||
}
|
||||
copyImageDataCreateAlpha(data.data(), &image);
|
||||
ReleaseDC(0, display_dc);
|
||||
return QPixmap::fromImage(image);
|
||||
}
|
||||
@ -307,32 +336,25 @@ Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &p)
|
||||
|
||||
Q_GUI_EXPORT QImage qt_imageFromWinHBITMAP(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
|
||||
QScopedArrayPointer<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__);
|
||||
QScopedArrayPointer<uchar> data(getDiBits(hdc, bitmap, w, h, true));
|
||||
if (data.isNull())
|
||||
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());
|
||||
}
|
||||
copyImageDataCreateAlpha(data.data(), &image);
|
||||
return image;
|
||||
}
|
||||
|
||||
static QImage qt_imageFromWinIconHBITMAP(HDC hdc, HBITMAP bitmap, int w, int h)
|
||||
{
|
||||
QImage image(w, h, QImage::Format_ARGB32_Premultiplied);
|
||||
if (image.isNull())
|
||||
return image;
|
||||
QScopedArrayPointer<uchar> data(getDiBits(hdc, bitmap, w, h, true));
|
||||
if (data.isNull())
|
||||
return QImage();
|
||||
copyImageData(data.data(), &image);
|
||||
return image;
|
||||
}
|
||||
|
||||
@ -354,23 +376,13 @@ Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon)
|
||||
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;
|
||||
initBitMapInfoHeader(w, h, false, &bitmapInfo);
|
||||
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 = qt_imageFromWinHBITMAP(hdc, winBitmap, w, h);
|
||||
QImage image = qt_imageFromWinIconHBITMAP(hdc, winBitmap, w, h);
|
||||
|
||||
for (int y = 0 ; y < h && !foundAlpha ; y++) {
|
||||
const QRgb *scanLine= reinterpret_cast<const QRgb *>(image.scanLine(y));
|
||||
@ -384,7 +396,7 @@ Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon)
|
||||
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 = qt_imageFromWinHBITMAP(hdc, winBitmap, w, h);
|
||||
const QImage mask = qt_imageFromWinIconHBITMAP(hdc, winBitmap, w, h);
|
||||
|
||||
for (int y = 0 ; y < h ; y++){
|
||||
QRgb *scanlineImage = reinterpret_cast<QRgb *>(image.scanLine(y));
|
||||
|
Loading…
Reference in New Issue
Block a user