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