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 <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) /* JPEG marker code for ICC */
00056 #define ICC_OVERHEAD_LEN  14    /* size of non-profile data in APP2 */
00057 #define MAX_BYTES_IN_MARKER  65533  /* maximum data len of a JPEG marker */
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("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()) ) ;
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     // open the file
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     /* Save APP0..APP15 markers */
00125     for (int m = 0; m < 16; m++)
00126         jpeg_save_markers (&cinfo, JPEG_APP0 + m, 0xFFFF);
00127 
00128     
00129 //     setup_read_icc_profile(&cinfo);
00130     // read header
00131     jpeg_read_header(&cinfo, true);
00132     
00133     // start reading
00134     jpeg_start_decompress(&cinfo);
00135     
00136     // Get the colorspace
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; // TODO: in ko2 popup a selection menu to inform the user
00161             }
00162         }
00163     }
00164     
00165     // Retrieve a pointer to the colorspace
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     // Create the cmsTransform if needed 
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     // Creating the KisImageSP
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     // Read exif information if any
00206     
00207     // Read data
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     // Read exif informations
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; /* Exif data is in an APP1 marker of at least 14 octets */
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; /* no Exif header */
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         // Interpret orientation tag
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(180, 0);
00286                     break;
00287                 case 4:
00288                     layer->paintDevice()->mirrorX();
00289                     break;
00290                 case 5:
00291                     image()->rotate(90, 0);
00292                     layer->paintDevice()->mirrorY();
00293                     break;
00294                 case 6:
00295                     image()->rotate(90, 0);
00296                     break;
00297                 case 7:
00298                     image()->rotate(90, 0);
00299                     layer->paintDevice()->mirrorX();
00300                     break;
00301                 case 8:
00302                     image()->rotate(270, 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     // Finish decompression
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     // We're not set up to handle asynchronous loading at the moment.
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     // Open file for writing
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     // Initialize structure
00376     struct jpeg_compress_struct cinfo;
00377     jpeg_create_compress(&cinfo);
00378     // Initialize error output
00379     struct jpeg_error_mgr jerr;
00380     cinfo.err = jpeg_std_error(&jerr);
00381     // Initialize output stream
00382     jpeg_stdio_dest(&cinfo, fp);
00383     
00384     cinfo.image_width = width;  // image width and height, in pixels
00385     cinfo.image_height = height;
00386     cinfo.input_components = img->colorSpace()->nColorChannels(); // number of color channels per pixel */
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;   // colorspace of input image
00394 
00395     
00396     // Set default compression parameters
00397     jpeg_set_defaults(&cinfo);
00398     // Customize them
00399     jpeg_set_quality(&cinfo, options.quality, true);
00400     
00401     if(options.progressive)
00402     {
00403         jpeg_simple_progression (&cinfo);
00404     }
00405     
00406     // Start compression
00407     jpeg_start_compress(&cinfo, true);
00408     // Save exif information if any available
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     // Save annotation
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:")) { // Attribute
00438             // FIXME
00439             kdDebug(41008) << "can't save this annotation : " << (*it) -> type() << endl;
00440         } else { // Profile
00441             //char* name = new char[(*it)->type().length()+1];
00442             write_icc_profile(& cinfo, (uchar*)(*it)->annotation().data(), (*it)->annotation().size());
00443         }
00444         ++it;
00445     }
00446 
00447     
00448     // Write data information
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     // Writting is over
00525     jpeg_finish_compress(&cinfo);
00526     fclose(fp);
00527     
00528     delete row_pointer;
00529     // Free memory
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 
KDE Home | KDE Accessibility Home | Description of Access Keys