mirror of
https://bitbucket.org/smil3y/katie.git
synced 2025-02-23 18:32:55 +00:00
reimplemnt png handler
based on code I wrote some time ago Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
parent
7b50a8c73b
commit
4a4cac8308
5 changed files with 191 additions and 191 deletions
|
@ -188,11 +188,11 @@ set_package_properties(Threads PROPERTIES
|
|||
TYPE REQUIRED
|
||||
)
|
||||
|
||||
find_package(PNG)
|
||||
set_package_properties(PNG PROPERTIES
|
||||
find_package(SPNG)
|
||||
set_package_properties(SPNG PROPERTIES
|
||||
PURPOSE "PNG format handler"
|
||||
DESCRIPTION "A collection of routines used to create PNG format graphics files"
|
||||
URL "http://www.libpng.org/pub/png/libpng.html"
|
||||
DESCRIPTION "Simple, modern libpng alternative"
|
||||
URL "https://libspng.org/"
|
||||
TYPE REQUIRED
|
||||
)
|
||||
|
||||
|
|
31
cmake/modules/FindSPNG.cmake
Normal file
31
cmake/modules/FindSPNG.cmake
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Try to find SPNG, once done this will define:
|
||||
#
|
||||
# SPNG_FOUND - system has SPNG
|
||||
# SPNG_INCLUDES - the SPNG include directory
|
||||
# SPNG_LIBRARIES - the libraries needed to use SPNG
|
||||
#
|
||||
# Copyright (C) 2023 Ivailo Monev <xakepa10@gmail.com>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
pkg_check_modules(PC_SPNG QUIET spng)
|
||||
|
||||
find_path(SPNG_INCLUDES
|
||||
NAMES spng.h
|
||||
HINTS $ENV{SPNGDIR}/include ${PC_SPNG_INCLUDEDIR}
|
||||
)
|
||||
|
||||
find_library(SPNG_LIBRARIES
|
||||
NAMES spng
|
||||
HINTS $ENV{SPNGDIR}/lib ${PC_SPNG_LIBDIR}
|
||||
)
|
||||
|
||||
find_package_handle_standard_args(SPNG
|
||||
VERSION_VAR PC_SPNG_VERSION
|
||||
REQUIRED_VARS SPNG_LIBRARIES SPNG_INCLUDES
|
||||
)
|
||||
|
||||
mark_as_advanced(SPNG_INCLUDES SPNG_LIBRARIES)
|
|
@ -1,9 +1,9 @@
|
|||
add_definitions(${PNG_DEFINITIONS})
|
||||
# add_definitions()
|
||||
set(EXTRA_GUI_LIBS
|
||||
KtCore
|
||||
${FREETYPE_LIBRARIES}
|
||||
${X11_X11_LIB}
|
||||
${PNG_LIBRARIES}
|
||||
${SPNG_LIBRARIES}
|
||||
${DEFLATE_LIBRARIES}
|
||||
)
|
||||
|
||||
|
@ -200,7 +200,7 @@ include_directories(
|
|||
${CMAKE_BINARY_DIR}/include/QtGui
|
||||
${FREETYPE_INCLUDE_DIRS}
|
||||
${X11_INCLUDE_DIR}
|
||||
${PNG_INCLUDE_DIRS}
|
||||
${SPNG_INCLUDES}
|
||||
${DEFLATE_INCLUDES}
|
||||
)
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Copyright (C) 2016 Ivailo Monev
|
||||
** Copyright (C) 2023 Ivailo Monev
|
||||
**
|
||||
** This file is part of the QtGui module of the Katie Toolkit.
|
||||
**
|
||||
|
@ -23,64 +22,45 @@
|
|||
#include "qiodevice.h"
|
||||
#include "qvariant.h"
|
||||
#include "qimage.h"
|
||||
#include "qimage_p.h"
|
||||
#include "qdrawhelper_p.h"
|
||||
#include "qcorecommon_p.h"
|
||||
#include "qguicommon_p.h"
|
||||
#include "qdebug.h"
|
||||
|
||||
#include <png.h>
|
||||
#include <pngconf.h>
|
||||
#include <spng.h>
|
||||
|
||||
// for reference:
|
||||
// https://www.w3.org/TR/PNG-Chunks.html
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
# define QFILLER_ORDER PNG_FILLER_BEFORE
|
||||
#else
|
||||
# define QFILLER_ORDER PNG_FILLER_AFTER
|
||||
#endif
|
||||
|
||||
/*
|
||||
All PNG files load to the minimal QImage equivalent.
|
||||
|
||||
All QImage formats output to reasonably efficient PNG equivalents.
|
||||
Never to grayscale.
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
|
||||
static void qt_png_warning(png_structp /*png_ptr*/, png_const_charp message)
|
||||
int spng_read_proc(spng_ctx *ctx, void *user, void *dst_src, size_t length)
|
||||
{
|
||||
qWarning("libpng warning: %s", message);
|
||||
}
|
||||
|
||||
static void qt_png_read(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||
{
|
||||
QPngHandler *handler = (QPngHandler *)png_get_io_ptr(png_ptr);
|
||||
|
||||
png_size_t nr = handler->device()->read((char*)data, length);
|
||||
if (nr != length) {
|
||||
png_error(png_ptr, "Read error");
|
||||
// qDebug() << Q_FUNC_INFO << length;
|
||||
Q_UNUSED(ctx);
|
||||
QIODevice* iodevice = static_cast<QIODevice*>(user);
|
||||
char* dst = static_cast<char*>(dst_src);
|
||||
const qint64 result = iodevice->read(dst, length);
|
||||
if (result <= 0) {
|
||||
return SPNG_IO_ERROR;
|
||||
}
|
||||
return SPNG_OK;
|
||||
}
|
||||
|
||||
static void qt_png_write(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||
int spng_write_proc(spng_ctx *ctx, void *user, void *dst_src, size_t length)
|
||||
{
|
||||
QPngHandler *handler = (QPngHandler *)png_get_io_ptr(png_ptr);
|
||||
|
||||
png_size_t nr = handler->device()->write((char*)data, length);
|
||||
if (nr != length) {
|
||||
png_error(png_ptr, "Write error");
|
||||
// qDebug() << Q_FUNC_INFO << length;
|
||||
Q_UNUSED(ctx);
|
||||
QIODevice* iodevice = static_cast<QIODevice*>(user);
|
||||
const char* src = static_cast<char*>(dst_src);
|
||||
const qint64 result = iodevice->write(src, length);
|
||||
if (result <= 0) {
|
||||
return SPNG_IO_ERROR;
|
||||
}
|
||||
return SPNG_OK;
|
||||
}
|
||||
|
||||
static void qt_png_flush(png_structp /* png_ptr */)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QPngHandler::QPngHandler()
|
||||
: m_compression(1)
|
||||
: m_complevel(1)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -100,185 +80,174 @@ bool QPngHandler::canRead() const
|
|||
|
||||
bool QPngHandler::read(QImage *image)
|
||||
{
|
||||
if (!canRead()) {
|
||||
spng_ctx *spngctx = spng_ctx_new(static_cast<spng_ctx_flags>(0));
|
||||
if (Q_UNLIKELY(!spngctx)) {
|
||||
qWarning("QPngHandler::read() Could not create context");
|
||||
return false;
|
||||
}
|
||||
|
||||
png_struct *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
|
||||
if (!png_ptr) {
|
||||
int spngresult = spng_set_png_stream(spngctx, spng_read_proc, device());
|
||||
if (Q_UNLIKELY(spngresult != SPNG_OK)) {
|
||||
qWarning("QPngHandler::read() Could not set stream: %s", spng_strerror(spngresult));
|
||||
spng_ctx_free(spngctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
png_set_error_fn(png_ptr, 0, 0, qt_png_warning);
|
||||
|
||||
png_info *info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr) {
|
||||
png_destroy_read_struct(&png_ptr, 0, 0);
|
||||
struct spng_ihdr spngihdr;
|
||||
::memset(&spngihdr, 0, sizeof(struct spng_ihdr));
|
||||
spngresult = spng_get_ihdr(spngctx, &spngihdr);
|
||||
if (Q_UNLIKELY(spngresult != SPNG_OK)) {
|
||||
qWarning("QPngHandler::read() Could not get IHDR: %s", spng_strerror(spngresult));
|
||||
spng_ctx_free(spngctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
png_info *end_info = png_create_info_struct(png_ptr);
|
||||
if (!end_info) {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
|
||||
*image = QImage(spngihdr.width, spngihdr.height, QImage::Format_ARGB32);
|
||||
if (Q_UNLIKELY(image->isNull())) {
|
||||
qWarning("QPngHandler::read() Could not create image");
|
||||
spng_ctx_free(spngctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
spngresult = spng_decode_image(
|
||||
spngctx,
|
||||
image->bits(), image->byteCount(),
|
||||
SPNG_FMT_RGBA8,
|
||||
SPNG_DECODE_TRNS
|
||||
);
|
||||
if (Q_UNLIKELY(spngresult != SPNG_OK)) {
|
||||
qWarning("QPngHandler::read() Could not decode image: %s", spng_strerror(spngresult));
|
||||
*image = QImage();
|
||||
spng_ctx_free(spngctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
png_set_read_fn(png_ptr, this, qt_png_read);
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
png_uint_32 width = 0;
|
||||
png_uint_32 height = 0;
|
||||
int bit_depth;
|
||||
int color_type;
|
||||
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
|
||||
const int passes = png_set_interlace_handling(png_ptr);
|
||||
|
||||
if (bit_depth == 16) {
|
||||
png_set_strip_16(png_ptr);
|
||||
}
|
||||
|
||||
png_set_expand(png_ptr);
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
|
||||
png_set_gray_to_rgb(png_ptr);
|
||||
} else if (color_type == PNG_COLOR_TYPE_PALETTE) {
|
||||
png_set_palette_to_rgb(png_ptr);
|
||||
}
|
||||
|
||||
QImage::Format format = QImage::Format_ARGB32;
|
||||
// Only add filler if no alpha, or we can get 5 channel data.
|
||||
if (!(color_type & PNG_COLOR_MASK_ALPHA)
|
||||
&& !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
|
||||
png_set_filler(png_ptr, 0xff, QFILLER_ORDER);
|
||||
// We want 4 bytes, but it isn't an alpha channel
|
||||
format = QImage::Format_RGB32;
|
||||
}
|
||||
*image = QImage(width, height, format);
|
||||
if (image->isNull()) {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
png_set_swap_alpha(png_ptr);
|
||||
#endif
|
||||
|
||||
png_read_update_info(png_ptr, info_ptr);
|
||||
|
||||
// Qt==ARGB==Big(ARGB)==Little(BGRA)
|
||||
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
||||
png_set_bgr(png_ptr);
|
||||
#endif
|
||||
|
||||
uchar *data = image->d->data;
|
||||
const int bpl = image->bytesPerLine();
|
||||
for (int p = 0; p < passes; p++) {
|
||||
for (uint y = 0; y < height; y++) {
|
||||
png_read_row(png_ptr, QFAST_SCAN_LINE(data, bpl, y), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
png_read_end(png_ptr, end_info);
|
||||
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
|
||||
*image = image->rgbSwapped();
|
||||
spng_ctx_free(spngctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QPngHandler::write(const QImage &image)
|
||||
{
|
||||
QImage copy = image.convertToFormat(image.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32);
|
||||
const int height = copy.height();
|
||||
const QImage copy = image.convertToFormat(QImage::Format_ARGB32).rgbSwapped();
|
||||
|
||||
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
|
||||
if (!png_ptr) {
|
||||
spng_ctx *spngctx = spng_ctx_new(SPNG_CTX_ENCODER);
|
||||
if (Q_UNLIKELY(!spngctx)) {
|
||||
qWarning("QPngHandler::write() Could not create context");
|
||||
return false;
|
||||
}
|
||||
|
||||
png_set_error_fn(png_ptr, 0, 0, qt_png_warning);
|
||||
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr) {
|
||||
png_destroy_write_struct(&png_ptr, 0);
|
||||
int spngresult = spng_set_png_stream(spngctx, spng_write_proc, device());
|
||||
if (Q_UNLIKELY(spngresult != SPNG_OK)) {
|
||||
qWarning("QPngHandler::write() Could not set stream: %s", spng_strerror(spngresult));
|
||||
spng_ctx_free(spngctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
struct spng_ihdr spngihdr;
|
||||
::memset(&spngihdr, 0, sizeof(struct spng_ihdr));
|
||||
spngihdr.width = copy.width();
|
||||
spngihdr.height = copy.height();
|
||||
spngihdr.bit_depth = 8;
|
||||
spngihdr.color_type = SPNG_COLOR_TYPE_TRUECOLOR_ALPHA;
|
||||
spngihdr.compression_method = 0; // no enum for it
|
||||
spngihdr.filter_method = SPNG_FILTER_NONE;
|
||||
spngihdr.interlace_method = SPNG_INTERLACE_NONE;
|
||||
spngresult = spng_set_ihdr(spngctx, &spngihdr);
|
||||
if (Q_UNLIKELY(spngresult != SPNG_OK)) {
|
||||
qWarning("QPngHandler::write() Could not set IHDR: %s", spng_strerror(spngresult));
|
||||
spng_ctx_free(spngctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
png_set_write_fn(png_ptr, (void*)this, qt_png_write, qt_png_flush);
|
||||
|
||||
int color_type = 0;
|
||||
if (copy.hasAlphaChannel()) {
|
||||
color_type = PNG_COLOR_TYPE_RGB_ALPHA;
|
||||
} else {
|
||||
color_type = PNG_COLOR_TYPE_RGB;
|
||||
spngresult = spng_set_option(spngctx, SPNG_IMG_COMPRESSION_LEVEL, m_complevel);
|
||||
if (Q_UNLIKELY(spngresult != SPNG_OK)) {
|
||||
qWarning("QPngHandler::write() Could not set image compression level: %s", spng_strerror(spngresult));
|
||||
spng_ctx_free(spngctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
png_set_IHDR(png_ptr, info_ptr, copy.width(), height,
|
||||
8, // per channel
|
||||
color_type, 0, 0, 0); // sets #channels
|
||||
|
||||
png_color_8 sig_bit;
|
||||
sig_bit.red = 8;
|
||||
sig_bit.green = 8;
|
||||
sig_bit.blue = 8;
|
||||
sig_bit.alpha = copy.hasAlphaChannel() ? 8 : 0;
|
||||
png_set_sBIT(png_ptr, info_ptr, &sig_bit);
|
||||
png_set_compression_level(png_ptr, m_compression);
|
||||
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
// Swap ARGB to RGBA (normal PNG format) before saving on
|
||||
// BigEndian machines
|
||||
png_set_swap_alpha(png_ptr);
|
||||
#elif Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
||||
// Qt==ARGB==Big(ARGB)==Little(BGRA). But RGB888 is RGB regardless
|
||||
png_set_bgr(png_ptr);
|
||||
#endif
|
||||
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
||||
png_set_packing(png_ptr);
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_RGB) {
|
||||
png_set_filler(png_ptr, 0, QFILLER_ORDER);
|
||||
spngresult = spng_encode_image(
|
||||
spngctx,
|
||||
copy.constBits(), copy.byteCount(),
|
||||
SPNG_FMT_PNG,
|
||||
SPNG_ENCODE_FINALIZE
|
||||
);
|
||||
if (Q_UNLIKELY(spngresult != SPNG_OK)) {
|
||||
qWarning("QPngHandler::write() Could not encode image: %s", spng_strerror(spngresult));
|
||||
spng_ctx_free(spngctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
png_write_row(png_ptr, (png_const_bytep)copy.constScanLine(y));
|
||||
}
|
||||
png_write_end(png_ptr, info_ptr);
|
||||
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
|
||||
spng_ctx_free(spngctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QPngHandler::supportsOption(QImageIOHandler::ImageOption option) const
|
||||
QVariant QPngHandler::option(QImageIOHandler::ImageOption option) const
|
||||
{
|
||||
return (option == QImageIOHandler::CompressionLevel);
|
||||
if (option == QImageIOHandler::Size) {
|
||||
const qint64 devicepos = device()->pos();
|
||||
|
||||
spng_ctx *spngctx = spng_ctx_new(static_cast<spng_ctx_flags>(0));
|
||||
if (Q_UNLIKELY(!spngctx)) {
|
||||
qWarning("QPngHandler::option() Could not create context");
|
||||
return false;
|
||||
}
|
||||
|
||||
int spngresult = spng_set_png_stream(spngctx, spng_read_proc, device());
|
||||
if (Q_UNLIKELY(spngresult != SPNG_OK)) {
|
||||
qWarning("QPngHandler::option() Could not set stream: %s", spng_strerror(spngresult));
|
||||
spng_ctx_free(spngctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct spng_ihdr spngihdr;
|
||||
::memset(&spngihdr, 0, sizeof(struct spng_ihdr));
|
||||
spngresult = spng_get_ihdr(spngctx, &spngihdr);
|
||||
if (Q_UNLIKELY(spngresult != SPNG_OK)) {
|
||||
qWarning("QPngHandler::option() Could not get IHDR: %s", spng_strerror(spngresult));
|
||||
spng_ctx_free(spngctx);
|
||||
device()->seek(devicepos);
|
||||
return false;
|
||||
}
|
||||
|
||||
spng_ctx_free(spngctx);
|
||||
device()->seek(devicepos);
|
||||
return QSize(spngihdr.width, spngihdr.height);
|
||||
} else if (option == QImageIOHandler::CompressionLevel) {
|
||||
return QVariant(m_complevel);
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void QPngHandler::setOption(QImageIOHandler::ImageOption option, const QVariant &value)
|
||||
{
|
||||
if (option == QImageIOHandler::CompressionLevel) {
|
||||
const int newlevel = value.toInt();
|
||||
if (Q_UNLIKELY(newlevel < 0 || newlevel > 9)) {
|
||||
qWarning("QPngHandler::setOption() invalid compression level value");
|
||||
m_compression = 1;
|
||||
const int newcomplevel = value.toInt();
|
||||
if (Q_UNLIKELY(newcomplevel < 0 || newcomplevel > 9)) {
|
||||
qWarning("QPngHandler::setOption() Invalid compression level (%d)", newcomplevel);
|
||||
m_complevel = 1;
|
||||
} else {
|
||||
m_compression = newlevel;
|
||||
m_complevel = newcomplevel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool QPngHandler::supportsOption(QImageIOHandler::ImageOption option) const
|
||||
{
|
||||
switch (option) {
|
||||
case QImageIOHandler::Size:
|
||||
case QImageIOHandler::CompressionLevel: {
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Q_UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray QPngHandler::name() const
|
||||
{
|
||||
return "png";
|
||||
|
@ -287,16 +256,16 @@ QByteArray QPngHandler::name() const
|
|||
bool QPngHandler::canRead(QIODevice *device)
|
||||
{
|
||||
if (Q_UNLIKELY(!device)) {
|
||||
qWarning("QPngHandler::canRead() called with no device");
|
||||
qWarning("QPngHandler::canRead() Called with no device");
|
||||
return false;
|
||||
}
|
||||
|
||||
QSTACKARRAY(char, head, 8);
|
||||
if (device->peek(head, sizeof(head)) != sizeof(head))
|
||||
if (device->peek(head, sizeof(head)) != sizeof(head)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static const uchar pngheader[]
|
||||
= { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
|
||||
static const uchar pngheader[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
|
||||
return (::memcmp(head, pngheader, 8) == 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Copyright (C) 2016 Ivailo Monev
|
||||
** Copyright (C) 2023 Ivailo Monev
|
||||
**
|
||||
** This file is part of the QtGui module of the Katie Toolkit.
|
||||
**
|
||||
|
@ -47,15 +46,16 @@ public:
|
|||
bool read(QImage *image) final;
|
||||
bool write(const QImage &image) final;
|
||||
|
||||
bool supportsOption(QImageIOHandler::ImageOption option) const final;
|
||||
QVariant option(QImageIOHandler::ImageOption option) const final;
|
||||
void setOption(QImageIOHandler::ImageOption option, const QVariant &value) final;
|
||||
bool supportsOption(QImageIOHandler::ImageOption option) const final;
|
||||
|
||||
QByteArray name() const final;
|
||||
|
||||
static bool canRead(QIODevice *device);
|
||||
|
||||
private:
|
||||
int m_compression;
|
||||
int m_complevel;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
Loading…
Add table
Reference in a new issue