C

Qt Quick Ultralite imagedecoder Example

/****************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Quick Ultralite module. ** ** $QT_BEGIN_LICENSE:COMM$ ** ** 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. ** ** $QT_END_LICENSE$ ** ******************************************************************************/
#include "desktopimagedecoder.h" #include <QBuffer> #include <QImage> #include <QImageReader> #include <platforminterface/log.h> static QImage::Format convertColorFormat(Qul::PixelFormat pixelFormat) { switch (pixelFormat) { case Qul::PixelFormat_ARGB32: return QImage::Format_ARGB32; case Qul::PixelFormat_ARGB32_Premultiplied: return QImage::Format_ARGB32_Premultiplied; case Qul::PixelFormat_RGB32: return QImage::Format_RGB32; case Qul::PixelFormat_RGB888: return QImage::Format_RGB888; case Qul::PixelFormat_RGB16: return QImage::Format_RGB16; case Qul::PixelFormat_Alpha8: return QImage::Format_Alpha8; case Qul::PixelFormat_Alpha1: return QImage::Format_Mono; case Qul::PixelFormat_ARGB4444: // Unsupported? return QImage::Format_Invalid; case Qul::PixelFormat_ARGB4444_Premultiplied: return QImage::Format_ARGB4444_Premultiplied; case Qul::PixelFormat_RGB332: // Unsupported? return QImage::Format_Invalid; case Qul::PixelFormat_RLE_ARGB32: case Qul::PixelFormat_RLE_ARGB32_Premultiplied: case Qul::PixelFormat_RLE_RGB32: case Qul::PixelFormat_RLE_RGB888: return QImage::Format_Invalid; default: return QImage::Format_Invalid; } } DesktopImageDecoder::DesktopImageDecoder() {} DesktopImageDecoder::~DesktopImageDecoder() {} static bool probe(const unsigned char *data, uint32_t size) { // Detect JPG images // FF D8 FF E0 xx xx 4A 46 // FF D8 FF E1 xx xx 45 78 // FF D8 FF E8 xx xx 53 50 if (size < 8) return false; if (data[0] != 0xff || data[1] != 0xd8 || data[2] != 0xff) return false; if (data[3] == 0xe0 && data[6] == 0x4a && data[7] == 0x46) return true; else if (data[3] == 0xe1 && data[6] == 0x45 && data[7] == 0x78) return true; else if (data[3] == 0xe8 && data[6] == 0x53 && data[7] == 0x50) return true; return false; } bool DesktopImageDecoder::imageInformation(RequestDataCallback &callback, int16_t *width, int16_t *height, Qul::PixelFormat *actualPixelFormat, Qul::PixelFormat optimalOpaquePixelFormat, Qul::PixelFormat optimalAlphaPixelFormat) { QUL_UNUSED(optimalOpaquePixelFormat); QUL_UNUSED(optimalAlphaPixelFormat); { unsigned char buffer[8]; if (callback.readData(buffer, 0, sizeof(buffer)) != sizeof(buffer)) return false; if (!probe(buffer, sizeof(buffer))) return false; } uint32_t offset = 0; while (1) { unsigned char marker; do { if (callback.readData(&marker, offset, sizeof(marker)) != sizeof(marker)) return false; offset += sizeof(marker); } while (marker == 0xff); // Ignore start and padding bytes if (marker > 0xd0 && marker <= 0xd8) continue; if (marker == 0xd9) return false; // EOI without finding a size block if (marker == 0x01) // TEM continue; if (marker == 0xc0) { unsigned char buffer[8]; if (callback.readData(buffer, offset, sizeof(buffer)) != sizeof(buffer)) return false; offset += sizeof(buffer); *height = buffer[3]; *height <<= 8; *height += buffer[4]; *width = buffer[5]; *width <<= 8; *width += buffer[6]; #if 0 // In case we need this some time int numColorComponents = buffer[7]; int bitsPerChannel = buffer[2]; Qul::PlatformInterface::log("bpp %d\n", bitsPerChannel * numColorComponents); #endif *actualPixelFormat = Qul::PixelFormat_RGB32; return true; } unsigned char buffer[2]; if (callback.readData(buffer, offset, sizeof(buffer)) != sizeof(buffer)) return false; offset += sizeof(buffer); uint32_t len = buffer[0]; len <<= 8; len += buffer[1]; len -= 2; // The two bytes from the length itself need to be subtracted offset += len; /* Discard data */ } Qul::PlatformInterface::log("insufficient data for detecting image dimensions\n"); return false; } int DesktopImageDecoder::decodeImage(RequestDataCallback &callback, unsigned char *outbuffer, uint32_t outbufferSize, Qul::PixelFormat pixelFormat, uint32_t requiredBytesPerLine) { QBuffer qBuffer; if (callback.rawData()) { qBuffer.setData((const char *) callback.rawData(), callback.totalAvailableDataSize()); } else { QByteArray data; data.fill('\0', callback.totalAvailableDataSize()); if (callback.readData((unsigned char *) (data.data()), 0, data.capacity()) != callback.totalAvailableDataSize()) { Qul::PlatformInterface::log("Insufficient data for read\n"); return -1; } qBuffer.setData(data); } qBuffer.open(QBuffer::ReadOnly); QImageReader imageReader(&qBuffer); QImage image; if (!imageReader.read(&image)) { Qul::PlatformInterface::log(imageReader.errorString().toLocal8Bit().constData()); return -1; } QImage::Format imageFormat = convertColorFormat(pixelFormat); if (imageFormat == QImage::Format_Invalid) { Qul::PlatformInterface::log("Unsupported image format\n"); return -1; } image.convertTo(imageFormat); if (image.bytesPerLine() != requiredBytesPerLine) { Qul::PlatformInterface::log("Resulting scanline length is not expected and conversion is not implemented.\n"); return -1; } const uint32_t datasize = image.size().height() * image.bytesPerLine(); if (datasize > outbufferSize) { Qul::PlatformInterface::log("Outputbuffer has insufficient size of %d, required %d\n", outbufferSize, datasize); return -1; } memcpy(outbuffer, image.constBits(), datasize); return 0; }