Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qiiofhelpers.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QGuiApplication>
5#include <QBuffer>
6#include <QImageIOHandler>
7#include <QImage>
8
9#include "qiiofhelpers_p.h"
10
11
13
14// QImage <-> CGImage conversion functions from QtGui on darwin
15CGImageRef qt_mac_toCGImage(const QImage &qImage);
16QImage qt_mac_toQImage(CGImageRef image);
17
18namespace NS_IIOF_HELPERS {
19
20// Callbacks for sequential data provider & consumer:
21
22static size_t cbGetBytes(void *info, void *buffer, size_t count)
23{
24 QIODevice *dev = static_cast<QIODevice *>(info);
25 if (!dev || !buffer)
26 return 0;
27 qint64 res = dev->read(static_cast<char *>(buffer), qint64(count));
28 return size_t(qMax(qint64(0), res));
29}
30
31static off_t cbSkipForward(void *info, off_t count)
32{
33 QIODevice *dev = static_cast<QIODevice *>(info);
34 if (!dev || count <= 0)
35 return 0;
36 qint64 res = 0;
37 if (!dev->isSequential()) {
38 qint64 prevPos = dev->pos();
39 dev->seek(prevPos + count);
40 res = dev->pos() - prevPos;
41 } else {
42 char *buf = new char[quint64(count)];
43 res = dev->read(buf, count);
44 delete[] buf;
45 }
46 return qMax(qint64(0), res);
47}
48
49static void cbRewind(void *)
50{
51 // Ignore this; we do not want the Qt device to be rewound after reading the image
52}
53
54static size_t cbPutBytes(void *info, const void *buffer, size_t count)
55{
56 QIODevice *dev = static_cast<QIODevice *>(info);
57 if (!dev || !buffer)
58 return 0;
59 qint64 res = dev->write(static_cast<const char *>(buffer), qint64(count));
60 return size_t(qMax(qint64(0), res));
61}
62
63
64QImageIOPlugin::Capabilities QIIOFHelpers::systemCapabilities(const QString &uti)
65{
66 QImageIOPlugin::Capabilities res;
67 QCFString cfUti(uti);
68
69 QCFType<CFArrayRef> cfSourceTypes = CGImageSourceCopyTypeIdentifiers();
70 CFIndex len = CFArrayGetCount(cfSourceTypes);
71 if (CFArrayContainsValue(cfSourceTypes, CFRangeMake(0, len), cfUti))
73
74 QCFType<CFArrayRef> cfDestTypes = CGImageDestinationCopyTypeIdentifiers();
75 len = CFArrayGetCount(cfDestTypes);
76 if (CFArrayContainsValue(cfDestTypes, CFRangeMake(0, len), cfUti))
78
79 return res;
80}
81
83{
84 QIIOFHelper h(q_ptr);
85 return h.readImage(out);
86}
87
89{
90 QIIOFHelper h(q_ptr);
91 return h.writeImage(in, uti);
92}
93
98
100{
101 static const CGDataProviderSequentialCallbacks cgCallbacks = { 0, &cbGetBytes, &cbSkipForward, &cbRewind, nullptr };
102
103 if (cgImageSource)
104 return true;
105 if (!q_ptr || !q_ptr->device())
106 return false;
107
108 if (QBuffer *b = qobject_cast<QBuffer *>(q_ptr->device())) {
109 // do direct access to avoid data copy
110 const void *rawData = b->data().constData() + b->pos();
111 cgDataProvider = CGDataProviderCreateWithData(nullptr, rawData, size_t(b->data().size() - b->pos()), nullptr);
112 } else {
113 cgDataProvider = CGDataProviderCreateSequential(q_ptr->device(), &cgCallbacks);
114 }
115
116 cgImageSource = CGImageSourceCreateWithDataProvider(cgDataProvider, nullptr);
117
118 if (cgImageSource)
119 cfImageDict = CGImageSourceCopyPropertiesAtIndex(cgImageSource, 0, nullptr);
120
121 return (cgImageSource);
122}
123
125{
126 if (!out || !initRead())
127 return false;
128
129 QCFType<CGImageRef> cgImage = CGImageSourceCreateImageAtIndex(cgImageSource, 0, nullptr);
130 if (!cgImage)
131 return false;
132
133 *out = qt_mac_toQImage(cgImage);
134 if (out->isNull())
135 return false;
136
137 int dpi = 0;
138 if (getIntProperty(kCGImagePropertyDPIWidth, &dpi))
139 out->setDotsPerMeterX(qRound(dpi / 0.0254f));
140 if (getIntProperty(kCGImagePropertyDPIHeight, &dpi))
141 out->setDotsPerMeterY(qRound(dpi / 0.0254f));
142
143 return true;
144}
145
147{
148 if (!cfImageDict)
149 return false;
150
151 CFNumberRef cfNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(cfImageDict, property));
152 if (cfNumber) {
153 int intVal;
154 if (CFNumberGetValue(cfNumber, kCFNumberIntType, &intVal)) {
155 if (value)
156 *value = intVal;
157 return true;
158 }
159 }
160 return false;
161}
162
163static QImageIOHandler::Transformations exif2Qt(int exifOrientation)
164{
165 switch (exifOrientation) {
166 case 1: // normal
168 case 2: // mirror horizontal
170 case 3: // rotate 180
172 case 4: // mirror vertical
174 case 5: // mirror horizontal and rotate 270 CW
176 case 6: // rotate 90 CW
178 case 7: // mirror horizontal and rotate 90 CW
180 case 8: // rotate 270 CW
182 }
184}
185
186static int qt2Exif(QImageIOHandler::Transformations transformation)
187{
188 switch (transformation) {
190 return 1;
192 return 2;
194 return 3;
196 return 4;
198 return 5;
200 return 6;
202 return 7;
204 return 8;
205 }
206 qWarning("Invalid Qt image transformation");
207 return 1;
208}
209
211{
212 if (!initRead())
213 return QVariant();
214
215 switch (option) {
217 QSize sz;
218 if (getIntProperty(kCGImagePropertyPixelWidth, &sz.rwidth())
219 && getIntProperty(kCGImagePropertyPixelHeight, &sz.rheight())) {
220 return sz;
221 }
222 break;
223 }
225 int orient;
226 if (getIntProperty(kCGImagePropertyOrientation, &orient))
227 return int(exif2Qt(orient));
228 break;
229 }
230 default:
231 break;
232 }
233
234 return QVariant();
235}
236
243
244bool QIIOFHelper::writeImage(const QImage &in, const QString &uti)
245{
246 static const CGDataConsumerCallbacks cgCallbacks = { &cbPutBytes, nullptr };
247
248 if (!q_ptr || !q_ptr->device() || in.isNull())
249 return false;
250
251 QCFType<CGImageRef> cgImage = qt_mac_toCGImage(in);
252 QCFType<CGDataConsumerRef> cgDataConsumer = CGDataConsumerCreate(q_ptr->device(), &cgCallbacks);
253 QCFType<CFStringRef> cfUti = uti.toCFString();
254 QCFType<CGImageDestinationRef> cgImageDest = CGImageDestinationCreateWithDataConsumer(cgDataConsumer, cfUti, 1, nullptr);
255 if (!cgImageDest || !cgImage)
256 return false;
257
258 QCFType<CFNumberRef> cfQuality = nullptr;
259 QCFType<CFNumberRef> cfOrientation = nullptr;
260 const void *dictKeys[2];
261 const void *dictVals[2];
262 int dictSize = 0;
263
265 bool ok = false;
266 int writeQuality = writeOptions.value(QImageIOHandler::Quality).toInt(&ok);
267 // If quality is unset, default to 75%
268 float quality = (ok && writeQuality >= 0 ? (qMin(writeQuality, 100)) : 75) / 100.0f;
269 cfQuality = CFNumberCreate(nullptr, kCFNumberFloatType, &quality);
270 dictKeys[dictSize] = static_cast<const void *>(kCGImageDestinationLossyCompressionQuality);
271 dictVals[dictSize] = static_cast<const void *>(cfQuality);
272 dictSize++;
273 }
276 cfOrientation = CFNumberCreate(nullptr, kCFNumberIntType, &orient);
277 dictKeys[dictSize] = static_cast<const void *>(kCGImagePropertyOrientation);
278 dictVals[dictSize] = static_cast<const void *>(cfOrientation);
279 dictSize++;
280 }
281
282 QCFType<CFDictionaryRef> cfProps = nullptr;
283 if (dictSize)
284 cfProps = CFDictionaryCreate(nullptr, dictKeys, dictVals, dictSize,
285 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
286
287 CGImageDestinationAddImage(cgImageDest, cgImage, cfProps);
288 return CGImageDestinationFinalize(cgImageDest);
289}
290
291}
292
void setOption(QImageIOHandler::ImageOption option, const QVariant &value)
QList< QVariant > writeOptions
QCFType< CGImageSourceRef > cgImageSource
bool writeImage(const QImage &in, const QString &uti)
QIIOFHelper(QImageIOHandler *q)
QCFType< CGDataProviderRef > cgDataProvider
bool getIntProperty(CFStringRef property, int *value)
QVariant imageProperty(QImageIOHandler::ImageOption option)
QCFType< CFDictionaryRef > cfImageDict
static bool writeImage(QImageIOHandler *q_ptr, const QImage &in, const QString &uti)
static QImageIOPlugin::Capabilities systemCapabilities(const QString &uti)
static bool readImage(QImageIOHandler *q_ptr, QImage *out)
\inmodule QtCore \reentrant
Definition qbuffer.h:16
\inmodule QtCore \reentrant
Definition qiodevice.h:34
virtual qint64 pos() const
For random-access devices, this function returns the position that data is written to or read from.
virtual bool isSequential() const
Returns true if this device is sequential; otherwise returns false.
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
virtual bool seek(qint64 pos)
For random-access devices, this function sets the current position to pos, returning true on success,...
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read.
The QImageIOHandler class defines the common image I/O interface for all image formats in Qt.
ImageOption
This enum describes the different options supported by QImageIOHandler.
virtual bool supportsOption(ImageOption option) const
Returns true if the QImageIOHandler supports the option option; otherwise returns false.
QIODevice * device() const
Returns the device currently assigned to the QImageIOHandler.
\inmodule QtGui
Definition qimage.h:37
qsizetype size() const noexcept
Definition qlist.h:397
T value(qsizetype i) const
Definition qlist.h:664
void resize(qsizetype size)
Definition qlist.h:403
\inmodule QtCore
Definition qsize.h:25
constexpr int & rheight() noexcept
Returns a reference to the height.
Definition qsize.h:157
constexpr int & rwidth() noexcept
Returns a reference to the width.
Definition qsize.h:154
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
\inmodule QtCore
Definition qvariant.h:65
int toInt(bool *ok=nullptr) const
Returns the variant as an int if the variant has userType() \l QMetaType::Int, \l QMetaType::Bool,...
static size_t cbPutBytes(void *info, const void *buffer, size_t count)
static size_t cbGetBytes(void *info, void *buffer, size_t count)
static void cbRewind(void *)
static int qt2Exif(QImageIOHandler::Transformations transformation)
static off_t cbSkipForward(void *info, off_t count)
static QImageIOHandler::Transformations exif2Qt(int exifOrientation)
Combined button and popup list for selecting options.
Definition image.cpp:4
QImage qt_mac_toQImage(CGImageRef image)
CGImageRef qt_mac_toCGImage(const QImage &inImage)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
QImage qt_mac_toQImage(CGImageRef image)
QT_BEGIN_NAMESPACE CGImageRef qt_mac_toCGImage(const QImage &qImage)
#define qWarning
Definition qlogging.h:166
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLboolean GLboolean GLboolean b
GLenum GLenum GLsizei count
GLenum GLuint buffer
GLenum GLuint GLenum GLsizei const GLchar * buf
GLfloat GLfloat GLfloat GLfloat h
GLuint res
GLuint in
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint GLenum option
GLenum GLsizei len
unsigned long long quint64
Definition qtypes.h:61
long long qint64
Definition qtypes.h:60
const char property[13]
Definition qwizard.cpp:101
QTextStream out(stdout)
[7]
QHostInfo info
[0]