Darwin: Add QImage::toCGImage() conversion function

(Move QT_FORWARD_DECLARE_CG to qglobal.h)

This function converts to CGImage for supported formats. This
is done by creating a CGImageRef that reuses the QImage data.

The CGImage and QImage ref counting systems are bridged, implemented
by using CGDataProvider that holds a copy of the QImage.

Unlike the previous internal implementation this public version
does not implicitly convert unsupported formats to ARGB32_Premultiplied.

See included documentation for the complete description.

Change-Id: Ie3984a7a8331e02a6f1c42943caaf76854e93538
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@qt.io>
This commit is contained in:
Morten Johan Sørvig 2015-11-02 10:49:17 +01:00 committed by Morten Johan Sørvig
parent dfae6a7593
commit b0abe20d4b
6 changed files with 205 additions and 2 deletions

View File

@ -538,6 +538,12 @@ Q_DECL_CONSTEXPR inline const T &qBound(const T &min, const T &val, const T &max
#ifndef Q_FORWARD_DECLARE_MUTABLE_CF_TYPE
# define Q_FORWARD_DECLARE_MUTABLE_CF_TYPE(type) typedef struct __ ## type * type ## Ref
#endif
#ifndef Q_FORWARD_DECLARE_CG_TYPE
#define Q_FORWARD_DECLARE_CG_TYPE(type) typedef const struct type *type ## Ref;
#endif
#ifndef Q_FORWARD_DECLARE_MUTABLE_CG_TYPE
#define Q_FORWARD_DECLARE_MUTABLE_CG_TYPE(type) typedef struct type *type ## Ref;
#endif
#ifdef Q_OS_DARWIN
# define QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(macos, ios, tvos, watchos) \

View File

@ -438,8 +438,8 @@ inline QDebug operator<<(QDebug debug, const QFlags<T> &flags)
#define QT_FORWARD_DECLARE_CF_TYPE(type) Q_FORWARD_DECLARE_CF_TYPE(type);
#define QT_FORWARD_DECLARE_MUTABLE_CF_TYPE(type) Q_FORWARD_DECLARE_MUTABLE_CF_TYPE(type);
#define QT_FORWARD_DECLARE_CG_TYPE(type) typedef const struct type *type ## Ref;
#define QT_FORWARD_DECLARE_MUTABLE_CG_TYPE(type) typedef struct type *type ## Ref;
#define QT_FORWARD_DECLARE_CG_TYPE(type) Q_FORWARD_DECLARE_CG_TYPE(type);
#define QT_FORWARD_DECLARE_MUTABLE_CG_TYPE(type) Q_FORWARD_DECLARE_MUTABLE_CG_TYPE(type);
QT_END_NAMESPACE
Q_FORWARD_DECLARE_CF_TYPE(CFString);

View File

@ -53,6 +53,8 @@ SOURCES += \
win32:!winrt: SOURCES += image/qpixmap_win.cpp
darwin: OBJECTIVE_SOURCES += image/qimage_darwin.mm
NO_PCH_SOURCES += image/qimage_compat.cpp
false: SOURCES += $$NO_PCH_SOURCES # Hack for QtCreator

View File

@ -54,6 +54,10 @@
#include <QtCore/qstringlist.h>
#endif
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
Q_FORWARD_DECLARE_MUTABLE_CG_TYPE(CGImage);
#endif
QT_BEGIN_NAMESPACE
@ -321,6 +325,11 @@ public:
static QPixelFormat toPixelFormat(QImage::Format format) Q_DECL_NOTHROW;
static QImage::Format toImageFormat(QPixelFormat format) Q_DECL_NOTHROW;
// Platform spesific conversion functions
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
CGImageRef toCGImage() const Q_DECL_CF_RETURNS_RETAINED;
#endif
#if QT_DEPRECATED_SINCE(5, 0)
QT_DEPRECATED inline QString text(const char *key, const char *lang = Q_NULLPTR) const;
QT_DEPRECATED inline QList<QImageTextKeyLang> textList() const;

View File

@ -0,0 +1,141 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qimage.h"
#include <private/qcore_mac_p.h>
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
QT_BEGIN_NAMESPACE
/*!
Creates a \c CGImage equivalent to the QImage \a image. Returns a
\c CGImageRef handle.
The returned CGImageRef partakes in the QImage implicit sharing,
and holds a reference to the QImage data. CGImage is immutable
and will never detach the QImage. Writing to the QImage will detach
as usual.
This function is fast, and does not copy or convert image data.
The following image formats are supported, and will be mapped to
a corresponding native image type:
\table
\header
\li Qt
\li CoreGraphics
\row
\li Format_ARGB32
\li kCGImageAlphaFirst | kCGBitmapByteOrder32Host
\row
\li Format_RGB32
\li kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host
\row
\li Format_RGBA8888_Premultiplied
\li kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big
\row
\li Format_RGBA8888
\li kCGImageAlphaLast | kCGBitmapByteOrder32Big
\row
\li Format_RGBX8888
\li kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big
\row
\li Format_ARGB32_Premultiplied
\li kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host
\endtable
Other formats are not supported; this function returns a null
CGImageRef for those cases. Users of this function may then
convert the QImage to a supported formate first, for example
Format_ARGB32_Premultiplied.
The CGImageRef color space is set to the sRGB color space.
\sa toNSImage()
*/
CGImageRef QImage::toCGImage() const
{
if (isNull())
return nil;
// Determine the target native format
uint cgflags = kCGImageAlphaNone;
switch (format()) {
case QImage::Format_ARGB32:
cgflags = kCGImageAlphaFirst | kCGBitmapByteOrder32Host;
break;
case QImage::Format_RGB32:
cgflags = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
break;
case QImage::Format_RGBA8888_Premultiplied:
cgflags = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;
break;
case QImage::Format_RGBA8888:
cgflags = kCGImageAlphaLast | kCGBitmapByteOrder32Big;
break;
case QImage::Format_RGBX8888:
cgflags = kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big;
break;
case QImage::Format_ARGB32_Premultiplied:
cgflags = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
break;
default: break;
}
// Format not supported: return nil CGImageRef
if (cgflags == kCGImageAlphaNone)
return nil;
// Create a data provider that owns a copy of the QImage and references the image data.
auto deleter = [](void *image, const void *, size_t)
{ delete static_cast<QImage *>(image); };
QCFType<CGDataProviderRef> dataProvider =
CGDataProviderCreateWithData(new QImage(*this), bits(), byteCount(), deleter);
QCFType<CGColorSpaceRef> colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
const size_t bitsPerComponent = 8;
const size_t bitsPerPixel = 32;
const CGFloat *decode = nullptr;
const bool shouldInterpolate = false;
return CGImageCreate(width(), height(), bitsPerComponent, bitsPerPixel,
this->bytesPerLine(), colorSpace, cgflags, dataProvider,
decode, shouldInterpolate, kCGRenderingIntentDefault);
}
QT_END_NAMESPACE

View File

@ -39,6 +39,10 @@
#include <private/qimage_p.h>
#include <private/qdrawhelper_p.h>
#ifdef Q_OS_DARWIN
#include <CoreGraphics/CoreGraphics.h>
#endif
Q_DECLARE_METATYPE(QImage::Format)
Q_DECLARE_METATYPE(Qt::GlobalColor)
@ -201,6 +205,11 @@ private slots:
void ditherGradient_data();
void ditherGradient();
#ifdef Q_OS_DARWIN
void toCGImage_data();
void toCGImage();
#endif
private:
const QString m_prefix;
};
@ -3307,5 +3316,41 @@ void tst_QImage::ditherGradient()
QVERIFY(observedGradientSteps >= minimumExpectedGradient);
}
#ifdef Q_OS_DARWIN
void tst_QImage::toCGImage_data()
{
QTest::addColumn<QImage::Format>("format");
QTest::addColumn<bool>("supported");
// Populate test data with supported status for all QImage formats.
QSet<QImage::Format> supported =
{ QImage::Format_ARGB32, QImage::Format_RGB32, QImage::Format_RGBA8888_Premultiplied,
QImage::Format_RGBA8888, QImage::Format_RGBX8888, QImage::Format_ARGB32_Premultiplied };
for (int i = QImage::Format_Invalid; i < QImage::Format_Grayscale8; ++i) {
QTest::newRow(qPrintable(formatToString(QImage::Format(i))))
<< QImage::Format(i) << supported.contains(QImage::Format(i));
}
}
// Verify that toCGImage() returns a valid CGImageRef for supported image formats.
void tst_QImage::toCGImage()
{
QFETCH(QImage::Format, format);
QFETCH(bool, supported);
QImage qimage(64, 64, format);
qimage.fill(Qt::red);
CGImageRef cgimage = qimage.toCGImage();
QCOMPARE(cgimage != nullptr, supported);
CGImageRelease(cgimage);
}
#endif
QTEST_GUILESS_MAIN(tst_QImage)
#include "tst_qimage.moc"