You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
678 lines
25 KiB
678 lines
25 KiB
/*
|
|
* Copyright (c) 2005-2006 Cyrille Berger <cberger@cberger.net>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "kis_tiff_converter.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <config.h>
|
|
#include LCMS_HEADER
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <tdeapplication.h>
|
|
#include <KoDocumentInfo.h>
|
|
|
|
#include <tdeio/netaccess.h>
|
|
|
|
#include <kis_abstract_colorspace.h>
|
|
#include <kis_colorspace_factory_registry.h>
|
|
#include <kis_doc.h>
|
|
#include <kis_image.h>
|
|
#include <kis_iterators_pixel.h>
|
|
#include <kis_layer.h>
|
|
#include <kis_meta_registry.h>
|
|
#include <kis_profile.h>
|
|
#include <kis_group_layer.h>
|
|
#include <kis_paint_layer.h>
|
|
|
|
#include "kis_tiff_reader.h"
|
|
#include "kis_tiff_ycbcr_reader.h"
|
|
#include "kis_tiff_stream.h"
|
|
#include "kis_tiff_writer_visitor.h"
|
|
|
|
namespace {
|
|
|
|
TQString getColorSpaceForColorType(uint16 color_type, uint16 color_nb_bits, TIFF *image, uint16 &nbchannels, uint16 &extrasamplescount, uint8 &destDepth, uint16 sampletype) {
|
|
if(color_type == PHOTOMETRIC_MINISWHITE || color_type == PHOTOMETRIC_MINISBLACK)
|
|
{
|
|
if(nbchannels == 0) nbchannels = 1;
|
|
extrasamplescount = nbchannels - 1; // FIX the extrasamples count in case of
|
|
if(color_nb_bits <= 8)
|
|
{
|
|
destDepth = 8;
|
|
return "GRAYA";
|
|
} else {
|
|
destDepth = 16;
|
|
return "GRAYA16";
|
|
}
|
|
} else if(color_type == PHOTOMETRIC_RGB /*|| color_type == */ ) {
|
|
if(nbchannels == 0) nbchannels = 3;
|
|
extrasamplescount = nbchannels - 3; // FIX the extrasamples count in case of
|
|
if(sampletype == SAMPLEFORMAT_IEEEFP)
|
|
{
|
|
if(color_nb_bits == 16)
|
|
{
|
|
destDepth = 16;
|
|
return "RGBAF16HALF";
|
|
} else if( color_nb_bits == 32) {
|
|
destDepth = 32;
|
|
return "RGBAF32";
|
|
}
|
|
return "";
|
|
} else {
|
|
if(color_nb_bits <= 8)
|
|
{
|
|
destDepth = 8;
|
|
return "RGBA";
|
|
} else {
|
|
destDepth = 16;
|
|
return "RGBA16";
|
|
}
|
|
}
|
|
} else if(color_type == PHOTOMETRIC_YCBCR ) {
|
|
if(nbchannels == 0) nbchannels = 3;
|
|
extrasamplescount = nbchannels - 3; // FIX the extrasamples count in case of
|
|
if(color_nb_bits <= 8)
|
|
{
|
|
destDepth = 8;
|
|
return "YCbCrAU8";
|
|
} else {
|
|
destDepth = 16;
|
|
return "YCbCrAU16";
|
|
}
|
|
} else if(color_type == PHOTOMETRIC_SEPARATED ) {
|
|
if(nbchannels == 0) nbchannels = 4;
|
|
// SEPARATED is in general CMYK but not allways, so we check
|
|
uint16 inkset;
|
|
if((TIFFGetField(image, TIFFTAG_INKSET, &inkset) == 0)){
|
|
kdDebug(41008) << "Image does not define the inkset." << endl;
|
|
inkset = 2;
|
|
}
|
|
if(inkset != INKSET_CMYK)
|
|
{
|
|
kdDebug(41008) << "Unsupported inkset (right now, only CMYK is supported)" << endl;
|
|
char** ink_names;
|
|
uint16 numberofinks;
|
|
if( TIFFGetField(image, TIFFTAG_INKNAMES, &ink_names) && TIFFGetField(image, TIFFTAG_NUMBEROFINKS, &numberofinks) )
|
|
{
|
|
kdDebug(41008) << "Inks are : " << endl;
|
|
for(uint i = 0; i < numberofinks; i++)
|
|
{
|
|
kdDebug(41008) << ink_names[i] << endl;
|
|
}
|
|
} else {
|
|
kdDebug(41008) << "inknames aren't defined !" << endl;
|
|
// To be able to read stupid adobe files, if there are no information about inks and four channels, then it's a CMYK file :
|
|
if( nbchannels - extrasamplescount != 4)
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
if(color_nb_bits <= 8)
|
|
{
|
|
destDepth = 8;
|
|
return "CMYK";
|
|
} else {
|
|
destDepth = 16;
|
|
return "CMYKA16";
|
|
}
|
|
} else if(color_type == PHOTOMETRIC_CIELAB
|
|
#ifdef PHOTOMETRIC_ICCLAB
|
|
|| color_type == PHOTOMETRIC_ICCLAB
|
|
#endif
|
|
) {
|
|
destDepth = 16;
|
|
if(nbchannels == 0) nbchannels = 3;
|
|
extrasamplescount = nbchannels - 3; // FIX the extrasamples count in case of
|
|
return "LABA"; // TODO add support for a 8bit LAB colorspace when it is written
|
|
} else if(color_type == PHOTOMETRIC_PALETTE) {
|
|
destDepth = 16;
|
|
if(nbchannels == 0) nbchannels = 2;
|
|
extrasamplescount = nbchannels - 2; // FIX the extrasamples count in case of
|
|
// <-- we will convert the index image to RGBA16 as the palette is allways on 16bits colors
|
|
return "RGBA16";
|
|
}
|
|
return "";
|
|
}
|
|
}
|
|
|
|
KisTIFFConverter::KisTIFFConverter(KisDoc *doc, KisUndoAdapter *adapter)
|
|
{
|
|
m_doc = doc;
|
|
m_adapter = adapter;
|
|
m_job = 0;
|
|
m_stop = false;
|
|
}
|
|
|
|
KisTIFFConverter::~KisTIFFConverter()
|
|
{
|
|
}
|
|
|
|
KisImageBuilder_Result KisTIFFConverter::decode(const KURL& uri)
|
|
{
|
|
kdDebug(41008) << "Start decoding TIFF File" << endl;
|
|
// Opent the TIFF file
|
|
TIFF *image = 0;
|
|
if((image = TIFFOpen(TQFile::encodeName(uri.path()), "r")) == NULL){
|
|
kdDebug(41008) << "Could not open the file, either it doesn't exist, either it is not a TIFF : " << uri.path() << endl;
|
|
|
|
return (KisImageBuilder_RESULT_BAD_FETCH);
|
|
}
|
|
do {
|
|
kdDebug(41008) << "Read new sub-image" << endl;
|
|
KisImageBuilder_Result result = readTIFFDirectory(image);
|
|
if(result != KisImageBuilder_RESULT_OK){
|
|
return result;
|
|
}
|
|
} while (TIFFReadDirectory(image));
|
|
// Freeing memory
|
|
TIFFClose(image);
|
|
return KisImageBuilder_RESULT_OK;
|
|
}
|
|
|
|
KisImageBuilder_Result KisTIFFConverter::readTIFFDirectory( TIFF* image)
|
|
{
|
|
// Read information about the tiff
|
|
uint32 width, height;
|
|
if(TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &width) == 0){
|
|
kdDebug(41008) << "Image does not define its width" << endl;
|
|
TIFFClose(image);
|
|
return KisImageBuilder_RESULT_INVALID_ARG;
|
|
}
|
|
if(TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height) == 0){
|
|
kdDebug(41008) << "Image does not define its height" << endl;
|
|
TIFFClose(image);
|
|
return KisImageBuilder_RESULT_INVALID_ARG;
|
|
}
|
|
uint16 depth;
|
|
if((TIFFGetField(image, TIFFTAG_BITSPERSAMPLE, &depth) == 0)){
|
|
kdDebug(41008) << "Image does not define its depth" << endl;
|
|
depth = 1;
|
|
}
|
|
uint16 sampletype;
|
|
if((TIFFGetField(image, TIFFTAG_SAMPLEFORMAT, &sampletype) == 0)){
|
|
kdDebug(41008) << "Image does not define its sample type" << endl;
|
|
sampletype = SAMPLEFORMAT_UINT;
|
|
}
|
|
// Determine the number of channels (usefull to know if a file has an alpha or not
|
|
uint16 nbchannels;
|
|
if(TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &nbchannels) == 0){
|
|
kdDebug(41008) << "Image has an undefined number of samples per pixel" << endl;
|
|
nbchannels = 0;
|
|
}
|
|
// Get the number of extrasamples and information about them
|
|
uint16 *sampleinfo, extrasamplescount;
|
|
if(TIFFGetField(image, TIFFTAG_EXTRASAMPLES, &extrasamplescount, &sampleinfo) == 0)
|
|
{
|
|
extrasamplescount = 0;
|
|
}
|
|
// Determine the colorspace
|
|
uint16 color_type;
|
|
if(TIFFGetField(image, TIFFTAG_PHOTOMETRIC, &color_type) == 0){
|
|
kdDebug(41008) << "Image has an undefined photometric interpretation" << endl;
|
|
color_type = PHOTOMETRIC_MINISWHITE;
|
|
}
|
|
uint8 dstDepth;
|
|
TQString csName = getColorSpaceForColorType(color_type, depth, image, nbchannels, extrasamplescount, dstDepth,sampletype);
|
|
if(csName.isEmpty()) {
|
|
kdDebug(41008) << "Image has an unsupported colorspace : " << color_type << " for this depth : "<< depth << endl;
|
|
TIFFClose(image);
|
|
return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
|
|
}
|
|
kdDebug(41008) << "Colorspace is : " << csName << " with a depth of " << depth << " and with a nb of channels of " << nbchannels << endl;
|
|
|
|
// Read image profile
|
|
kdDebug() << "Reading profile" << endl;
|
|
KisProfile* profile = 0;
|
|
DWORD EmbedLen;
|
|
LPBYTE EmbedBuffer;
|
|
|
|
if (TIFFGetField(image, TIFFTAG_ICCPROFILE, &EmbedLen, &EmbedBuffer)) {
|
|
kdDebug(41008) << "Profile found" << endl;
|
|
TQByteArray rawdata;
|
|
rawdata.resize(EmbedLen);
|
|
memcpy(rawdata.data(), EmbedBuffer, EmbedLen);
|
|
profile = new KisProfile(rawdata);
|
|
} else {
|
|
kdDebug(41008) << "No Profile found" << endl;
|
|
}
|
|
|
|
// Retrieve a pointer to the colorspace
|
|
KisColorSpace* cs = 0;
|
|
if (profile && profile->isSuitableForOutput())
|
|
{
|
|
kdDebug(41008) << "image has embedded profile: " << profile -> productName() << "\n";
|
|
cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(csName, profile);
|
|
}
|
|
else
|
|
cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName,""),"");
|
|
|
|
if(cs == 0) {
|
|
kdDebug(41008) << "Colorspace " << csName << " is not available, please check your installation." << endl;
|
|
TIFFClose(image);
|
|
return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
|
|
}
|
|
|
|
// Create the cmsTransform if needed
|
|
cmsHTRANSFORM transform = 0;
|
|
if(profile && !profile->isSuitableForOutput())
|
|
{
|
|
kdDebug(41008) << "The profile can't be used in chalk, need conversion" << endl;
|
|
transform = cmsCreateTransform(profile->profile(), cs->colorSpaceType(),
|
|
cs->getProfile()->profile() , cs->colorSpaceType(),
|
|
INTENT_PERCEPTUAL, 0);
|
|
}
|
|
|
|
|
|
// Check if there is an alpha channel
|
|
int8 alphapos = -1; // <- no alpha
|
|
// Check which extra is alpha if any
|
|
kdDebug(41008) << "There are " << nbchannels << " channels and " << extrasamplescount << " extra channels" << endl;
|
|
if(sampleinfo) // index images don't have any sampleinfo, and therefor sampleinfo == 0
|
|
{
|
|
for(int i = 0; i < extrasamplescount; i ++)
|
|
{
|
|
kdDebug(41008) << i << " " << extrasamplescount << " " << (cs->nColorChannels()) << nbchannels << " " << sampleinfo[i] << endl;
|
|
if(sampleinfo[i] == EXTRASAMPLE_ASSOCALPHA)
|
|
{
|
|
// XXX: dangelo: the color values are already multiplied with
|
|
// the alpha value. This needs to be reversed later (postprocessor?)
|
|
alphapos = i;
|
|
}
|
|
|
|
if (sampleinfo[i] == EXTRASAMPLE_UNASSALPHA)
|
|
{
|
|
// color values are not premultiplied with alpha, and can be used as they are.
|
|
alphapos = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Read META Information
|
|
KoDocumentInfo * info = m_doc->documentInfo();
|
|
KoDocumentInfoAbout * aboutPage = static_cast<KoDocumentInfoAbout *>(info->page( "about" ));
|
|
KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor *>(info->page( "author"));
|
|
char* text;
|
|
if (TIFFGetField(image, TIFFTAG_ARTIST, &text)) {
|
|
authorPage->setFullName(text);
|
|
}
|
|
if (TIFFGetField(image, TIFFTAG_DOCUMENTNAME, &text)) {
|
|
aboutPage->setTitle(text);
|
|
}
|
|
if (TIFFGetField(image,TIFFTAG_IMAGEDESCRIPTION,&text) ) {
|
|
aboutPage->setAbstract( text );
|
|
}
|
|
|
|
|
|
// Get the planar configuration
|
|
uint16 planarconfig;
|
|
if(TIFFGetField(image, TIFFTAG_PLANARCONFIG, &planarconfig) == 0)
|
|
{
|
|
kdDebug(41008) << "Plannar configuration is not define" << endl;
|
|
TIFFClose(image);
|
|
return KisImageBuilder_RESULT_INVALID_ARG;
|
|
}
|
|
// Creating the KisImageSP
|
|
if( ! m_img ) {
|
|
m_img = new KisImage(m_doc->undoAdapter(), width, height, cs, "built image");
|
|
TQ_CHECK_PTR(m_img);
|
|
m_img->blockSignals(true); // Don't send out signals while we're building the image
|
|
if(profile)
|
|
{
|
|
m_img -> addAnnotation( profile->annotation() );
|
|
}
|
|
} else {
|
|
if( m_img->width() < (TQ_INT32)width || m_img->height() < (TQ_INT32)height)
|
|
{
|
|
TQ_UINT32 newwidth = (m_img->width() < (TQ_INT32)width) ? width : m_img->width();
|
|
TQ_UINT32 newheight = (m_img->height() < (TQ_INT32)height) ? height : m_img->height();
|
|
m_img->resize(newwidth, newheight, false);
|
|
}
|
|
}
|
|
KisPaintLayer* layer = new KisPaintLayer(m_img, m_img -> nextLayerName(), TQ_UINT8_MAX);
|
|
tdata_t buf = 0;
|
|
tdata_t* ps_buf = 0; // used only for planar configuration seperated
|
|
TIFFStreamBase* tiffstream;
|
|
|
|
KisTIFFReaderBase* tiffReader = 0;
|
|
|
|
TQ_UINT8 poses[5];
|
|
KisTIFFPostProcessor* postprocessor = 0;
|
|
|
|
// Configure poses
|
|
uint8 nbcolorsamples = nbchannels - extrasamplescount;
|
|
switch(color_type)
|
|
{
|
|
case PHOTOMETRIC_MINISWHITE:
|
|
{
|
|
poses[0] = 0; poses[1] = 1;
|
|
postprocessor = new KisTIFFPostProcessorInvert(nbcolorsamples);
|
|
}
|
|
break;
|
|
case PHOTOMETRIC_MINISBLACK:
|
|
{
|
|
poses[0] = 0; poses[1] = 1;
|
|
postprocessor = new KisTIFFPostProcessor(nbcolorsamples);
|
|
}
|
|
break;
|
|
case PHOTOMETRIC_CIELAB:
|
|
{
|
|
poses[0] = 0; poses[1] = 1; poses[2] = 2; poses[3] = 3;
|
|
postprocessor = new KisTIFFPostProcessorICCLABtoCIELAB(nbcolorsamples);
|
|
}
|
|
break;
|
|
#ifdef PHOTOMETRIC_ICCLAB
|
|
case PHOTOMETRIC_ICCLAB:
|
|
{
|
|
poses[0] = 0; poses[1] = 1; poses[2] = 2; poses[3] = 3;
|
|
postprocessor = new KisTIFFPostProcessor(nbcolorsamples);
|
|
}
|
|
break;
|
|
#endif
|
|
case PHOTOMETRIC_RGB:
|
|
{
|
|
poses[0] = 2; poses[1] = 1; poses[2] = 0; poses[3] = 3;
|
|
postprocessor = new KisTIFFPostProcessor(nbcolorsamples);
|
|
}
|
|
break;
|
|
case PHOTOMETRIC_SEPARATED:
|
|
{
|
|
poses[0] = 0; poses[1] = 1; poses[2] = 2; poses[3] = 3; poses[4] = 4;
|
|
postprocessor = new KisTIFFPostProcessor(nbcolorsamples);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
// Initisalize tiffReader
|
|
uint16 * lineSizeCoeffs = new uint16[nbchannels];
|
|
uint16 vsubsampling = 1;
|
|
uint16 hsubsampling = 1;
|
|
for(uint i = 0; i < nbchannels; i++)
|
|
{
|
|
lineSizeCoeffs[i] = 1;
|
|
}
|
|
if( color_type == PHOTOMETRIC_PALETTE)
|
|
{
|
|
uint16 *red; // No need to free them they are free by libtiff
|
|
uint16 *green;
|
|
uint16 *blue;
|
|
if ((TIFFGetField(image, TIFFTAG_COLORMAP, &red, &green, &blue)) == 0)
|
|
{
|
|
kdDebug(41008) << "Indexed image does not define a palette" << endl;
|
|
TIFFClose(image);
|
|
return KisImageBuilder_RESULT_INVALID_ARG;
|
|
}
|
|
|
|
tiffReader = new KisTIFFReaderFromPalette( layer->paintDevice(), red, green, blue, poses, alphapos, depth, nbcolorsamples, extrasamplescount, transform, postprocessor);
|
|
} else if(color_type == PHOTOMETRIC_YCBCR ) {
|
|
TIFFGetFieldDefaulted( image, TIFFTAG_YCBCRSUBSAMPLING, &hsubsampling, &vsubsampling );
|
|
lineSizeCoeffs[1] = hsubsampling;
|
|
lineSizeCoeffs[2] = hsubsampling;
|
|
uint16 position;
|
|
TIFFGetFieldDefaulted( image, TIFFTAG_YCBCRPOSITIONING, &position );
|
|
if( dstDepth == 8 )
|
|
{
|
|
tiffReader = new KisTIFFYCbCrReaderTarget8Bit(layer->paintDevice(), poses, alphapos, depth, nbcolorsamples, extrasamplescount, transform, postprocessor, hsubsampling, vsubsampling, (KisTIFFYCbCr::Position)position);
|
|
} else if( dstDepth == 16 )
|
|
{
|
|
tiffReader = new KisTIFFYCbCrReaderTarget16Bit( layer->paintDevice(), poses, alphapos, depth, nbcolorsamples, extrasamplescount, transform, postprocessor, hsubsampling, vsubsampling, (KisTIFFYCbCr::Position)position);
|
|
}
|
|
} else if(dstDepth == 8)
|
|
{
|
|
tiffReader = new KisTIFFReaderTarget8bit( layer->paintDevice(), poses, alphapos, depth, nbcolorsamples, extrasamplescount, transform, postprocessor);
|
|
} else if(dstDepth == 16) {
|
|
tiffReader = new KisTIFFReaderTarget16bit( layer->paintDevice(), poses, alphapos, depth, nbcolorsamples, extrasamplescount, transform, postprocessor);
|
|
} else if(dstDepth == 32) {
|
|
tiffReader = new KisTIFFReaderTarget32bit( layer->paintDevice(), poses, alphapos, depth, nbcolorsamples, extrasamplescount, transform, postprocessor);
|
|
}
|
|
|
|
if(TIFFIsTiled(image))
|
|
{
|
|
kdDebug(41008) << "tiled image" << endl;
|
|
uint32 tileWidth, tileHeight;
|
|
uint32 x, y;
|
|
TIFFGetField(image, TIFFTAG_TILEWIDTH, &tileWidth);
|
|
TIFFGetField(image, TIFFTAG_TILELENGTH, &tileHeight);
|
|
uint32 linewidth = (tileWidth * depth * nbchannels) / 8;
|
|
if(planarconfig == PLANARCONFIG_CONTIG)
|
|
{
|
|
buf = _TIFFmalloc(TIFFTileSize(image));
|
|
if(depth < 16)
|
|
{
|
|
tiffstream = new TIFFStreamContigBelow16((uint8*)buf, depth, linewidth);
|
|
} else if(depth < 32)
|
|
{
|
|
tiffstream = new TIFFStreamContigBelow32((uint8*)buf, depth, linewidth);
|
|
} else {
|
|
tiffstream = new TIFFStreamContigAbove32((uint8*)buf, depth, linewidth);
|
|
}
|
|
} else {
|
|
ps_buf = new tdata_t[nbchannels];
|
|
uint32 * lineSizes = new uint32[nbchannels];
|
|
uint16 baseSize = TIFFTileSize(image)/nbchannels;
|
|
for(uint i = 0; i < nbchannels; i++)
|
|
{
|
|
ps_buf[i] = _TIFFmalloc(baseSize);
|
|
lineSizes[i] = baseSize / lineSizeCoeffs[i];
|
|
}
|
|
tiffstream = new TIFFStreamSeperate( (uint8**) ps_buf, nbchannels, depth, lineSizes);
|
|
delete [] lineSizes;
|
|
}
|
|
kdDebug(41008) << linewidth << " " << nbchannels << " " << layer->paintDevice()->colorSpace()->nColorChannels() << endl;
|
|
for (y = 0; y < height; y+= tileHeight)
|
|
{
|
|
for (x = 0; x < width; x += tileWidth)
|
|
{
|
|
kdDebug(41008) << "Reading tile x = " << x << " y = " << y << endl;
|
|
if( planarconfig == PLANARCONFIG_CONTIG )
|
|
{
|
|
TIFFReadTile(image, buf, x, y, 0, (tsample_t) -1);
|
|
} else {
|
|
for(uint i = 0; i < nbchannels; i++)
|
|
{
|
|
TIFFReadTile(image, ps_buf[i], x, y, 0, i);
|
|
}
|
|
}
|
|
uint32 realTileWidth = (x + tileWidth) < width ? tileWidth : width - x;
|
|
for (uint yintile = 0; y + yintile < height && yintile < tileHeight/vsubsampling; ) {
|
|
tiffReader->copyDataToChannels( x, y + yintile , realTileWidth, tiffstream);
|
|
yintile += 1;
|
|
tiffstream->moveToLine( yintile );
|
|
}
|
|
tiffstream->restart();
|
|
}
|
|
}
|
|
} else {
|
|
kdDebug(41008) << "striped image" << endl;
|
|
tsize_t stripsize = TIFFStripSize(image);
|
|
uint32 rowsPerStrip;
|
|
TIFFGetFieldDefaulted(image, TIFFTAG_ROWSPERSTRIP, &rowsPerStrip);
|
|
kdDebug() << rowsPerStrip << " " << height << endl;
|
|
rowsPerStrip = TQMIN(rowsPerStrip, height); // when TIFFNumberOfStrips(image) == 1 it might happen that rowsPerStrip is incorrectly set
|
|
if(planarconfig == PLANARCONFIG_CONTIG)
|
|
{
|
|
buf = _TIFFmalloc(stripsize);
|
|
if(depth < 16)
|
|
{
|
|
tiffstream = new TIFFStreamContigBelow16((uint8*)buf, depth, stripsize/rowsPerStrip);
|
|
} else if(depth < 32)
|
|
{
|
|
tiffstream = new TIFFStreamContigBelow32((uint8*)buf, depth, stripsize/rowsPerStrip);
|
|
} else {
|
|
tiffstream = new TIFFStreamContigAbove32((uint8*)buf, depth, stripsize/rowsPerStrip);
|
|
}
|
|
} else {
|
|
ps_buf = new tdata_t[nbchannels];
|
|
uint32 scanLineSize = stripsize/rowsPerStrip;
|
|
kdDebug(41008) << " scanLineSize for each plan = " << scanLineSize << endl;
|
|
uint32 * lineSizes = new uint32[nbchannels];
|
|
for(uint i = 0; i < nbchannels; i++)
|
|
{
|
|
ps_buf[i] = _TIFFmalloc(stripsize);
|
|
lineSizes[i] = scanLineSize / lineSizeCoeffs[i];
|
|
}
|
|
tiffstream = new TIFFStreamSeperate( (uint8**) ps_buf, nbchannels, depth, lineSizes);
|
|
delete [] lineSizes;
|
|
}
|
|
|
|
kdDebug(41008) << "Scanline size = " << TIFFRasterScanlineSize(image) << " / strip size = " << TIFFStripSize(image) << " / rowsPerStrip = " << rowsPerStrip << " stripsize/rowsPerStrip = " << stripsize/rowsPerStrip << endl;
|
|
uint32 y = 0;
|
|
kdDebug(41008) << " NbOfStrips = " << TIFFNumberOfStrips(image) << " rowsPerStrip = " << rowsPerStrip << " stripsize = " << stripsize << endl;
|
|
for (uint32 strip = 0; y < height; strip++)
|
|
{
|
|
if( planarconfig == PLANARCONFIG_CONTIG )
|
|
{
|
|
TIFFReadEncodedStrip(image, TIFFComputeStrip( image, y, 0 ) , buf, (tsize_t) -1);
|
|
} else {
|
|
for(uint i = 0; i < nbchannels; i++)
|
|
{
|
|
TIFFReadEncodedStrip(image, TIFFComputeStrip( image, y, i ), ps_buf[i], (tsize_t) -1);
|
|
}
|
|
}
|
|
for( uint32 yinstrip = 0 ; yinstrip < rowsPerStrip && y < height ; )
|
|
{
|
|
uint linesread = tiffReader->copyDataToChannels( 0, y, width, tiffstream);
|
|
y += linesread;
|
|
yinstrip += linesread;
|
|
tiffstream->moveToLine( yinstrip );
|
|
}
|
|
tiffstream->restart();
|
|
}
|
|
}
|
|
tiffReader->finalize();
|
|
delete lineSizeCoeffs;
|
|
delete tiffReader;
|
|
delete tiffstream;
|
|
if( planarconfig == PLANARCONFIG_CONTIG )
|
|
{
|
|
_TIFFfree(buf);
|
|
} else {
|
|
for(uint i = 0; i < nbchannels; i++)
|
|
{
|
|
_TIFFfree(ps_buf[i]);
|
|
}
|
|
delete[] ps_buf;
|
|
}
|
|
|
|
m_img->addLayer(layer, m_img->rootLayer(), 0);
|
|
return KisImageBuilder_RESULT_OK;
|
|
}
|
|
|
|
KisImageBuilder_Result KisTIFFConverter::buildImage(const KURL& uri)
|
|
{
|
|
if (uri.isEmpty())
|
|
return KisImageBuilder_RESULT_NO_URI;
|
|
|
|
if (!TDEIO::NetAccess::exists(uri, false, tqApp -> mainWidget())) {
|
|
return KisImageBuilder_RESULT_NOT_EXIST;
|
|
}
|
|
|
|
// We're not set up to handle asynchronous loading at the moment.
|
|
KisImageBuilder_Result result = KisImageBuilder_RESULT_FAILURE;
|
|
TQString tmpFile;
|
|
|
|
if (TDEIO::NetAccess::download(uri, tmpFile, tqApp -> mainWidget())) {
|
|
KURL uriTF;
|
|
uriTF.setPath( tmpFile );
|
|
result = decode(uriTF);
|
|
TDEIO::NetAccess::removeTempFile(tmpFile);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
KisImageSP KisTIFFConverter::image()
|
|
{
|
|
return m_img;
|
|
}
|
|
|
|
|
|
KisImageBuilder_Result KisTIFFConverter::buildFile(const KURL& uri, KisImageSP img, KisTIFFOptions options)
|
|
{
|
|
kdDebug(41008) << "Start writing TIFF File" << endl;
|
|
if (!img)
|
|
return KisImageBuilder_RESULT_EMPTY;
|
|
|
|
if (uri.isEmpty())
|
|
return KisImageBuilder_RESULT_NO_URI;
|
|
|
|
if (!uri.isLocalFile())
|
|
return KisImageBuilder_RESULT_NOT_LOCAL;
|
|
|
|
// Open file for writing
|
|
TIFF *image;
|
|
if((image = TIFFOpen(TQFile::encodeName(uri.path()), "w")) == NULL){
|
|
kdDebug(41008) << "Could not open the file for writting " << uri.path() << endl;
|
|
TIFFClose(image);
|
|
return (KisImageBuilder_RESULT_FAILURE);
|
|
}
|
|
|
|
// Set the document informations
|
|
KoDocumentInfo * info = m_doc->documentInfo();
|
|
KoDocumentInfoAbout * aboutPage = static_cast<KoDocumentInfoAbout *>(info->page( "about" ));
|
|
TQString title = aboutPage->title();
|
|
if(!title.isEmpty())
|
|
{
|
|
TIFFSetField(image, TIFFTAG_DOCUMENTNAME, title.ascii());
|
|
}
|
|
TQString abstract = aboutPage->abstract();
|
|
if(!abstract.isEmpty())
|
|
{
|
|
TIFFSetField(image, TIFFTAG_IMAGEDESCRIPTION, abstract.ascii());
|
|
}
|
|
KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor *>(info->page( "author" ));
|
|
TQString author = authorPage->fullName();
|
|
if(!author.isEmpty())
|
|
{
|
|
TIFFSetField(image, TIFFTAG_ARTIST, author.ascii());
|
|
}
|
|
|
|
KisTIFFWriterVisitor* visitor = new KisTIFFWriterVisitor(image, &options);
|
|
KisGroupLayer* root = dynamic_cast<KisGroupLayer*>(img->rootLayer().data());
|
|
if(root == 0)
|
|
{
|
|
TDEIO::del(uri);
|
|
TIFFClose(image);
|
|
return KisImageBuilder_RESULT_FAILURE;
|
|
}
|
|
if(!visitor->visit( root ))
|
|
{
|
|
TDEIO::del(uri);
|
|
TIFFClose(image);
|
|
return KisImageBuilder_RESULT_FAILURE;
|
|
}
|
|
|
|
TIFFClose(image);
|
|
return KisImageBuilder_RESULT_OK;
|
|
}
|
|
|
|
|
|
void KisTIFFConverter::cancel()
|
|
{
|
|
m_stop = true;
|
|
}
|
|
|
|
#include "kis_tiff_converter.moc"
|