Qt 6.x
The Qt SDK
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// Callbacks for sequential data provider & consumer:
15
16static size_t cbGetBytes(void *info, void *buffer, size_t count)
17{
18 QIODevice *dev = static_cast<QIODevice *>(info);
19 if (!dev || !buffer)
20 return 0;
21 qint64 res = dev->read(static_cast<char *>(buffer), qint64(count));
22 return size_t(qMax(qint64(0), res));
23}
24
25static off_t cbSkipForward(void *info, off_t count)
26{
27 QIODevice *dev = static_cast<QIODevice *>(info);
28 if (!dev || count <= 0)
29 return 0;
30 qint64 res = 0;
31 if (!dev->isSequential()) {
32 qint64 prevPos = dev->pos();
33 dev->seek(prevPos + count);
34 res = dev->pos() - prevPos;
35 } else {
36 char *buf = new char[quint64(count)];
37 res = dev->read(buf, count);
38 delete[] buf;
39 }
40 return qMax(qint64(0), res);
41}
42
43static void cbRewind(void *)
44{
45 // Ignore this; we do not want the Qt device to be rewound after reading the image
46}
47
48static size_t cbPutBytes(void *info, const void *buffer, size_t count)
49{
50 QIODevice *dev = static_cast<QIODevice *>(info);
51 if (!dev || !buffer)
52 return 0;
53 qint64 res = dev->write(static_cast<const char *>(buffer), qint64(count));
54 return size_t(qMax(qint64(0), res));
55}
56
57
58// QImage <-> CGImage conversion functions from QtGui on darwin
59CGImageRef qt_mac_toCGImage(const QImage &qImage);
60QImage qt_mac_toQImage(CGImageRef image);
61
62QImageIOPlugin::Capabilities QIIOFHelpers::systemCapabilities(const QString &uti)
63{
64 QImageIOPlugin::Capabilities res;
65 QCFString cfUti(uti);
66
67 QCFType<CFArrayRef> cfSourceTypes = CGImageSourceCopyTypeIdentifiers();
68 CFIndex len = CFArrayGetCount(cfSourceTypes);
69 if (CFArrayContainsValue(cfSourceTypes, CFRangeMake(0, len), cfUti))
71
72 QCFType<CFArrayRef> cfDestTypes = CGImageDestinationCopyTypeIdentifiers();
73 len = CFArrayGetCount(cfDestTypes);
74 if (CFArrayContainsValue(cfDestTypes, CFRangeMake(0, len), cfUti))
76
77 return res;
78}
79
81{
82 QIIOFHelper h(q_ptr);
83 return h.readImage(out);
84}
85
87{
88 QIIOFHelper h(q_ptr);
89 return h.writeImage(in, uti);
90}
91
93 : q_ptr(q)
94{
95}
96
98{
99 static const CGDataProviderSequentialCallbacks cgCallbacks = { 0, &cbGetBytes, &cbSkipForward, &cbRewind, nullptr };
100
101 if (cgImageSource)
102 return true;
103 if (!q_ptr || !q_ptr->device())
104 return false;
105
106 if (QBuffer *b = qobject_cast<QBuffer *>(q_ptr->device())) {
107 // do direct access to avoid data copy
108 const void *rawData = b->data().constData() + b->pos();
109 cgDataProvider = CGDataProviderCreateWithData(nullptr, rawData, size_t(b->data().size() - b->pos()), nullptr);
110 } else {
111 cgDataProvider = CGDataProviderCreateSequential(q_ptr->device(), &cgCallbacks);
112 }
113
114 cgImageSource = CGImageSourceCreateWithDataProvider(cgDataProvider, nullptr);
115
116 if (cgImageSource)
117 cfImageDict = CGImageSourceCopyPropertiesAtIndex(cgImageSource, 0, nullptr);
118
119 return (cgImageSource);
120}
121
123{
124 if (!out || !initRead())
125 return false;
126
127 QCFType<CGImageRef> cgImage = CGImageSourceCreateImageAtIndex(cgImageSource, 0, nullptr);
128 if (!cgImage)
129 return false;
130
131 *out = qt_mac_toQImage(cgImage);
132 if (out->isNull())
133 return false;
134
135 int dpi = 0;
136 if (getIntProperty(kCGImagePropertyDPIWidth, &dpi))
137 out->setDotsPerMeterX(qRound(dpi / 0.0254f));
138 if (getIntProperty(kCGImagePropertyDPIHeight, &dpi))
139 out->setDotsPerMeterY(qRound(dpi / 0.0254f));
140
141 return true;
142}
143
145{
146 if (!cfImageDict)
147 return false;
148
149 CFNumberRef cfNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(cfImageDict, property));
150 if (cfNumber) {
151 int intVal;
152 if (CFNumberGetValue(cfNumber, kCFNumberIntType, &intVal)) {
153 if (value)
154 *value = intVal;
155 return true;
156 }
157 }
158 return false;
159}
160
161static QImageIOHandler::Transformations exif2Qt(int exifOrientation)
162{
163 switch (exifOrientation) {
164 case 1: // normal
166 case 2: // mirror horizontal
168 case 3: // rotate 180
170 case 4: // mirror vertical
172 case 5: // mirror horizontal and rotate 270 CW
174 case 6: // rotate 90 CW
176 case 7: // mirror horizontal and rotate 90 CW
178 case 8: // rotate 270 CW
180 }
182}
183
184static int qt2Exif(QImageIOHandler::Transformations transformation)
185{
186 switch (transformation) {
188 return 1;
190 return 2;
192 return 3;
194 return 4;
196 return 5;
198 return 6;
200 return 7;
202 return 8;
203 }
204 qWarning("Invalid Qt image transformation");
205 return 1;
206}
207
209{
210 if (!initRead())
211 return QVariant();
212
213 switch (option) {
215 QSize sz;
216 if (getIntProperty(kCGImagePropertyPixelWidth, &sz.rwidth())
217 && getIntProperty(kCGImagePropertyPixelHeight, &sz.rheight())) {
218 return sz;
219 }
220 break;
221 }
223 int orient;
224 if (getIntProperty(kCGImagePropertyOrientation, &orient))
225 return int(exif2Qt(orient));
226 break;
227 }
228 default:
229 break;
230 }
231
232 return QVariant();
233}
234
236{
237 if (writeOptions.size() < option + 1)
240}
241
242bool QIIOFHelper::writeImage(const QImage &in, const QString &uti)
243{
244 static const CGDataConsumerCallbacks cgCallbacks = { &cbPutBytes, nullptr };
245
246 if (!q_ptr || !q_ptr->device() || in.isNull())
247 return false;
248
250 QCFType<CGDataConsumerRef> cgDataConsumer = CGDataConsumerCreate(q_ptr->device(), &cgCallbacks);
251 QCFType<CFStringRef> cfUti = uti.toCFString();
252 QCFType<CGImageDestinationRef> cgImageDest = CGImageDestinationCreateWithDataConsumer(cgDataConsumer, cfUti, 1, nullptr);
253 if (!cgImageDest || !cgImage)
254 return false;
255
256 QCFType<CFNumberRef> cfQuality = nullptr;
257 QCFType<CFNumberRef> cfOrientation = nullptr;
258 const void *dictKeys[2];
259 const void *dictVals[2];
260 int dictSize = 0;
261
263 bool ok = false;
264 int writeQuality = writeOptions.value(QImageIOHandler::Quality).toInt(&ok);
265 // If quality is unset, default to 75%
266 float quality = (ok && writeQuality >= 0 ? (qMin(writeQuality, 100)) : 75) / 100.0f;
267 cfQuality = CFNumberCreate(nullptr, kCFNumberFloatType, &quality);
268 dictKeys[dictSize] = static_cast<const void *>(kCGImageDestinationLossyCompressionQuality);
269 dictVals[dictSize] = static_cast<const void *>(cfQuality);
270 dictSize++;
271 }
274 cfOrientation = CFNumberCreate(nullptr, kCFNumberIntType, &orient);
275 dictKeys[dictSize] = static_cast<const void *>(kCGImagePropertyOrientation);
276 dictVals[dictSize] = static_cast<const void *>(cfOrientation);
277 dictSize++;
278 }
279
280 QCFType<CFDictionaryRef> cfProps = nullptr;
281 if (dictSize)
282 cfProps = CFDictionaryCreate(nullptr, dictKeys, dictVals, dictSize,
283 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
284
285 CGImageDestinationAddImage(cgImageDest, cgImage, cfProps);
286 return CGImageDestinationFinalize(cgImageDest);
287}
288
\inmodule QtCore \reentrant
Definition qbuffer.h:16
QImageIOHandler * q_ptr
QList< QVariant > writeOptions
bool getIntProperty(CFStringRef property, int *value)
QCFType< CGImageSourceRef > cgImageSource
bool writeImage(const QImage &in, const QString &uti)
QVariant imageProperty(QImageIOHandler::ImageOption option)
QCFType< CGDataProviderRef > cgDataProvider
void setOption(QImageIOHandler::ImageOption option, const QVariant &value)
QIIOFHelper(QImageIOHandler *q)
QCFType< CFDictionaryRef > cfImageDict
bool readImage(QImage *out)
static bool readImage(QImageIOHandler *q_ptr, QImage *out)
static bool writeImage(QImageIOHandler *q_ptr, const QImage &in, const QString &uti)
static QImageIOPlugin::Capabilities systemCapabilities(const QString &uti)
\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:386
T value(qsizetype i) const
Definition qlist.h:661
void resize(qsizetype size)
Definition qlist.h:392
\inmodule QtCore
Definition qsize.h:25
constexpr int & rheight() noexcept
Returns a reference to the height.
Definition qsize.h:156
constexpr int & rwidth() noexcept
Returns a reference to the width.
Definition qsize.h:153
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
\inmodule QtCore
Definition qvariant.h:64
int toInt(bool *ok=nullptr) const
Returns the variant as an int if the variant has userType() \l QMetaType::Int, \l QMetaType::Bool,...
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:281
static off_t cbSkipForward(void *info, off_t count)
static void cbRewind(void *)
QImage qt_mac_toQImage(CGImageRef image)
CGImageRef qt_mac_toCGImage(const QImage &qImage)
static QT_BEGIN_NAMESPACE size_t cbGetBytes(void *info, void *buffer, size_t count)
static size_t cbPutBytes(void *info, const void *buffer, size_t count)
static int qt2Exif(QImageIOHandler::Transformations transformation)
static QImageIOHandler::Transformations exif2Qt(int exifOrientation)
static QImageIOHandler::Transformations exif2Qt(int exifOrientation)
#define qWarning
Definition qlogging.h:162
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
GLenum GLsizei len
GLuint in
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint GLenum option
unsigned long long quint64
Definition qtypes.h:56
long long qint64
Definition qtypes.h:55
const char property[13]
Definition qwizard.cpp:101
QFileInfo info(fileName)
[8]
QTextStream out(stdout)
[7]