filters

kis_jpeg_converter.cc

00001 /*
00002  *  Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
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) /* JPEG marker code for ICC */
00053 #define ICC_OVERHEAD_LEN  14    /* size of non-profile data in APP2 */
00054 #define MAX_BYTES_IN_MARKER  65533  /* maximum data len of a JPEG marker */
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     // open the file
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     /* Save APP0..APP15 markers */
00122     for (int m = 0; m < 16; m++)
00123         jpeg_save_markers (&cinfo, JPEG_APP0 + m, 0xFFFF);
00124 
00125     
00126 //     setup_read_icc_profile(&cinfo);
00127     // read header
00128     jpeg_read_header(&cinfo, true);
00129     
00130     // start reading
00131     jpeg_start_decompress(&cinfo);
00132     
00133     // Get the colorspace
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; // TODO: in ko2 popup a selection menu to inform the user
00158             }
00159         }
00160     }
00161     
00162     // Retrieve a pointer to the colorspace
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     // Create the cmsTransform if needed 
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     // Creating the KisImageSP
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     // Read exif information if any
00203     
00204     // Read data
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     // Read exif informations
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; /* Exif data is in an APP1 marker of at least 14 octets */
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; /* no Exif header */
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         // Interpret orientation tag
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     // Finish decompression
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     // We're not set up to handle asynchronous loading at the moment.
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     // Open file for writing
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     // Initialize structure
00373     struct jpeg_compress_struct cinfo;
00374     jpeg_create_compress(&cinfo);
00375     // Initialize error output
00376     struct jpeg_error_mgr jerr;
00377     cinfo.err = jpeg_std_error(&jerr);
00378     // Initialize output stream
00379     jpeg_stdio_dest(&cinfo, fp);
00380     
00381     cinfo.image_width = width;  // image width and height, in pixels
00382     cinfo.image_height = height;
00383     cinfo.input_components = img->colorSpace()->nColorChannels(); // number of color channels per pixel */
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;   // colorspace of input image
00391 
00392     
00393     // Set default compression parameters
00394     jpeg_set_defaults(&cinfo);
00395     // Customize them
00396     jpeg_set_quality(&cinfo, options.quality, true);
00397     
00398     if(options.progressive)
00399     {
00400         jpeg_simple_progression (&cinfo);
00401     }
00402     
00403     // Start compression
00404     jpeg_start_compress(&cinfo, true);
00405     // Save exif information if any available
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     // Save annotation
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:")) { // Attribute
00435             // FIXME
00436             kdDebug(41008) << "can't save this annotation : " << (*it) -> type() << endl;
00437         } else { // Profile
00438             //char* name = new char[(*it)->type().length()+1];
00439             write_icc_profile(& cinfo, (uchar*)(*it)->annotation().data(), (*it)->annotation().size());
00440         }
00441         ++it;
00442     }
00443 
00444     
00445     // Write data information
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     // Writting is over
00522     jpeg_finish_compress(&cinfo);
00523     fclose(fp);
00524     
00525     delete row_pointer;
00526     // Free memory
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 
KDE Home | KDE Accessibility Home | Description of Access Keys