QtGui: Add Windows conversion functions for to QImage

Add conversions from/to HBITMAP, HICON to QImage. Split the pixmap
conversion functions apart to use them.

Task-number: QTBUG-81876
Change-Id: Ic0c41a402a1f6e9bec572fc4d691357bd48e6423
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Friedemann Kleint 2020-07-24 09:22:16 +02:00
parent b4aee30692
commit f06dfb60b9
3 changed files with 119 additions and 20 deletions

View File

@ -298,6 +298,11 @@ public:
// Platform specific conversion functions
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
CGImageRef toCGImage() const Q_DECL_CF_RETURNS_RETAINED;
#elif defined(Q_OS_WIN) || defined(Q_QDOC)
HBITMAP toHBITMAP() const;
HICON toHICON(const QImage &mask = {}) const;
static QImage fromHBITMAP(HBITMAP hbitmap);
static QImage fromHICON(HICON icon);
#endif
protected:

View File

@ -228,9 +228,9 @@ enum HBitmapFormat
HBitmapAlpha
};
Q_GUI_EXPORT HBITMAP qt_createIconMask(const QBitmap &bitmap)
static HBITMAP qt_createIconMask(QImage bm)
{
QImage bm = bitmap.toImage().convertToFormat(QImage::Format_Mono);
Q_ASSERT(bm.format() == QImage::Format_Mono);
const int w = bm.width();
const int h = bm.height();
const int bpl = ((w+15)/16)*2; // bpl, 16 bit alignment
@ -242,6 +242,11 @@ Q_GUI_EXPORT HBITMAP qt_createIconMask(const QBitmap &bitmap)
return hbm;
}
Q_GUI_EXPORT HBITMAP qt_createIconMask(const QBitmap &bitmap)
{
return qt_createIconMask(bitmap.toImage().convertToFormat(QImage::Format_Mono));
}
static inline QImage::Format format32(int hbitmapFormat)
{
switch (hbitmapFormat) {
@ -344,6 +349,40 @@ Q_GUI_EXPORT HBITMAP qt_imageToWinHBITMAP(const QImage &imageIn, int hbitmapForm
return bitmap;
}
/*!
\since 6.0
Creates a \c HBITMAP equivalent of the QImage. Returns the \c HBITMAP
handle.
It is the caller's responsibility to free the \c HBITMAP data
after use.
For usage with with standard GDI calls, such as \c BitBlt(), the image
should have the format QImage::Format_RGB32.
When using the resulting HBITMAP for the \c AlphaBlend() GDI function,
the image should have the format QImage::Format_ARGB32_Premultiplied
(use convertToFormat()).
When using the resulting HBITMAP as application icon or a systray icon,
the image should have the format QImage::Format_ARGB32.
\sa fromHBITMAP(), convertToFormat()
*/
HBITMAP QImage::toHBITMAP() const
{
switch (format()) {
case QImage::Format_ARGB32:
return qt_imageToWinHBITMAP(*this, HBitmapAlpha);
case QImage::Format_ARGB32_Premultiplied:
return qt_imageToWinHBITMAP(*this, HBitmapPremultipliedAlpha);
default:
break;
}
return qt_imageToWinHBITMAP(*this);
}
Q_GUI_EXPORT HBITMAP qt_pixmapToWinHBITMAP(const QPixmap &p, int hbitmapFormat = 0)
{
if (p.isNull())
@ -451,26 +490,64 @@ Q_GUI_EXPORT QImage qt_imageFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0
return result;
}
/*!
\since 6.0
Returns a QImage that is equivalent to the given \a bitmap.
HBITMAP does not store information about the alpha channel.
In the standard case, the alpha channel is ignored and a fully
opaque image is created (typically of format QImage::Format_RGB32).
There are cases where the alpha channel is used, though, for example
for application icon or systray icons. In that case,
\c reinterpretAsFormat(QImage::Format_ARGB32) should be called
on the returned image to ensure the format is correct.
\sa toHBITMAP(), reinterpretAsFormat()
*/
QImage QImage::fromHBITMAP(HBITMAP hbitmap)
{
return qt_imageFromWinHBITMAP(hbitmap);
}
Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0)
{
return QPixmap::fromImage(imageFromWinHBITMAP_GetDiBits(bitmap, /* forceQuads */ true, hbitmapFormat));
}
Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &p)
/*!
\since 6.0
Creates a \c HICON equivalent of the QPixmap, applying the mask
\a mask. If \a mask is not null, it needs to be of format QImage::Format_Mono.
Returns the \c HICON handle.
It is the caller's responsibility to free the \c HICON data after use.
\sa fromHICON()
*/
HICON QImage::toHICON(const QImage &mask) const
{
if (p.isNull())
if (!mask.isNull() && mask.format() != QImage::Format_Mono) {
qWarning("QImage::toHICON(): Mask must be empty or have format Format_Mono");
return nullptr;
}
if (isNull())
return nullptr;
QBitmap maskBitmap = p.mask();
if (maskBitmap.isNull()) {
maskBitmap = QBitmap(p.size());
maskBitmap.fill(Qt::color1);
auto effectiveMask = mask;
if (effectiveMask.isNull()) {
effectiveMask = QImage(size(), QImage::Format_Mono);
effectiveMask.fill(Qt::color1);
}
ICONINFO ii;
ii.fIcon = true;
ii.hbmMask = qt_createIconMask(maskBitmap);
ii.hbmColor = qt_pixmapToWinHBITMAP(p, HBitmapAlpha);
ii.hbmMask = qt_createIconMask(effectiveMask);
ii.hbmColor = qt_imageToWinHBITMAP(*this, HBitmapAlpha);
ii.xHotspot = 0;
ii.yHotspot = 0;
@ -482,6 +559,15 @@ Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &p)
return hIcon;
}
Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &p)
{
QImage mask;
QBitmap maskBitmap = p.mask();
if (!maskBitmap.isNull())
mask = maskBitmap.toImage().convertToFormat(QImage::Format_Mono);
return p.toImage().toHICON(mask);
}
Q_GUI_EXPORT QImage qt_imageFromWinHBITMAP(HDC hdc, HBITMAP bitmap, int w, int h)
{
QImage image(w, h, QImage::Format_ARGB32_Premultiplied);
@ -520,7 +606,14 @@ static inline bool hasAlpha(const QImage &image)
return false;
}
Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon)
/*!
\since 6.0
Returns a QImage that is equivalent to the given \a icon.
\sa toHICON()
*/
QImage QImage::fromHICON(HICON icon)
{
HDC screenDevice = GetDC(nullptr);
HDC hdc = CreateCompatibleDC(screenDevice);
@ -531,7 +624,7 @@ Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon)
if (!result) {
qErrnoWarning("QPixmap::fromWinHICON(), failed to GetIconInfo()");
DeleteDC(hdc);
return QPixmap();
return {};
}
const int w = int(iconinfo.xHotspot) * 2;
@ -570,7 +663,12 @@ Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon)
SelectObject(hdc, oldhdc); //restore state
DeleteObject(winBitmap);
DeleteDC(hdc);
return QPixmap::fromImage(std::move(image));
return image;
}
Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon)
{
return QPixmap::fromImage(QImage::fromHICON(icon));
}
QT_END_NAMESPACE

View File

@ -3777,10 +3777,6 @@ void tst_QImage::wideImage()
}
#if defined(Q_OS_WIN)
QT_BEGIN_NAMESPACE
Q_GUI_EXPORT HBITMAP qt_imageToWinHBITMAP(const QImage &p, int hbitmapFormat = 0);
Q_GUI_EXPORT QImage qt_imageFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0);
QT_END_NAMESPACE
static inline QColor COLORREFToQColor(COLORREF cr)
{
@ -3844,7 +3840,7 @@ void tst_QImage::toWinHBITMAP()
? createTestImage(QImage::Format_RGB32, width, height, color, bottomRightColor).convertToFormat(format)
: createTestImage(format, width, height, color, bottomRightColor);
const HBITMAP bitmap = qt_imageToWinHBITMAP(image);
const HBITMAP bitmap = image.toHBITMAP();
QVERIFY(bitmap != 0);
@ -3867,7 +3863,7 @@ void tst_QImage::toWinHBITMAP()
QCOMPARE(COLORREFToQColor(GetPixel(bitmapDc, 3, height - 1)), color);
QCOMPARE(COLORREFToQColor(GetPixel(bitmapDc, width - 1, height - 1)), bottomRightColor);
const QImage convertedBack = qt_imageFromWinHBITMAP(bitmap);
const QImage convertedBack = QImage::fromHBITMAP(bitmap);
QCOMPARE(convertedBack.convertToFormat(QImage::Format_ARGB32_Premultiplied),
image.convertToFormat(QImage::Format_ARGB32_Premultiplied));
@ -3884,7 +3880,7 @@ void tst_QImage::fromMonoHBITMAP() // QTBUG-72343, corruption for mono bitmaps
char bitmapData[size];
memset(bitmapData, 0, size);
const HBITMAP hbitmap = CreateBitmap(width, height, /* planes */ 1, /* bitcount */ 1, bitmapData);
const QImage image = qt_imageFromWinHBITMAP(hbitmap);
const QImage image = QImage::fromHBITMAP(hbitmap);
QCOMPARE(image.size(), QSize(width, height));
QCOMPARE(image.scanLine(0)[0], 0u);
DeleteObject(hbitmap);