42 QIODevice *dev =
static_cast<QIODevice *>(info);
43 qCDebug(lcImageIO) <<
"Skipping" << dev <<
"forward" << count <<
"bytes" ;
45 if (!dev || count <= 0)
48 if (!dev->isSequential()) {
49 const qint64 prevPos = dev->pos();
51 if (!qAddOverflow(prevPos, qint64(count), &newPos))
53 res = dev->pos() - prevPos;
56 qint64 remaining = count;
57 while (remaining > 0) {
58 const qint64 chunk = dev->read(buf, qMin(remaining, qint64(
sizeof(buf))));
65 return qMax(qint64(0), res);
91QImageIOPlugin::Capabilities
QIIOFHelpers::systemCapabilities(
const QString &uti)
93 QImageIOPlugin::Capabilities res;
96 QCFType<CFArrayRef> cfSourceTypes = CGImageSourceCopyTypeIdentifiers();
97 CFIndex len = CFArrayGetCount(cfSourceTypes);
98 if (CFArrayContainsValue(cfSourceTypes, CFRangeMake(0, len), cfUti))
99 res |= QImageIOPlugin::CanRead;
101 QCFType<CFArrayRef> cfDestTypes = CGImageDestinationCopyTypeIdentifiers();
102 len = CFArrayGetCount(cfDestTypes);
103 if (CFArrayContainsValue(cfDestTypes, CFRangeMake(0, len), cfUti))
104 res |= QImageIOPlugin::CanWrite;
130 if (!q_ptr || !q_ptr->device())
133 if (QBuffer *b = qobject_cast<QBuffer *>(q_ptr->device())) {
135 const void *rawData = b->data().constData() + b->pos();
136 cgDataProvider = CGDataProviderCreateWithData(
nullptr, rawData, size_t(b->data().size() - b->pos()),
nullptr);
138 static const CGDataProviderSequentialCallbacks cgCallbacks = {
142 cgDataProvider = CGDataProviderCreateSequential(q_ptr->device(), &cgCallbacks);
145 cgImageSource = CGImageSourceCreateWithDataProvider(cgDataProvider,
nullptr);
148 auto primaryIndex = CGImageSourceGetPrimaryImageIndex(cgImageSource);
149 cfImageDict = CGImageSourceCopyPropertiesAtIndex(cgImageSource, primaryIndex,
nullptr);
152 qCInfo(lcImageIO) <<
"Initialized source" << cgImageSource
153 <<
"with" << CGImageSourceGetCount(cgImageSource) <<
"images"
154 <<
"and primary index" << CGImageSourceGetPrimaryImageIndex(cgImageSource);
156 return (cgImageSource);
165 if (
const int mbLimit = QImageReader::allocationLimit()) {
166 const QSize size = imageProperty(QImageIOHandler::Size).toSize();
167 if (!size.isEmpty()) {
168 qsizetype bpl, total;
169 if (qMulOverflow<qsizetype>(size.width(), 4, &bpl)
170 || qMulOverflow<qsizetype>(bpl, size.height(), &total)
171 || (total >> 20) > qsizetype(mbLimit)) {
172 qCWarning(lcImageIO,
"QIIOFHelper: rejecting image (%dx%d) as it exceeds the "
173 "allocation limit of %d MB", size.width(), size.height(), mbLimit);
179 auto primaryIndex = CGImageSourceGetPrimaryImageIndex(cgImageSource);
180 QCFType<CGImageRef> cgImage = CGImageSourceCreateImageAtIndex(cgImageSource, primaryIndex,
nullptr);
182 qCInfo(lcImageIO) <<
"Read image at index" << primaryIndex
183 <<
"with properties" << cfImageDict <<
"and got" << cgImage;
188 *out = qt_mac_toQImage(cgImage);
193 constexpr int maxDpi =
int(
double(
std::numeric_limits<
int>::max()) * 0.0254);
194 if (getIntProperty(kCGImagePropertyDPIWidth, &dpi) && dpi > 0 && dpi <= maxDpi)
195 out->setDotsPerMeterX(qRound(dpi / 0.0254));
196 if (getIntProperty(kCGImagePropertyDPIHeight, &dpi) && dpi > 0 && dpi <= maxDpi)
197 out->setDotsPerMeterY(qRound(dpi / 0.0254));
221 switch (exifOrientation) {
223 return QImageIOHandler::TransformationNone;
225 return QImageIOHandler::TransformationMirror;
227 return QImageIOHandler::TransformationRotate180;
229 return QImageIOHandler::TransformationFlip;
231 return QImageIOHandler::TransformationFlipAndRotate90;
233 return QImageIOHandler::TransformationRotate90;
235 return QImageIOHandler::TransformationMirrorAndRotate90;
237 return QImageIOHandler::TransformationRotate270;
239 return QImageIOHandler::TransformationNone;
242static int qt2Exif(QImageIOHandler::Transformations transformation)
244 switch (transformation) {
245 case QImageIOHandler::TransformationNone:
247 case QImageIOHandler::TransformationMirror:
249 case QImageIOHandler::TransformationRotate180:
251 case QImageIOHandler::TransformationFlip:
253 case QImageIOHandler::TransformationFlipAndRotate90:
255 case QImageIOHandler::TransformationRotate90:
257 case QImageIOHandler::TransformationMirrorAndRotate90:
259 case QImageIOHandler::TransformationRotate270:
262 qWarning(
"Invalid Qt image transformation");
272 case QImageIOHandler::Size: {
274 if (getIntProperty(kCGImagePropertyPixelWidth, &sz.rwidth())
275 && getIntProperty(kCGImagePropertyPixelHeight, &sz.rheight())) {
280 case QImageIOHandler::ImageTransformation: {
282 if (getIntProperty(kCGImagePropertyOrientation, &orient))
283 return int(exif2Qt(orient));
302 static const CGDataConsumerCallbacks cgCallbacks = { &cbPutBytes,
nullptr };
304 if (!q_ptr || !q_ptr->device() || in.isNull())
307 QCFType<CGImageRef> cgImage = qt_mac_toCGImage(in);
308 QCFType<CGDataConsumerRef> cgDataConsumer = CGDataConsumerCreate(q_ptr->device(), &cgCallbacks);
309 QCFType<CFStringRef> cfUti = uti.toCFString();
310 QCFType<CGImageDestinationRef> cgImageDest = CGImageDestinationCreateWithDataConsumer(cgDataConsumer, cfUti, 1,
nullptr);
311 if (!cgImageDest || !cgImage)
314 QCFType<CFNumberRef> cfQuality =
nullptr;
315 QCFType<CFNumberRef> cfOrientation =
nullptr;
316 const void *dictKeys[2];
317 const void *dictVals[2];
320 if (q_ptr->supportsOption(QImageIOHandler::Quality)) {
322 int writeQuality = writeOptions.value(QImageIOHandler::Quality).toInt(&ok);
324 float quality = (ok && writeQuality >= 0 ? (qMin(writeQuality, 100)) : 75) / 100.0f;
325 cfQuality = CFNumberCreate(
nullptr, kCFNumberFloatType, &quality);
326 dictKeys[dictSize] =
static_cast<
const void *>(kCGImageDestinationLossyCompressionQuality);
327 dictVals[dictSize] =
static_cast<
const void *>(cfQuality);
330 if (q_ptr->supportsOption(QImageIOHandler::ImageTransformation)) {
331 int orient = qt2Exif(
static_cast<QImageIOHandler::Transformation>(writeOptions.value(QImageIOHandler::ImageTransformation).toInt()));
332 cfOrientation = CFNumberCreate(
nullptr, kCFNumberIntType, &orient);
333 dictKeys[dictSize] =
static_cast<
const void *>(kCGImagePropertyOrientation);
334 dictVals[dictSize] =
static_cast<
const void *>(cfOrientation);
338 QCFType<CFDictionaryRef> cfProps =
nullptr;
340 cfProps = CFDictionaryCreate(
nullptr, dictKeys, dictVals, dictSize,
341 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
343 qCInfo(lcImageIO) <<
"Writing" << cgImage <<
"\nwith properties" << cfProps;
345 CGImageDestinationAddImage(cgImageDest, cgImage, cfProps);
346 return CGImageDestinationFinalize(cgImageDest);