diff --git a/kdeui/util/kimageio.h b/kdeui/util/kimageio.h index 9c86a733..a4255da2 100644 --- a/kdeui/util/kimageio.h +++ b/kdeui/util/kimageio.h @@ -27,9 +27,9 @@ * @li WEBP \ \ * @li JPEG \ \ * @li ICO \ \ + * @li TIFF \ \ * @li JP2 \ * @li RAW \ - * @li TIFF \ */ namespace KImageIO { diff --git a/kimgio/README b/kimgio/README index 88dbdb4b..55892cfb 100644 --- a/kimgio/README +++ b/kimgio/README @@ -6,9 +6,9 @@ Current formats include: WEBP JPEG ICO +TIFF JP2 RAW -TIFF If you want to contribute plugin for image format and there is no solid C/C++ library for it (like there is for WebP) then it is unlikely it will be diff --git a/kimgio/tiff.cpp b/kimgio/tiff.cpp index 2e877adc..087c612a 100644 --- a/kimgio/tiff.cpp +++ b/kimgio/tiff.cpp @@ -68,11 +68,8 @@ static tmsize_t tiff_read_proc(thandle_t tiffhandle, void* tiffptr, tmsize_t tif static tmsize_t tiff_write_proc(thandle_t tiffhandle, void* tiffptr, tmsize_t tiffsize) { - // dummy - Q_UNUSED(tiffhandle); - Q_UNUSED(tiffptr); - Q_UNUSED(tiffsize); - return 0; + QIODevice* device = static_cast(tiffhandle); + return device->write(static_cast(tiffptr), tiffsize); } static toff_t tiff_seek_proc(thandle_t tiffhandle, toff_t tiffoffset, int tiffwhence) @@ -174,7 +171,7 @@ bool TIFFHandler::read(QImage *image) } // NOTE: TIFFReadRGBA* functions do internal conversion (e.g. YCbCr to RGBA) which does not - // work for all images + // work for all images (see man TIFFReadRGBAImage) char tifferror[1024]; ::memset(tifferror, '\0', sizeof(tifferror)); int tiffresult = TIFFRGBAImageOK(tiffclient, tifferror); @@ -230,6 +227,8 @@ bool TIFFHandler::read(QImage *image) return false; } + *image = image->rgbSwapped(); + TIFFClose(tiffclient); TIFFSetErrorHandler(s_tifferrorhandler); TIFFSetWarningHandler(s_tiffwarninghandler); @@ -238,8 +237,110 @@ bool TIFFHandler::read(QImage *image) bool TIFFHandler::write(const QImage &image) { - // this plugin is a read-only kind of plugin - return false; + s_tifferrorhandler = TIFFSetErrorHandler(tiff_error_handler); + s_tiffwarninghandler = TIFFSetWarningHandler(tiff_warning_handler); + + TIFF* tiffclient = TIFFClientOpen( + "TIFFHandler", "w", + device(), + tiff_read_proc, + tiff_write_proc, + tiff_seek_proc, + tiff_close_proc, + tiff_size_proc, + tiff_mapfile_proc, + tiff_unmapfile_proc + ); + if (!Q_UNLIKELY(tiffclient)) { + kWarning() << "Could not open client"; + TIFFSetErrorHandler(s_tifferrorhandler); + TIFFSetWarningHandler(s_tiffwarninghandler); + return false; + } + + QImage image32 = image.convertToFormat(QImage::Format_ARGB32).rgbSwapped(); + + const int width = image32.width(); + int tiffresult = TIFFSetField(tiffclient, TIFFTAG_IMAGEWIDTH, width); + if (Q_UNLIKELY(tiffresult != 1)) { + kWarning() << "Could not set width field"; + TIFFClose(tiffclient); + TIFFSetErrorHandler(s_tifferrorhandler); + TIFFSetWarningHandler(s_tiffwarninghandler); + return false; + } + + const int height = image32.height(); + tiffresult = TIFFSetField(tiffclient, TIFFTAG_IMAGELENGTH, height); + if (Q_UNLIKELY(tiffresult != 1)) { + kWarning() << "Could not set height field"; + TIFFClose(tiffclient); + TIFFSetErrorHandler(s_tifferrorhandler); + TIFFSetWarningHandler(s_tiffwarninghandler); + return false; + } + + tiffresult = TIFFSetField(tiffclient, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + if (Q_UNLIKELY(tiffresult != 1)) { + kWarning() << "Could not set planar config field"; + TIFFClose(tiffclient); + TIFFSetErrorHandler(s_tifferrorhandler); + TIFFSetWarningHandler(s_tiffwarninghandler); + return false; + } + + tiffresult = TIFFSetField(tiffclient, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + if (Q_UNLIKELY(tiffresult != 1)) { + kWarning() << "Could not set photometric field"; + TIFFClose(tiffclient); + TIFFSetErrorHandler(s_tifferrorhandler); + TIFFSetWarningHandler(s_tiffwarninghandler); + return false; + } + + tiffresult = TIFFSetField(tiffclient, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + if (Q_UNLIKELY(tiffresult != 1)) { + kWarning() << "Could not set compression field"; + TIFFClose(tiffclient); + TIFFSetErrorHandler(s_tifferrorhandler); + TIFFSetWarningHandler(s_tiffwarninghandler); + return false; + } + + tiffresult = TIFFSetField(tiffclient, TIFFTAG_SAMPLESPERPIXEL, 4); + if (Q_UNLIKELY(tiffresult != 1)) { + kWarning() << "Could not set samples per-pixel field"; + TIFFClose(tiffclient); + TIFFSetErrorHandler(s_tifferrorhandler); + TIFFSetWarningHandler(s_tiffwarninghandler); + return false; + } + + tiffresult = TIFFSetField(tiffclient, TIFFTAG_BITSPERSAMPLE, 8); + if (Q_UNLIKELY(tiffresult != 1)) { + kWarning() << "Could not set bits per-pixel field"; + TIFFClose(tiffclient); + TIFFSetErrorHandler(s_tifferrorhandler); + TIFFSetWarningHandler(s_tiffwarninghandler); + return false; + } + + for (int i = 0; i < height; i++) { + uchar* scanline = image32.scanLine(i); + tiffresult = TIFFWriteScanline(tiffclient, scanline, i); + if (Q_UNLIKELY(tiffresult != 1)) { + kWarning() << "Could not write scanline"; + TIFFClose(tiffclient); + TIFFSetErrorHandler(s_tifferrorhandler); + TIFFSetWarningHandler(s_tiffwarninghandler); + return false; + } + } + + TIFFClose(tiffclient); + TIFFSetErrorHandler(s_tifferrorhandler); + TIFFSetWarningHandler(s_tiffwarninghandler); + return true; } QByteArray TIFFHandler::name() const @@ -277,15 +378,19 @@ QList TIFFPlugin::mimeTypes() const QImageIOPlugin::Capabilities TIFFPlugin::capabilities(QIODevice *device, const QByteArray &format) const { if (format == s_tiffpluginformat) { - return QImageIOPlugin::Capabilities(QImageIOPlugin::CanRead); + return QImageIOPlugin::Capabilities(QImageIOPlugin::CanRead | QImageIOPlugin::CanWrite); } if (!device || !device->isOpen()) { return 0; } + QImageIOPlugin::Capabilities cap; if (device->isReadable() && TIFFHandler::canRead(device)) { - return QImageIOPlugin::Capabilities(QImageIOPlugin::CanRead); + cap |= QImageIOPlugin::CanRead; } - return 0; + if (format == s_tiffpluginformat && device->isWritable()) { + cap |= QImageIOPlugin::CanWrite; + } + return cap; } QImageIOHandler *TIFFPlugin::create(QIODevice *device, const QByteArray &format) const diff --git a/kimgio/webp.cpp b/kimgio/webp.cpp index d15ef53b..2e33012e 100644 --- a/kimgio/webp.cpp +++ b/kimgio/webp.cpp @@ -136,7 +136,7 @@ bool WebPHandler::write(const QImage &image) return false; } - QImage image32 = image.convertToFormat(QImage::Format_ARGB32); + const QImage image32 = image.convertToFormat(QImage::Format_ARGB32); uint8_t *webpoutput = nullptr; #if Q_BYTE_ORDER == Q_BIG_ENDIAN