00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kis_tiff_writer_visitor.h"
00021
00022 #include <kmessagebox.h>
00023 #include <klocale.h>
00024
00025 #include <kis_annotation.h>
00026 #include <kis_colorspace.h>
00027 #include <kis_group_layer.h>
00028 #include <kis_image.h>
00029 #include <kis_paint_layer.h>
00030 #include <kis_types.h>
00031
00032 #include "kis_tiff_converter.h"
00033
00034 namespace {
00035 bool writeColorSpaceInformation( TIFF* image, KisColorSpace * cs, uint16& color_type )
00036 {
00037 if ( cs->id() == KisID("GRAYA") || cs->id() == KisID("GRAYA16") )
00038 {
00039 color_type = PHOTOMETRIC_MINISBLACK;
00040 return true;
00041 }
00042 if ( cs->id() == KisID("RGBA") || cs->id() == KisID("RGBA16") )
00043 {
00044 color_type = PHOTOMETRIC_RGB;
00045 return true;
00046 }
00047 if ( cs->id() == KisID("CMYK") || cs->id() == KisID("CMYKA16") )
00048 {
00049 color_type = PHOTOMETRIC_SEPARATED;
00050 TIFFSetField(image, TIFFTAG_INKSET, INKSET_CMYK);
00051 return true;
00052 }
00053 if ( cs->id() == KisID("LABA") )
00054 {
00055 color_type = PHOTOMETRIC_CIELAB;
00056 return true;
00057 }
00058
00059 KMessageBox::error(0, i18n("The selected image format does not support the colorspace of the image (%1)\nPlease choose another format or convert to a different colorspace").arg(cs->id().name()) ) ;
00060 return false;
00061
00062 }
00063 }
00064
00065 KisTIFFWriterVisitor::KisTIFFWriterVisitor(TIFF*img, KisTIFFOptions* options) : m_image(img), m_options(options)
00066 {
00067 }
00068
00069 KisTIFFWriterVisitor::~KisTIFFWriterVisitor()
00070 {
00071 }
00072
00073 bool KisTIFFWriterVisitor::saveAlpha() { return m_options->alpha; }
00074
00075 bool KisTIFFWriterVisitor::copyDataToStrips( KisHLineIterator it, tdata_t buff, uint8 depth, uint8 nbcolorssamples, Q_UINT8* poses)
00076 {
00077 if(depth == 16)
00078 {
00079 Q_UINT16 *dst = reinterpret_cast<Q_UINT16 *>(buff);
00080 while (!it.isDone()) {
00081 const Q_UINT16 *d = reinterpret_cast<const Q_UINT16 *>(it.rawData());
00082 int i;
00083 for(i = 0; i < nbcolorssamples; i++)
00084 {
00085 *(dst++) = d[poses[i]];
00086 }
00087 if(saveAlpha()) *(dst++) = d[poses[i]];
00088 ++it;
00089 }
00090 return true;
00091 } else if(depth == 8) {
00092 Q_UINT8 *dst = reinterpret_cast<Q_UINT8 *>(buff);
00093 while (!it.isDone()) {
00094 const Q_UINT8 *d = it.rawData();
00095 int i;
00096 for(i = 0; i < nbcolorssamples; i++)
00097 {
00098 *(dst++) = d[poses[i]];
00099 }
00100 if(saveAlpha()) *(dst++) = d[poses[i]];
00101 ++it;
00102 }
00103 return true;
00104 }
00105 return false;
00106 }
00107
00108
00109 bool KisTIFFWriterVisitor::visit(KisPaintLayer *layer)
00110 {
00111 kdDebug(41008) << "visiting on paint layer " << layer->name() << "\n";
00112 KisPaintDeviceSP pd = layer->paintDevice();
00113
00114 int depth = 8 * pd->pixelSize() / pd->nChannels();
00115 TIFFSetField(image(), TIFFTAG_BITSPERSAMPLE, depth);
00116
00117 if(saveAlpha())
00118 {
00119 TIFFSetField(image(), TIFFTAG_SAMPLESPERPIXEL, pd->nChannels());
00120 uint16 sampleinfo[1] = { EXTRASAMPLE_UNASSALPHA };
00121 TIFFSetField(image(), TIFFTAG_EXTRASAMPLES, 1, sampleinfo);
00122 } else {
00123 TIFFSetField(image(), TIFFTAG_SAMPLESPERPIXEL, pd->nChannels() - 1);
00124 TIFFSetField(image(), TIFFTAG_EXTRASAMPLES, 0);
00125 }
00126
00127 uint16 color_type;
00128 if(!writeColorSpaceInformation(image(), pd->colorSpace(), color_type))
00129 {
00130 return false;
00131 }
00132 TIFFSetField(image(), TIFFTAG_PHOTOMETRIC, color_type);
00133 TIFFSetField(image(), TIFFTAG_IMAGEWIDTH, layer->image()->width());
00134 TIFFSetField(image(), TIFFTAG_IMAGELENGTH, layer->image()->height());
00135
00136
00137 TIFFSetField(image(), TIFFTAG_COMPRESSION, m_options->compressionType);
00138 TIFFSetField(image(), TIFFTAG_FAXMODE, m_options->faxMode);
00139 TIFFSetField(image(), TIFFTAG_JPEGQUALITY, m_options->jpegQuality);
00140 TIFFSetField(image(), TIFFTAG_ZIPQUALITY, m_options->deflateCompress);
00141 TIFFSetField(image(), TIFFTAG_PIXARLOGQUALITY, m_options->pixarLogCompress);
00142
00143
00144 TIFFSetField(image(), TIFFTAG_PREDICTOR, m_options->predictor);
00145
00146
00147 TIFFSetField(image(), TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
00148
00149 TIFFSetField(image(), TIFFTAG_ROWSPERSTRIP, 8);
00150
00151
00152 KisProfile* profile = pd->colorSpace()->getProfile();
00153 if(profile)
00154 {
00155 QByteArray ba = profile->annotation()->annotation();
00156 TIFFSetField(image(), TIFFTAG_ICCPROFILE, ba.size(),ba.data());
00157 }
00158 tsize_t stripsize = TIFFStripSize(image());
00159 tdata_t buff = _TIFFmalloc(stripsize);
00160 Q_INT32 height = layer->image()->height();
00161 Q_INT32 width = layer->image()->width();
00162 bool r = true;
00163 for (int y = 0; y < height; y++) {
00164 KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, y, width, false);
00165 switch(color_type)
00166 {
00167 case PHOTOMETRIC_MINISBLACK:
00168 {
00169 Q_UINT8 poses[]={ 0,1 };
00170 r = copyDataToStrips(it, buff, depth, 1, poses);
00171 }
00172 break;
00173 case PHOTOMETRIC_RGB:
00174 {
00175 Q_UINT8 poses[]={ 2, 1, 0, 3};
00176 r = copyDataToStrips(it, buff, depth, 3, poses);
00177 }
00178 break;
00179 case PHOTOMETRIC_SEPARATED:
00180 {
00181 Q_UINT8 poses[]={ 0, 1, 2, 3, 4 };
00182 r = copyDataToStrips(it, buff, depth, 4, poses);
00183 }
00184 break;
00185 case PHOTOMETRIC_CIELAB:
00186 {
00187 Q_UINT8 poses[]={ 0, 1, 2, 3 };
00188 r = copyDataToStrips(it, buff, depth, 3, poses);
00189 }
00190 break;
00191 return false;
00192 }
00193 if(!r) return false;
00194 TIFFWriteScanline(image(), buff, y, (tsample_t) -1);
00195 }
00196 _TIFFfree(buff);
00197 TIFFWriteDirectory(image());
00198 return true;
00199 }
00200 bool KisTIFFWriterVisitor::visit(KisGroupLayer *layer)
00201 {
00202 kdDebug(41008) << "Visiting on grouplayer " << layer->name() << "\n";
00203 KisLayerSP child = layer->firstChild();
00204 while (child) {
00205 child->accept(*this);
00206 child = child->nextSibling();
00207 }
00208 return true;
00209 }
00210
00211 bool KisTIFFWriterVisitor::visit(KisPartLayer *)
00212 {
00213 return true;
00214 }