00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kis_jpeg_converter.h"
00021
00022 #include <stdio.h>
00023
00024 extern "C" {
00025 #include <iccjpeg.h>
00026 }
00027
00028 #include <qfile.h>
00029
00030 #include <kapplication.h>
00031 #include <KoDocumentInfo.h>
00032
00033 #include <kio/netaccess.h>
00034
00035 #include <kis_abstract_colorspace.h>
00036 #include <kis_colorspace_factory_registry.h>
00037 #include <kis_doc.h>
00038 #include <kis_image.h>
00039 #include <kis_iterators_pixel.h>
00040 #include <kis_paint_layer.h>
00041 #include <kis_group_layer.h>
00042 #include <kis_meta_registry.h>
00043 #include <kis_profile.h>
00044
00045 #include <kis_exif_io.h>
00046
00047 extern "C" {
00048 #include <libexif/exif-loader.h>
00049 #include <libexif/exif-utils.h>
00050 }
00051
00052 #define ICC_MARKER (JPEG_APP0 + 2)
00053 #define ICC_OVERHEAD_LEN 14
00054 #define MAX_BYTES_IN_MARKER 65533
00055 #define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
00056
00057 namespace {
00058
00059 J_COLOR_SPACE getColorTypeforColorSpace( KisColorSpace * cs)
00060 {
00061 if ( cs->id() == KisID("GRAYA") || cs->id() == KisID("GRAYA16") )
00062 {
00063 return JCS_GRAYSCALE;
00064 }
00065 if ( cs->id() == KisID("RGBA") || cs->id() == KisID("RGBA16") )
00066 {
00067 return JCS_RGB;
00068 }
00069 if ( cs->id() == KisID("CMYK") || cs->id() == KisID("CMYK16") )
00070 {
00071 return JCS_CMYK;
00072 }
00073 kdDebug(41008) << "Cannot export images in " + cs->id().name() + " yet.\n";
00074 return JCS_UNKNOWN;
00075 }
00076
00077 QString getColorSpaceForColorType(J_COLOR_SPACE color_type) {
00078 kdDebug(41008) << "color_type = " << color_type << endl;
00079 if(color_type == JCS_GRAYSCALE)
00080 {
00081 return "GRAYA";
00082 } else if(color_type == JCS_RGB) {
00083 return "RGBA";
00084 } else if(color_type == JCS_CMYK) {
00085 return "CMYK";
00086 }
00087 return "";
00088 }
00089
00090 }
00091
00092 KisJPEGConverter::KisJPEGConverter(KisDoc *doc, KisUndoAdapter *adapter)
00093 {
00094 m_doc = doc;
00095 m_adapter = adapter;
00096 m_job = 0;
00097 m_stop = false;
00098 }
00099
00100 KisJPEGConverter::~KisJPEGConverter()
00101 {
00102 }
00103
00104 KisImageBuilder_Result KisJPEGConverter::decode(const KURL& uri)
00105 {
00106 struct jpeg_decompress_struct cinfo;
00107 struct jpeg_error_mgr jerr;
00108
00109 cinfo.err = jpeg_std_error(&jerr);
00110 jpeg_create_decompress(&cinfo);
00111
00112
00113 FILE *fp = fopen(QFile::encodeName(uri.path()), "rb");
00114 if (!fp)
00115 {
00116 return (KisImageBuilder_RESULT_NOT_EXIST);
00117 }
00118 jpeg_stdio_src(&cinfo, fp);
00119
00120 jpeg_save_markers (&cinfo, JPEG_COM, 0xFFFF);
00121
00122 for (int m = 0; m < 16; m++)
00123 jpeg_save_markers (&cinfo, JPEG_APP0 + m, 0xFFFF);
00124
00125
00126
00127
00128 jpeg_read_header(&cinfo, true);
00129
00130
00131 jpeg_start_decompress(&cinfo);
00132
00133
00134 QString csName = getColorSpaceForColorType(cinfo.out_color_space);
00135 if(csName.isEmpty()) {
00136 kdDebug(41008) << "unsupported colorspace : " << cinfo.out_color_space << endl;
00137 jpeg_destroy_decompress(&cinfo);
00138 fclose(fp);
00139 return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
00140 }
00141 uchar* profile_data;
00142 uint profile_len;
00143 KisProfile* profile = 0;
00144 QByteArray profile_rawdata;
00145 if( read_icc_profile (&cinfo, &profile_data, &profile_len))
00146 {
00147 profile_rawdata.resize(profile_len);
00148 memcpy(profile_rawdata.data(), profile_data, profile_len);
00149 cmsHPROFILE hProfile = cmsOpenProfileFromMem(profile_data, (DWORD)profile_len);
00150
00151 if (hProfile != (cmsHPROFILE) NULL) {
00152 profile = new KisProfile( profile_rawdata);
00153 Q_CHECK_PTR(profile);
00154 kdDebug(41008) << "profile name: " << profile->productName() << " profile description: " << profile->productDescription() << " information sur le produit: " << profile->productInfo() << endl;
00155 if(!profile->isSuitableForOutput())
00156 {
00157 kdDebug(41008) << "the profile is not suitable for output and therefore cannot be used in krita, we need to convert the image to a standard profile" << endl;
00158 }
00159 }
00160 }
00161
00162
00163 KisColorSpace* cs;
00164 if (profile && profile->isSuitableForOutput())
00165 {
00166 kdDebug(41008) << "image has embedded profile: " << profile -> productName() << "\n";
00167 cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(csName, profile);
00168 }
00169 else
00170 cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName,""),"");
00171
00172 if(cs == 0)
00173 {
00174 kdDebug(41008) << "unknown colorspace" << endl;
00175 jpeg_destroy_decompress(&cinfo);
00176 fclose(fp);
00177 return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
00178 }
00179
00180
00181
00182 cmsHTRANSFORM transform = 0;
00183 if(profile && !profile->isSuitableForOutput())
00184 {
00185 transform = cmsCreateTransform(profile->profile(), cs->colorSpaceType(),
00186 cs->getProfile()->profile() , cs->colorSpaceType(),
00187 INTENT_PERCEPTUAL, 0);
00188 }
00189
00190
00191 if( ! m_img) {
00192 m_img = new KisImage(m_doc->undoAdapter(), cinfo.image_width, cinfo.image_height, cs, "built image");
00193 Q_CHECK_PTR(m_img);
00194 if(profile && !profile->isSuitableForOutput())
00195 {
00196 m_img -> addAnnotation( new KisAnnotation( profile->productName(), "", profile_rawdata) );
00197 }
00198 }
00199
00200 KisPaintLayerSP layer = new KisPaintLayer(m_img, m_img -> nextLayerName(), Q_UINT8_MAX);
00201
00202
00203
00204
00205 JSAMPROW row_pointer = new JSAMPLE[cinfo.image_width*cinfo.num_components];
00206
00207 for (; cinfo.output_scanline < cinfo.image_height;) {
00208 KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, cinfo.output_scanline, cinfo.image_width, true);
00209 jpeg_read_scanlines(&cinfo, &row_pointer, 1);
00210 Q_UINT8 *src = row_pointer;
00211 switch(cinfo.out_color_space)
00212 {
00213 case JCS_GRAYSCALE:
00214 while (!it.isDone()) {
00215 Q_UINT8 *d = it.rawData();
00216 d[0] = *(src++);
00217 if(transform) cmsDoTransform(transform, d, d, 1);
00218 d[1] = Q_UINT8_MAX;
00219 ++it;
00220 }
00221 break;
00222 case JCS_RGB:
00223 while (!it.isDone()) {
00224 Q_UINT8 *d = it.rawData();
00225 d[2] = *(src++);
00226 d[1] = *(src++);
00227 d[0] = *(src++);
00228 if(transform) cmsDoTransform(transform, d, d, 1);
00229 d[3] = Q_UINT8_MAX;
00230 ++it;
00231 }
00232 break;
00233 case JCS_CMYK:
00234 while (!it.isDone()) {
00235 Q_UINT8 *d = it.rawData();
00236 d[0] = Q_UINT8_MAX - *(src++);
00237 d[1] = Q_UINT8_MAX - *(src++);
00238 d[2] = Q_UINT8_MAX - *(src++);
00239 d[3] = Q_UINT8_MAX - *(src++);
00240 if(transform) cmsDoTransform(transform, d, d, 1);
00241 d[4] = Q_UINT8_MAX;
00242 ++it;
00243 }
00244 break;
00245 default:
00246 return KisImageBuilder_RESULT_UNSUPPORTED;
00247 }
00248 }
00249
00250 m_img->addLayer(layer.data(), m_img->rootLayer(), 0);
00251
00252
00253
00254 kdDebug(41008) << "Looking for exif information" << endl;
00255
00256 for (jpeg_saved_marker_ptr marker = cinfo.marker_list; marker != NULL; marker = marker->next) {
00257 kdDebug(41008) << "Marker is " << marker->marker << endl;
00258 if (marker->marker != (JOCTET) (JPEG_APP0 + 1) ||
00259 marker->data_length < 14)
00260 continue;
00261
00262 if (GETJOCTET (marker->data[0]) != (JOCTET) 0x45 ||
00263 GETJOCTET (marker->data[1]) != (JOCTET) 0x78 ||
00264 GETJOCTET (marker->data[2]) != (JOCTET) 0x69 ||
00265 GETJOCTET (marker->data[3]) != (JOCTET) 0x66 ||
00266 GETJOCTET (marker->data[4]) != (JOCTET) 0x00 ||
00267 GETJOCTET (marker->data[5]) != (JOCTET) 0x00)
00268 continue;
00269 kdDebug(41008) << "Found exif information of length : "<< marker->data_length << endl;
00270 KisExifIO exifIO(layer->paintDevice()->exifInfo());
00271 exifIO.readExifFromMem( marker->data , marker->data_length );
00272
00273 ExifValue v;
00274 if( layer->paintDevice()->exifInfo()->getValue("Orientation", v) && v.type() == ExifValue::EXIF_TYPE_SHORT)
00275 {
00276 switch(v.asShort(0))
00277 {
00278 case 2:
00279 layer->paintDevice()->mirrorY();
00280 break;
00281 case 3:
00282 image()->rotate(180, 0);
00283 break;
00284 case 4:
00285 layer->paintDevice()->mirrorX();
00286 break;
00287 case 5:
00288 image()->rotate(90, 0);
00289 layer->paintDevice()->mirrorY();
00290 break;
00291 case 6:
00292 image()->rotate(90, 0);
00293 break;
00294 case 7:
00295 image()->rotate(90, 0);
00296 layer->paintDevice()->mirrorX();
00297 break;
00298 case 8:
00299 image()->rotate(270, 0);
00300 break;
00301 default:
00302 break;
00303 }
00304 v.setValue(0, (Q_UINT16)1);
00305 layer->paintDevice()->exifInfo()->setValue("Orientation", v);
00306 }
00307 break;
00308 }
00309
00310
00311 jpeg_finish_decompress(&cinfo);
00312 jpeg_destroy_decompress(&cinfo);
00313 fclose(fp);
00314 delete row_pointer;
00315 return KisImageBuilder_RESULT_OK;
00316 }
00317
00318
00319
00320 KisImageBuilder_Result KisJPEGConverter::buildImage(const KURL& uri)
00321 {
00322 if (uri.isEmpty())
00323 return KisImageBuilder_RESULT_NO_URI;
00324
00325 if (!KIO::NetAccess::exists(uri, false, qApp -> mainWidget())) {
00326 return KisImageBuilder_RESULT_NOT_EXIST;
00327 }
00328
00329
00330 KisImageBuilder_Result result = KisImageBuilder_RESULT_FAILURE;
00331 QString tmpFile;
00332
00333 if (KIO::NetAccess::download(uri, tmpFile, qApp -> mainWidget())) {
00334 KURL uriTF;
00335 uriTF.setPath( tmpFile );
00336 result = decode(uriTF);
00337 KIO::NetAccess::removeTempFile(tmpFile);
00338 }
00339
00340 return result;
00341 }
00342
00343
00344 KisImageSP KisJPEGConverter::image()
00345 {
00346 return m_img;
00347 }
00348
00349
00350 KisImageBuilder_Result KisJPEGConverter::buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, KisJPEGOptions options, KisExifInfo* exifInfo)
00351 {
00352 if (!layer)
00353 return KisImageBuilder_RESULT_INVALID_ARG;
00354
00355 KisImageSP img = layer -> image();
00356 if (!img)
00357 return KisImageBuilder_RESULT_EMPTY;
00358
00359 if (uri.isEmpty())
00360 return KisImageBuilder_RESULT_NO_URI;
00361
00362 if (!uri.isLocalFile())
00363 return KisImageBuilder_RESULT_NOT_LOCAL;
00364
00365 FILE *fp = fopen(QFile::encodeName(uri.path()), "wb");
00366 if (!fp)
00367 {
00368 return (KisImageBuilder_RESULT_FAILURE);
00369 }
00370 uint height = img->height();
00371 uint width = img->width();
00372
00373 struct jpeg_compress_struct cinfo;
00374 jpeg_create_compress(&cinfo);
00375
00376 struct jpeg_error_mgr jerr;
00377 cinfo.err = jpeg_std_error(&jerr);
00378
00379 jpeg_stdio_dest(&cinfo, fp);
00380
00381 cinfo.image_width = width;
00382 cinfo.image_height = height;
00383 cinfo.input_components = img->colorSpace()->nColorChannels();
00384 J_COLOR_SPACE color_type = getColorTypeforColorSpace(img->colorSpace());
00385 if(color_type == JCS_UNKNOWN)
00386 {
00387 KIO::del(uri);
00388 return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
00389 }
00390 cinfo.in_color_space = color_type;
00391
00392
00393
00394 jpeg_set_defaults(&cinfo);
00395
00396 jpeg_set_quality(&cinfo, options.quality, true);
00397
00398 if(options.progressive)
00399 {
00400 jpeg_simple_progression (&cinfo);
00401 }
00402
00403
00404 jpeg_start_compress(&cinfo, true);
00405
00406 if(exifInfo)
00407 {
00408 kdDebug(41008) << "Trying to save exif information" << endl;
00409 KisExifIO exifIO(exifInfo);
00410 unsigned char* exif_data;
00411 unsigned int exif_size;
00412 exifIO.saveExifToMem( &exif_data, &exif_size);
00413 kdDebug(41008) << "Exif informations size is " << exif_size << endl;
00414 if (exif_size < MAX_DATA_BYTES_IN_MARKER)
00415 {
00416 jpeg_write_marker(&cinfo, JPEG_APP0 + 1, exif_data, exif_size);
00417 } else {
00418 kdDebug(41008) << "exif informations couldn't be saved." << endl;
00419 }
00420 }
00421
00422
00423
00424 vKisAnnotationSP_it it = annotationsStart;
00425 while(it != annotationsEnd) {
00426 if (!(*it) || (*it) -> type() == QString()) {
00427 kdDebug(41008) << "Warning: empty annotation" << endl;
00428 ++it;
00429 continue;
00430 }
00431
00432 kdDebug(41008) << "Trying to store annotation of type " << (*it) -> type() << " of size " << (*it) -> annotation() . size() << endl;
00433
00434 if ((*it) -> type().startsWith("krita_attribute:")) {
00435
00436 kdDebug(41008) << "can't save this annotation : " << (*it) -> type() << endl;
00437 } else {
00438
00439 write_icc_profile(& cinfo, (uchar*)(*it)->annotation().data(), (*it)->annotation().size());
00440 }
00441 ++it;
00442 }
00443
00444
00445
00446
00447 JSAMPROW row_pointer = new JSAMPLE[width*cinfo.input_components];
00448 int color_nb_bits = 8 * layer->paintDevice()->pixelSize() / layer->paintDevice()->nChannels();
00449
00450 for (; cinfo.next_scanline < height;) {
00451 KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, cinfo.next_scanline, width, false);
00452 Q_UINT8 *dst = row_pointer;
00453 switch(color_type)
00454 {
00455 case JCS_GRAYSCALE:
00456 if(color_nb_bits == 16)
00457 {
00458 while (!it.isDone()) {
00459 const Q_UINT16 *d = reinterpret_cast<const Q_UINT16 *>(it.rawData());
00460 *(dst++) = d[0] / Q_UINT8_MAX;
00461 ++it;
00462 }
00463 } else {
00464 while (!it.isDone()) {
00465 const Q_UINT8 *d = it.rawData();
00466 *(dst++) = d[0];
00467 ++it;
00468 }
00469 }
00470 break;
00471 case JCS_RGB:
00472 if(color_nb_bits == 16)
00473 {
00474 while (!it.isDone()) {
00475 const Q_UINT16 *d = reinterpret_cast<const Q_UINT16 *>(it.rawData());
00476 *(dst++) = d[2] / Q_UINT8_MAX;
00477 *(dst++) = d[1] / Q_UINT8_MAX;
00478 *(dst++) = d[0] / Q_UINT8_MAX;
00479 ++it;
00480 }
00481 } else {
00482 while (!it.isDone()) {
00483 const Q_UINT8 *d = it.rawData();
00484 *(dst++) = d[2];
00485 *(dst++) = d[1];
00486 *(dst++) = d[0];
00487 ++it;
00488 }
00489 }
00490 break;
00491 case JCS_CMYK:
00492 if(color_nb_bits == 16)
00493 {
00494 while (!it.isDone()) {
00495 const Q_UINT16 *d = reinterpret_cast<const Q_UINT16 *>(it.rawData());
00496 *(dst++) = Q_UINT8_MAX - d[0] / Q_UINT8_MAX;
00497 *(dst++) = Q_UINT8_MAX - d[1] / Q_UINT8_MAX;
00498 *(dst++) = Q_UINT8_MAX - d[2] / Q_UINT8_MAX;
00499 *(dst++) = Q_UINT8_MAX - d[3] / Q_UINT8_MAX;
00500 ++it;
00501 }
00502 } else {
00503 while (!it.isDone()) {
00504 const Q_UINT8 *d = it.rawData();
00505 *(dst++) = Q_UINT8_MAX - d[0];
00506 *(dst++) = Q_UINT8_MAX - d[1];
00507 *(dst++) = Q_UINT8_MAX - d[2];
00508 *(dst++) = Q_UINT8_MAX - d[3];
00509 ++it;
00510 }
00511 }
00512 break;
00513 default:
00514 KIO::del(uri);
00515 return KisImageBuilder_RESULT_UNSUPPORTED;
00516 }
00517 jpeg_write_scanlines(&cinfo, &row_pointer, 1);
00518 }
00519
00520
00521
00522 jpeg_finish_compress(&cinfo);
00523 fclose(fp);
00524
00525 delete row_pointer;
00526
00527 jpeg_destroy_compress(&cinfo);
00528
00529 return KisImageBuilder_RESULT_OK;
00530 }
00531
00532
00533 void KisJPEGConverter::cancel()
00534 {
00535 m_stop = true;
00536 }
00537
00538 #include "kis_jpeg_converter.moc"
00539