mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-23 18:32:49 +00:00
kimgio: fix TIFF images reading and implement write
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
parent
c9e7213de4
commit
b3e9998d8c
4 changed files with 119 additions and 14 deletions
|
@ -27,9 +27,9 @@
|
||||||
* @li WEBP \<read\> \<write\>
|
* @li WEBP \<read\> \<write\>
|
||||||
* @li JPEG \<read\> \<write\>
|
* @li JPEG \<read\> \<write\>
|
||||||
* @li ICO \<read\> \<write\>
|
* @li ICO \<read\> \<write\>
|
||||||
|
* @li TIFF \<read\> \<write\>
|
||||||
* @li JP2 \<read\>
|
* @li JP2 \<read\>
|
||||||
* @li RAW \<read\>
|
* @li RAW \<read\>
|
||||||
* @li TIFF \<read\>
|
|
||||||
*/
|
*/
|
||||||
namespace KImageIO
|
namespace KImageIO
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,9 +6,9 @@ Current formats include:
|
||||||
WEBP <read> <write>
|
WEBP <read> <write>
|
||||||
JPEG <read> <write>
|
JPEG <read> <write>
|
||||||
ICO <read> <write>
|
ICO <read> <write>
|
||||||
|
TIFF <read> <write>
|
||||||
JP2 <read>
|
JP2 <read>
|
||||||
RAW <read>
|
RAW <read>
|
||||||
TIFF <read>
|
|
||||||
|
|
||||||
If you want to contribute plugin for image format and there is no solid
|
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
|
C/C++ library for it (like there is for WebP) then it is unlikely it will be
|
||||||
|
|
125
kimgio/tiff.cpp
125
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)
|
static tmsize_t tiff_write_proc(thandle_t tiffhandle, void* tiffptr, tmsize_t tiffsize)
|
||||||
{
|
{
|
||||||
// dummy
|
QIODevice* device = static_cast<QIODevice*>(tiffhandle);
|
||||||
Q_UNUSED(tiffhandle);
|
return device->write(static_cast<char*>(tiffptr), tiffsize);
|
||||||
Q_UNUSED(tiffptr);
|
|
||||||
Q_UNUSED(tiffsize);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static toff_t tiff_seek_proc(thandle_t tiffhandle, toff_t tiffoffset, int tiffwhence)
|
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
|
// 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];
|
char tifferror[1024];
|
||||||
::memset(tifferror, '\0', sizeof(tifferror));
|
::memset(tifferror, '\0', sizeof(tifferror));
|
||||||
int tiffresult = TIFFRGBAImageOK(tiffclient, tifferror);
|
int tiffresult = TIFFRGBAImageOK(tiffclient, tifferror);
|
||||||
|
@ -230,6 +227,8 @@ bool TIFFHandler::read(QImage *image)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*image = image->rgbSwapped();
|
||||||
|
|
||||||
TIFFClose(tiffclient);
|
TIFFClose(tiffclient);
|
||||||
TIFFSetErrorHandler(s_tifferrorhandler);
|
TIFFSetErrorHandler(s_tifferrorhandler);
|
||||||
TIFFSetWarningHandler(s_tiffwarninghandler);
|
TIFFSetWarningHandler(s_tiffwarninghandler);
|
||||||
|
@ -238,8 +237,110 @@ bool TIFFHandler::read(QImage *image)
|
||||||
|
|
||||||
bool TIFFHandler::write(const QImage &image)
|
bool TIFFHandler::write(const QImage &image)
|
||||||
{
|
{
|
||||||
// this plugin is a read-only kind of plugin
|
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;
|
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
|
QByteArray TIFFHandler::name() const
|
||||||
|
@ -277,15 +378,19 @@ QList<QByteArray> TIFFPlugin::mimeTypes() const
|
||||||
QImageIOPlugin::Capabilities TIFFPlugin::capabilities(QIODevice *device, const QByteArray &format) const
|
QImageIOPlugin::Capabilities TIFFPlugin::capabilities(QIODevice *device, const QByteArray &format) const
|
||||||
{
|
{
|
||||||
if (format == s_tiffpluginformat) {
|
if (format == s_tiffpluginformat) {
|
||||||
return QImageIOPlugin::Capabilities(QImageIOPlugin::CanRead);
|
return QImageIOPlugin::Capabilities(QImageIOPlugin::CanRead | QImageIOPlugin::CanWrite);
|
||||||
}
|
}
|
||||||
if (!device || !device->isOpen()) {
|
if (!device || !device->isOpen()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
QImageIOPlugin::Capabilities cap;
|
||||||
if (device->isReadable() && TIFFHandler::canRead(device)) {
|
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
|
QImageIOHandler *TIFFPlugin::create(QIODevice *device, const QByteArray &format) const
|
||||||
|
|
|
@ -136,7 +136,7 @@ bool WebPHandler::write(const QImage &image)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage image32 = image.convertToFormat(QImage::Format_ARGB32);
|
const QImage image32 = image.convertToFormat(QImage::Format_ARGB32);
|
||||||
|
|
||||||
uint8_t *webpoutput = nullptr;
|
uint8_t *webpoutput = nullptr;
|
||||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||||
|
|
Loading…
Add table
Reference in a new issue