20#include "kis_jpeg_converter.h"
30#include <tdeapplication.h>
31#include <tdemessagebox.h>
34#include <KoDocumentInfo.h>
36#include <tdeio/netaccess.h>
38#include <kis_abstract_colorspace.h>
39#include <kis_colorspace_factory_registry.h>
42#include <kis_iterators_pixel.h>
43#include <kis_paint_layer.h>
44#include <kis_group_layer.h>
45#include <kis_meta_registry.h>
46#include <kis_profile.h>
48#include <kis_exif_io.h>
51#include <libexif/exif-loader.h>
52#include <libexif/exif-utils.h>
55#define ICC_MARKER (JPEG_APP0 + 2)
56#define ICC_OVERHEAD_LEN 14
57#define MAX_BYTES_IN_MARKER 65533
58#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
62 J_COLOR_SPACE getColorTypeforColorSpace( KisColorSpace * cs)
64 if ( cs->id() == KisID(
"GRAYA") || cs->id() == KisID(
"GRAYA16") )
68 if ( cs->id() == KisID(
"RGBA") || cs->id() == KisID(
"RGBA16") )
72 if ( cs->id() == KisID(
"CMYK") || cs->id() == KisID(
"CMYK16") )
76 KMessageBox::error(0, i18n(
"Cannot export images in %1.\n").arg(cs->id().name()) ) ;
80 TQString getColorSpaceForColorType(J_COLOR_SPACE color_type) {
81 kdDebug(41008) <<
"color_type = " << color_type << endl;
82 if(color_type == JCS_GRAYSCALE)
85 }
else if(color_type == JCS_RGB) {
87 }
else if(color_type == JCS_CMYK) {
95KisJPEGConverter::KisJPEGConverter(KisDoc *doc, KisUndoAdapter *adapter)
103KisJPEGConverter::~KisJPEGConverter()
107KisImageBuilder_Result KisJPEGConverter::decode(
const KURL& uri)
109 struct jpeg_decompress_struct cinfo;
110 struct jpeg_error_mgr jerr;
112 cinfo.err = jpeg_std_error(&jerr);
113 jpeg_create_decompress(&cinfo);
116 FILE *fp = fopen(TQFile::encodeName(uri.path()),
"rb");
119 return (KisImageBuilder_RESULT_NOT_EXIST);
121 jpeg_stdio_src(&cinfo, fp);
123 jpeg_save_markers (&cinfo, JPEG_COM, 0xFFFF);
125 for (
int m = 0; m < 16; m++)
126 jpeg_save_markers (&cinfo, JPEG_APP0 + m, 0xFFFF);
131 jpeg_read_header(&cinfo,
true);
134 jpeg_start_decompress(&cinfo);
137 TQString csName = getColorSpaceForColorType(cinfo.out_color_space);
138 if(csName.isEmpty()) {
139 kdDebug(41008) <<
"unsupported colorspace : " << cinfo.out_color_space << endl;
140 jpeg_destroy_decompress(&cinfo);
142 return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
146 KisProfile* profile = 0;
147 TQByteArray profile_rawdata;
148 if( read_icc_profile (&cinfo, &profile_data, &profile_len))
150 profile_rawdata.resize(profile_len);
151 memcpy(profile_rawdata.data(), profile_data, profile_len);
152 cmsHPROFILE hProfile = cmsOpenProfileFromMem(profile_data, (DWORD)profile_len);
154 if (hProfile != (cmsHPROFILE) NULL) {
155 profile =
new KisProfile( profile_rawdata);
156 TQ_CHECK_PTR(profile);
157 kdDebug(41008) <<
"profile name: " << profile->productName() <<
" profile description: " << profile->productDescription() <<
" information sur le produit: " << profile->productInfo() << endl;
158 if(!profile->isSuitableForOutput())
160 kdDebug(41008) <<
"the profile is not suitable for output and therefore cannot be used in chalk, we need to convert the image to a standard profile" << endl;
167 if (profile && profile->isSuitableForOutput())
169 kdDebug(41008) <<
"image has embedded profile: " << profile -> productName() <<
"\n";
170 cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(csName, profile);
173 cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName,
""),
"");
177 kdDebug(41008) <<
"unknown colorspace" << endl;
178 jpeg_destroy_decompress(&cinfo);
180 return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
185 cmsHTRANSFORM transform = 0;
186 if(profile && !profile->isSuitableForOutput())
188 transform = cmsCreateTransform(profile->profile(), cs->colorSpaceType(),
189 cs->getProfile()->profile() , cs->colorSpaceType(),
190 INTENT_PERCEPTUAL, 0);
195 m_img =
new KisImage(m_doc->undoAdapter(), cinfo.image_width, cinfo.image_height, cs,
"built image");
197 if(profile && !profile->isSuitableForOutput())
199 m_img -> addAnnotation(
new KisAnnotation( profile->productName(),
"", profile_rawdata) );
203 KisPaintLayerSP layer =
new KisPaintLayer(m_img, m_img -> nextLayerName(), TQ_UINT8_MAX);
208 JSAMPROW row_pointer =
new JSAMPLE[cinfo.image_width *cinfo.num_components];
210 for (; cinfo.output_scanline < cinfo.image_height;) {
211 KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, cinfo.output_scanline, cinfo.image_width,
true);
212 jpeg_read_scanlines(&cinfo, &row_pointer, 1);
213 TQ_UINT8 *src = row_pointer;
214 switch(cinfo.out_color_space)
217 while (!it.isDone()) {
218 TQ_UINT8 *d = it.rawData();
220 if(transform) cmsDoTransform(transform, d, d, 1);
226 while (!it.isDone()) {
227 TQ_UINT8 *d = it.rawData();
231 if(transform) cmsDoTransform(transform, d, d, 1);
237 while (!it.isDone()) {
238 TQ_UINT8 *d = it.rawData();
239 d[0] = TQ_UINT8_MAX - *(src++);
240 d[1] = TQ_UINT8_MAX - *(src++);
241 d[2] = TQ_UINT8_MAX - *(src++);
242 d[3] = TQ_UINT8_MAX - *(src++);
243 if(transform) cmsDoTransform(transform, d, d, 1);
249 return KisImageBuilder_RESULT_UNSUPPORTED;
253 m_img->addLayer(layer.data(), m_img->rootLayer(), 0);
257 kdDebug(41008) <<
"Looking for exif information" << endl;
259 for (jpeg_saved_marker_ptr marker = cinfo.marker_list; marker != NULL; marker = marker->next) {
260 kdDebug(41008) <<
"Marker is " << marker->marker << endl;
261 if (marker->marker != (JOCTET) (JPEG_APP0 + 1) ||
262 marker->data_length < 14)
265 if (GETJOCTET (marker->data[0]) != (JOCTET) 0x45 ||
266 GETJOCTET (marker->data[1]) != (JOCTET) 0x78 ||
267 GETJOCTET (marker->data[2]) != (JOCTET) 0x69 ||
268 GETJOCTET (marker->data[3]) != (JOCTET) 0x66 ||
269 GETJOCTET (marker->data[4]) != (JOCTET) 0x00 ||
270 GETJOCTET (marker->data[5]) != (JOCTET) 0x00)
272 kdDebug(41008) <<
"Found exif information of length : "<< marker->data_length << endl;
273 KisExifIO exifIO(layer->paintDevice()->exifInfo());
274 exifIO.readExifFromMem( marker->data , marker->data_length );
277 if( layer->paintDevice()->exifInfo()->getValue(
"Orientation", v) && v.type() == ExifValue::EXIF_TYPE_SHORT)
282 layer->paintDevice()->mirrorY();
285 image()->rotate(M_PI, 0);
288 layer->paintDevice()->mirrorX();
291 image()->rotate(M_PI/2, 0);
292 layer->paintDevice()->mirrorY();
295 image()->rotate(M_PI/2, 0);
298 image()->rotate(M_PI/2, 0);
299 layer->paintDevice()->mirrorX();
302 image()->rotate(-M_PI/2 + 2*M_PI, 0);
307 v.setValue(0, (TQ_UINT16)1);
308 layer->paintDevice()->exifInfo()->setValue(
"Orientation", v);
314 jpeg_finish_decompress(&cinfo);
315 jpeg_destroy_decompress(&cinfo);
317 delete []row_pointer;
318 return KisImageBuilder_RESULT_OK;
323KisImageBuilder_Result KisJPEGConverter::buildImage(
const KURL& uri)
326 return KisImageBuilder_RESULT_NO_URI;
328 if (!TDEIO::NetAccess::exists(uri,
false, tqApp -> mainWidget())) {
329 return KisImageBuilder_RESULT_NOT_EXIST;
333 KisImageBuilder_Result result = KisImageBuilder_RESULT_FAILURE;
336 if (TDEIO::NetAccess::download(uri, tmpFile, tqApp -> mainWidget())) {
338 uriTF.setPath( tmpFile );
339 result = decode(uriTF);
340 TDEIO::NetAccess::removeTempFile(tmpFile);
347KisImageSP KisJPEGConverter::image()
353KisImageBuilder_Result KisJPEGConverter::buildFile(
const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, KisJPEGOptions options, KisExifInfo* exifInfo)
356 return KisImageBuilder_RESULT_INVALID_ARG;
358 KisImageSP img = layer -> image();
360 return KisImageBuilder_RESULT_EMPTY;
363 return KisImageBuilder_RESULT_NO_URI;
365 if (!uri.isLocalFile())
366 return KisImageBuilder_RESULT_NOT_LOCAL;
368 FILE *fp = fopen(TQFile::encodeName(uri.path()),
"wb");
371 return (KisImageBuilder_RESULT_FAILURE);
373 uint height = img->height();
374 uint width = img->width();
376 struct jpeg_compress_struct cinfo;
377 jpeg_create_compress(&cinfo);
379 struct jpeg_error_mgr jerr;
380 cinfo.err = jpeg_std_error(&jerr);
382 jpeg_stdio_dest(&cinfo, fp);
384 cinfo.image_width = width;
385 cinfo.image_height = height;
386 cinfo.input_components = img->colorSpace()->nColorChannels();
387 J_COLOR_SPACE color_type = getColorTypeforColorSpace(img->colorSpace());
388 if(color_type == JCS_UNKNOWN)
391 return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
393 cinfo.in_color_space = color_type;
397 jpeg_set_defaults(&cinfo);
399 jpeg_set_quality(&cinfo, options.quality,
true);
401 if(options.progressive)
403 jpeg_simple_progression (&cinfo);
407 jpeg_start_compress(&cinfo,
true);
411 kdDebug(41008) <<
"Trying to save exif information" << endl;
412 KisExifIO exifIO(exifInfo);
413 unsigned char* exif_data;
414 unsigned int exif_size;
415 exifIO.saveExifToMem( &exif_data, &exif_size);
416 kdDebug(41008) <<
"Exif informations size is " << exif_size << endl;
417 if (exif_size < MAX_DATA_BYTES_IN_MARKER)
419 jpeg_write_marker(&cinfo, JPEG_APP0 + 1, exif_data, exif_size);
421 kdDebug(41008) <<
"exif informations couldn't be saved." << endl;
427 vKisAnnotationSP_it it = annotationsStart;
428 while(it != annotationsEnd) {
429 if (!(*it) || (*it) -> type() == TQString()) {
430 kdDebug(41008) <<
"Warning: empty annotation" << endl;
435 kdDebug(41008) <<
"Trying to store annotation of type " << (*it) -> type() <<
" of size " << (*it) -> annotation() . size() << endl;
437 if ((*it) -> type().startsWith(
"chalk_attribute:")) {
439 kdDebug(41008) <<
"can't save this annotation : " << (*it) -> type() << endl;
442 write_icc_profile(& cinfo, (uchar*)(*it)->annotation().data(), (*it)->annotation().size());
450 JSAMPROW row_pointer =
new JSAMPLE[width*cinfo.input_components];
451 int color_nb_bits = 8 * layer->paintDevice()->pixelSize() / layer->paintDevice()->nChannels();
453 for (; cinfo.next_scanline < height;) {
454 KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, cinfo.next_scanline, width,
false);
455 TQ_UINT8 *dst = row_pointer;
459 if(color_nb_bits == 16)
461 while (!it.isDone()) {
462 const TQ_UINT16 *d =
reinterpret_cast<const TQ_UINT16 *
>(it.rawData());
463 *(dst++) = d[0] / TQ_UINT8_MAX;
467 while (!it.isDone()) {
468 const TQ_UINT8 *d = it.rawData();
475 if(color_nb_bits == 16)
477 while (!it.isDone()) {
478 const TQ_UINT16 *d =
reinterpret_cast<const TQ_UINT16 *
>(it.rawData());
479 *(dst++) = d[2] / TQ_UINT8_MAX;
480 *(dst++) = d[1] / TQ_UINT8_MAX;
481 *(dst++) = d[0] / TQ_UINT8_MAX;
485 while (!it.isDone()) {
486 const TQ_UINT8 *d = it.rawData();
495 if(color_nb_bits == 16)
497 while (!it.isDone()) {
498 const TQ_UINT16 *d =
reinterpret_cast<const TQ_UINT16 *
>(it.rawData());
499 *(dst++) = TQ_UINT8_MAX - d[0] / TQ_UINT8_MAX;
500 *(dst++) = TQ_UINT8_MAX - d[1] / TQ_UINT8_MAX;
501 *(dst++) = TQ_UINT8_MAX - d[2] / TQ_UINT8_MAX;
502 *(dst++) = TQ_UINT8_MAX - d[3] / TQ_UINT8_MAX;
506 while (!it.isDone()) {
507 const TQ_UINT8 *d = it.rawData();
508 *(dst++) = TQ_UINT8_MAX - d[0];
509 *(dst++) = TQ_UINT8_MAX - d[1];
510 *(dst++) = TQ_UINT8_MAX - d[2];
511 *(dst++) = TQ_UINT8_MAX - d[3];
518 return KisImageBuilder_RESULT_UNSUPPORTED;
520 jpeg_write_scanlines(&cinfo, &row_pointer, 1);
525 jpeg_finish_compress(&cinfo);
528 delete [] row_pointer;
530 jpeg_destroy_compress(&cinfo);
532 return KisImageBuilder_RESULT_OK;
536void KisJPEGConverter::cancel()
541#include "kis_jpeg_converter.moc"