File indexing completed on 2025-01-26 04:10:56

0001 /*
0002  *  SPDX-FileCopyrightText: 2005 Cyrille Berger <cberger@cberger.net>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 #include "kis_jpeg_converter.h"
0007 
0008 #include <stdio.h>
0009 #include <stdint.h>
0010 
0011 #include <KoConfig.h>
0012 #ifdef HAVE_LCMS2
0013 #   include <lcms2.h>
0014 #else
0015 #   include <lcms.h>
0016 #endif
0017 
0018 extern "C" {
0019 #include <iccjpeg.h>
0020 }
0021 
0022 #include <exiv2/jpgimage.hpp>
0023 #include <exiv2/version.hpp>
0024 #if EXIV2_TEST_VERSION(0,28,0)
0025 #include <exiv2/photoshop.hpp>
0026 #endif
0027 
0028 #include <QFile>
0029 #include <QBuffer>
0030 #include <QApplication>
0031 
0032 #include <klocalizedstring.h>
0033 #include <QFileInfo>
0034 
0035 #include <KoDocumentInfo.h>
0036 #include <KoColorSpace.h>
0037 #include <KoColorSpaceRegistry.h>
0038 #include <KoColorProfile.h>
0039 #include <KoColor.h>
0040 #include <KoUnit.h>
0041 #include "KoColorModelStandardIds.h"
0042 
0043 #include <KisDocument.h>
0044 #include <kis_group_layer.h>
0045 #include <kis_image.h>
0046 #include <kis_iterator_ng.h>
0047 #include <kis_jpeg_destination.h>
0048 #include <kis_jpeg_source.h>
0049 #include <kis_meta_data_backend_registry.h>
0050 #include <kis_meta_data_entry.h>
0051 #include <kis_meta_data_store.h>
0052 #include <kis_meta_data_value.h>
0053 #include <kis_paint_device.h>
0054 #include <kis_paint_layer.h>
0055 #include <kis_painter.h>
0056 #include <kis_transaction.h>
0057 #include <kis_transform_worker.h>
0058 
0059 #define ICC_MARKER  (JPEG_APP0 + 2) /* JPEG marker code for ICC */
0060 #define ICC_OVERHEAD_LEN  14    /* size of non-profile data in APP2 */
0061 #define MAX_BYTES_IN_MARKER  65533  /* maximum data len of a JPEG marker */
0062 #define MAX_DATA_BYTES_IN_MARKER  (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
0063 
0064 const char photoshopMarker[] = "Photoshop 3.0\0";
0065 //const char photoshopBimId_[] = "8BIM";
0066 const uint16_t photoshopIptc = 0x0404;
0067 const char xmpMarker[] = "http://ns.adobe.com/xap/1.0/\0";
0068 const QByteArray photoshopIptc_((char*)&photoshopIptc, 2);
0069 
0070 namespace
0071 {
0072 
0073 void jpegErrorExit (j_common_ptr cinfo)
0074 {
0075     char jpegLastErrorMsg[JMSG_LENGTH_MAX];
0076 
0077     ( *( cinfo->err->format_message ) ) ( cinfo, jpegLastErrorMsg );
0078 
0079     throw std::runtime_error(jpegLastErrorMsg);
0080 }
0081 
0082 J_COLOR_SPACE getColorTypeforColorSpace(const KoColorSpace * cs)
0083 {
0084     if (KoID(cs->id()) == KoID("GRAYA") || cs->id() == "GRAYAU16" || cs->id() == "GRAYA16") {
0085         return JCS_GRAYSCALE;
0086     }
0087     if (KoID(cs->id()) == KoID("RGBA") || KoID(cs->id()) == KoID("RGBA16")) {
0088         return JCS_RGB;
0089     }
0090     if (KoID(cs->id()) == KoID("CMYK") || KoID(cs->id()) == KoID("CMYKAU16")) {
0091         return JCS_CMYK;
0092     }
0093     return JCS_UNKNOWN;
0094 }
0095 
0096 QString getColorSpaceModelForColorType(J_COLOR_SPACE color_type)
0097 {
0098     dbgFile << "color_type =" << color_type;
0099     if (color_type == JCS_GRAYSCALE) {
0100         return GrayAColorModelID.id();
0101     } else if (color_type == JCS_RGB) {
0102         return RGBAColorModelID.id();
0103     } else if (color_type == JCS_CMYK) {
0104         return CMYKAColorModelID.id();
0105     }
0106     return "";
0107 }
0108 
0109 }
0110 
0111 struct KisJPEGConverter::Private
0112 {
0113     Private(KisDocument *doc, bool batchMode)
0114         : doc(doc),
0115           stop(false),
0116           batchMode(batchMode)
0117     {}
0118 
0119     KisImageSP image;
0120     KisDocument *doc;
0121     bool stop;
0122     bool batchMode;
0123 };
0124 
0125 KisJPEGConverter::KisJPEGConverter(KisDocument *doc, bool batchMode)
0126     : m_d(new Private(doc, batchMode))
0127 {
0128 }
0129 
0130 KisJPEGConverter::~KisJPEGConverter()
0131 {
0132 }
0133 
0134 KisImportExportErrorCode KisJPEGConverter::decode(QIODevice *io)
0135 {
0136     struct jpeg_decompress_struct cinfo;
0137     struct jpeg_error_mgr jerr;
0138 
0139     cinfo.err = jpeg_std_error(&jerr);
0140     jerr.error_exit = jpegErrorExit;
0141 
0142     try {
0143         jpeg_create_decompress(&cinfo);
0144 
0145         KisJPEGSource::setSource(&cinfo, io);
0146 
0147         jpeg_save_markers(&cinfo, JPEG_COM, 0xFFFF);
0148         /* Save APP0..APP15 markers */
0149         for (int m = 0; m < 16; m++)
0150             jpeg_save_markers(&cinfo, JPEG_APP0 + m, 0xFFFF);
0151 
0152 
0153         //     setup_read_icc_profile(&cinfo);
0154         // read header
0155         jpeg_read_header(&cinfo, (boolean)true);
0156 
0157         // start reading
0158         jpeg_start_decompress(&cinfo);
0159 
0160         // Get the colorspace
0161         QString modelId = getColorSpaceModelForColorType(cinfo.out_color_space);
0162         if (modelId.isEmpty()) {
0163             dbgFile << "unsupported colorspace :" << cinfo.out_color_space;
0164             jpeg_destroy_decompress(&cinfo);
0165             return ImportExportCodes::FormatColorSpaceUnsupported;
0166         }
0167 
0168         uchar* profile_data = 0;
0169         uint profile_len = 0;
0170         const KoColorProfile* profile = 0;
0171         QByteArray profile_rawdata;
0172         if (read_icc_profile(&cinfo, &profile_data, &profile_len)) {
0173             profile_rawdata.resize(profile_len);
0174             memcpy(profile_rawdata.data(), profile_data, profile_len);
0175             cmsHPROFILE hProfile = cmsOpenProfileFromMem(profile_data, profile_len);
0176 
0177             if (hProfile != (cmsHPROFILE) 0) {
0178                 profile = KoColorSpaceRegistry::instance()->createColorProfile(modelId, Integer8BitsColorDepthID.id(), profile_rawdata);
0179                 Q_CHECK_PTR(profile);
0180                 dbgFile <<"profile name:" << profile->name() <<" product information:" << profile->info();
0181                 if (!profile->isSuitableForOutput()) {
0182                     dbgFile << "the profile is not suitable for output and therefore cannot be used in krita, we need to convert the image to a standard profile"; // TODO: in ko2 popup a selection menu to inform the user
0183                 }
0184             }
0185 
0186             free(profile_data);
0187         }
0188 
0189         const QString colorSpaceId =
0190             KoColorSpaceRegistry::instance()->colorSpaceId(modelId, Integer8BitsColorDepthID.id());
0191 
0192         // Check that the profile is used by the color space
0193         if (profile && !KoColorSpaceRegistry::instance()->profileIsCompatible(profile, colorSpaceId)) {
0194             warnFile << "The profile " << profile->name() << " is not compatible with the color space model " << modelId;
0195             profile = 0;
0196         }
0197 
0198         // Retrieve a pointer to the colorspace
0199         const KoColorSpace* cs;
0200         if (profile && profile->isSuitableForOutput()) {
0201             dbgFile << "image has embedded profile:" << profile -> name() << "";
0202             cs = KoColorSpaceRegistry::instance()->colorSpace(modelId, Integer8BitsColorDepthID.id(), profile);
0203         } else
0204             cs = KoColorSpaceRegistry::instance()->colorSpace(modelId, Integer8BitsColorDepthID.id(), "");
0205 
0206         if (cs == 0) {
0207             dbgFile << "unknown colorspace";
0208             jpeg_destroy_decompress(&cinfo);
0209             return ImportExportCodes::FormatColorSpaceUnsupported;
0210         }
0211         // TODO fixit
0212         // Create the cmsTransform if needed
0213 
0214         KoColorTransformation* transform = 0;
0215         if (profile && !profile->isSuitableForOutput()) {
0216             transform = KoColorSpaceRegistry::instance()->colorSpace(modelId, Integer8BitsColorDepthID.id(), profile)->createColorConverter(cs, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags());
0217         }
0218         // Apparently an invalid transform was created from the profile. See bug https://bugs.kde.org/show_bug.cgi?id=255451.
0219         // After 2.3: warn the user!
0220         if (transform && !transform->isValid()) {
0221             delete transform;
0222             transform = 0;
0223         }
0224 
0225         // Creating the KisImageSP
0226         if (!m_d->image) {
0227             m_d->image = new KisImage(m_d->doc->createUndoStore(),  cinfo.image_width,  cinfo.image_height, cs, "built image");
0228             Q_CHECK_PTR(m_d->image);
0229         }
0230 
0231         // Set resolution
0232         double xres = 72, yres = 72;
0233         if (cinfo.density_unit == 1) {
0234             xres = cinfo.X_density;
0235             yres = cinfo.Y_density;
0236         } else if (cinfo.density_unit == 2) {
0237             xres = cinfo.X_density * 2.54;
0238             yres = cinfo.Y_density * 2.54;
0239         }
0240         if (xres < 72) {
0241             xres = 72;
0242         }
0243         if (yres < 72) {
0244             yres = 72;
0245         }
0246         m_d->image->setResolution(POINT_TO_INCH(xres), POINT_TO_INCH(yres));   // It is the "invert" macro because we convert from pointer-per-inch to points
0247 
0248         // Create layer
0249         KisPaintLayerSP layer = KisPaintLayerSP(new KisPaintLayer(m_d->image.data(), m_d->image -> nextLayerName(), quint8_MAX));
0250 
0251         // Read data
0252         JSAMPROW row_pointer = new JSAMPLE[cinfo.image_width*cinfo.num_components];
0253 
0254         for (; cinfo.output_scanline < cinfo.image_height;) {
0255             KisHLineIteratorSP it = layer->paintDevice()->createHLineIteratorNG(0, cinfo.output_scanline, cinfo.image_width);
0256             jpeg_read_scanlines(&cinfo, &row_pointer, 1);
0257             quint8 *src = row_pointer;
0258             switch (cinfo.out_color_space) {
0259             case JCS_GRAYSCALE:
0260                 do {
0261                     quint8 *d = it->rawData();
0262                     d[0] = *(src++);
0263                     if (transform) transform->transform(d, d, 1);
0264                     d[1] = quint8_MAX;
0265 
0266                 } while (it->nextPixel());
0267                 break;
0268             case JCS_RGB:
0269                 do {
0270                     quint8 *d = it->rawData();
0271                     d[2] = *(src++);
0272                     d[1] = *(src++);
0273                     d[0] = *(src++);
0274                     if (transform) transform->transform(d, d, 1);
0275                     d[3] = quint8_MAX;
0276 
0277                 } while (it->nextPixel());
0278                 break;
0279             case JCS_CMYK:
0280                 do {
0281                     quint8 *d = it->rawData();
0282                     d[0] = quint8_MAX - *(src++);
0283                     d[1] = quint8_MAX - *(src++);
0284                     d[2] = quint8_MAX - *(src++);
0285                     d[3] = quint8_MAX - *(src++);
0286                     if (transform) transform->transform(d, d, 1);
0287                     d[4] = quint8_MAX;
0288 
0289                 } while (it->nextPixel());
0290                 break;
0291             default:
0292                 return ImportExportCodes::FormatFeaturesUnsupported;
0293             }
0294         }
0295 
0296         m_d->image->addNode(KisNodeSP(layer.data()), m_d->image->rootLayer().data());
0297 
0298         // Read exif information
0299 
0300         dbgFile << "Looking for exif information";
0301 
0302         for (jpeg_saved_marker_ptr marker = cinfo.marker_list; marker != 0; marker = marker->next) {
0303             dbgFile << "Marker is" << marker->marker;
0304             if (marker->marker != (JOCTET)(JPEG_APP0 + 1)
0305                     || marker->data_length < 14) {
0306                 continue; /* Exif data is in an APP1 marker of at least 14 octets */
0307             }
0308 
0309             if (GETJOCTET(marker->data[0]) != (JOCTET) 0x45 ||
0310                     GETJOCTET(marker->data[1]) != (JOCTET) 0x78 ||
0311                     GETJOCTET(marker->data[2]) != (JOCTET) 0x69 ||
0312                     GETJOCTET(marker->data[3]) != (JOCTET) 0x66 ||
0313                     GETJOCTET(marker->data[4]) != (JOCTET) 0x00 ||
0314                     GETJOCTET(marker->data[5]) != (JOCTET) 0x00)
0315                 continue; /* no Exif header */
0316 
0317             dbgFile << "Found exif information of length :" << marker->data_length;
0318             KisMetaData::IOBackend *exifIO = KisMetadataBackendRegistry::instance()->value("exif");
0319             Q_ASSERT(exifIO);
0320             QByteArray byteArray((const char*)marker->data + 6, marker->data_length - 6);
0321             QBuffer buf(&byteArray);
0322             exifIO->loadFrom(layer->metaData(), &buf);
0323             // Interpret orientation tag
0324             if (layer->metaData()->containsEntry("http://ns.adobe.com/tiff/1.0/", "Orientation")) {
0325                 KisMetaData::Entry& entry = layer->metaData()->getEntry("http://ns.adobe.com/tiff/1.0/", "Orientation");
0326                 if (entry.value().type() == KisMetaData::Value::Variant) {
0327                     switch (entry.value().asVariant().toInt()) {
0328                     case 2:
0329                         KisTransformWorker::mirrorX(layer->paintDevice());
0330                         break;
0331                     case 3:
0332                         image()->rotateImage(M_PI);
0333                         break;
0334                     case 4:
0335                         KisTransformWorker::mirrorY(layer->paintDevice());
0336                         break;
0337                     case 5:
0338                         image()->rotateImage(M_PI / 2);
0339                         KisTransformWorker::mirrorY(layer->paintDevice());
0340                         break;
0341                     case 6:
0342                         image()->rotateImage(M_PI / 2);
0343                         break;
0344                     case 7:
0345                         image()->rotateImage(M_PI / 2);
0346                         KisTransformWorker::mirrorX(layer->paintDevice());
0347                         break;
0348                     case 8:
0349                         image()->rotateImage(-M_PI / 2 + M_PI*2);
0350                         break;
0351                     default:
0352                         break;
0353                     }
0354                 }
0355                 entry.value().setVariant(1);
0356             }
0357             break;
0358         }
0359 
0360         dbgFile << "Looking for IPTC information";
0361 
0362         for (jpeg_saved_marker_ptr marker = cinfo.marker_list; marker != 0; marker = marker->next) {
0363             dbgFile << "Marker is" << marker->marker;
0364             if (marker->marker != (JOCTET)(JPEG_APP0 + 13) ||  marker->data_length < 14) {
0365                 continue; /* IPTC data is in an APP13 marker of at least 16 octets */
0366             }
0367             if (memcmp(marker->data, photoshopMarker, 14) != 0) {
0368                 for (int i = 0; i < 14; i++) {
0369                     dbgFile << (int)(*(marker->data + i)) << "" << (int)(photoshopMarker[i]);
0370                 }
0371                 dbgFile << "No photoshop marker";
0372                 continue; /* No IPTC Header */
0373             }
0374 
0375             dbgFile << "Found Photoshop information of length :" << marker->data_length;
0376             KisMetaData::IOBackend *iptcIO = KisMetadataBackendRegistry::instance()->value("iptc");
0377             Q_ASSERT(iptcIO);
0378             const Exiv2::byte *record = 0;
0379             uint32_t sizeIptc = 0;
0380             uint32_t sizeHdr = 0;
0381             // Find actual Iptc data within the APP13 segment
0382             if (!Exiv2::Photoshop::locateIptcIrb((Exiv2::byte*)(marker->data + 14),
0383 #if EXIV2_TEST_VERSION(0,28,0)
0384                                                  marker->data_length - 14, &record, sizeHdr, sizeIptc)) {
0385 #else
0386                                                  marker->data_length - 14, &record, &sizeHdr, &sizeIptc)) {
0387 #endif
0388                 if (sizeIptc) {
0389                     // Decode the IPTC data
0390                     QByteArray byteArray((const char*)(record + sizeHdr), sizeIptc);
0391                     QBuffer buf(&byteArray);
0392                     iptcIO->loadFrom(layer->metaData(), &buf);
0393                 } else {
0394                     dbgFile << "IPTC Not found in Photoshop marker";
0395                 }
0396             }
0397             break;
0398         }
0399 
0400         dbgFile << "Looking for XMP information";
0401 
0402         for (jpeg_saved_marker_ptr marker = cinfo.marker_list; marker != 0; marker = marker->next) {
0403             dbgFile << "Marker is" << marker->marker;
0404             if (marker->marker != (JOCTET)(JPEG_APP0 + 1) || marker->data_length < 31) {
0405                 continue; /* XMP data is in an APP1 marker of at least 31 octets */
0406             }
0407             if (memcmp(marker->data, xmpMarker, 29) != 0) {
0408                 dbgFile << "Not XMP marker";
0409                 continue; /* No xmp Header */
0410             }
0411             dbgFile << "Found XMP Marker of length " << marker->data_length;
0412             QByteArray byteArray((const char*)marker->data + 29, marker->data_length - 29);
0413             KisMetaData::IOBackend *xmpIO = KisMetadataBackendRegistry::instance()->value("xmp");
0414             Q_ASSERT(xmpIO);
0415             xmpIO->loadFrom(layer->metaData(), new QBuffer(&byteArray));
0416             break;
0417         }
0418 
0419         // Dump loaded metadata
0420         layer->metaData()->debugDump();
0421 
0422         // Check whether the metadata has resolution info, too...
0423         if (cinfo.density_unit == 0 && layer->metaData()->containsEntry("tiff:XResolution") && layer->metaData()->containsEntry("tiff:YResolution")) {
0424             double xres = layer->metaData()->getEntry("tiff:XResolution").value().asDouble();
0425             double yres = layer->metaData()->getEntry("tiff:YResolution").value().asDouble();
0426             if (xres != 0 && yres != 0) {
0427                 m_d->image->setResolution(POINT_TO_INCH(xres), POINT_TO_INCH(yres));   // It is the "invert" macro because we convert from pointer-per-inch to points
0428             }
0429         }
0430 
0431         // Finish decompression
0432         jpeg_finish_decompress(&cinfo);
0433         jpeg_destroy_decompress(&cinfo);
0434         delete [] row_pointer;
0435         return ImportExportCodes::OK;
0436     }
0437     catch( std::runtime_error &) {
0438         jpeg_destroy_decompress(&cinfo);
0439         return ImportExportCodes::FileFormatIncorrect;
0440     }
0441 }
0442 
0443 
0444 
0445 KisImportExportErrorCode KisJPEGConverter::buildImage(QIODevice *io)
0446 {
0447     return decode(io);
0448 }
0449 
0450 
0451 KisImageSP KisJPEGConverter::image()
0452 {
0453     return m_d->image;
0454 }
0455 
0456 
0457 KisImportExportErrorCode KisJPEGConverter::buildFile(QIODevice *io, KisPaintLayerSP layer, KisJPEGOptions options, KisMetaData::Store* metaData)
0458 {
0459     KIS_ASSERT_RECOVER_RETURN_VALUE(layer, ImportExportCodes::InternalError);
0460 
0461     KisImageSP image = KisImageSP(layer->image());
0462     KIS_ASSERT_RECOVER_RETURN_VALUE(image, ImportExportCodes::InternalError);
0463 
0464     const KoColorSpace * cs = layer->colorSpace();
0465     J_COLOR_SPACE color_type = getColorTypeforColorSpace(cs);
0466 
0467     if (color_type == JCS_UNKNOWN) {
0468         layer->paintDevice()->convertTo(KoColorSpaceRegistry::instance()->rgb8(), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags());
0469         cs = KoColorSpaceRegistry::instance()->rgb8();
0470         color_type = JCS_RGB;
0471     }
0472 
0473     if (options.forceSRGB) {
0474         const KoColorSpace* dst = KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(), layer->colorSpace()->colorDepthId().id(), "sRGB built-in - (lcms internal)");
0475         layer->paintDevice()->convertTo(dst);
0476         cs = dst;
0477         color_type = JCS_RGB;
0478     }
0479 
0480     uint height = image->height();
0481     uint width = image->width();
0482     // Initialize structure
0483     struct jpeg_compress_struct cinfo;
0484     // Initialize error output
0485     struct jpeg_error_mgr jerr;
0486     cinfo.err = jpeg_std_error(&jerr);
0487     jerr.error_exit = jpegErrorExit;
0488 
0489     try {
0490 
0491 
0492         jpeg_create_compress(&cinfo);
0493         // Initialize output stream
0494         KisJPEGDestination::setDestination(&cinfo, io);
0495 
0496         cinfo.image_width = width;  // image width and height, in pixels
0497         cinfo.image_height = height;
0498         cinfo.input_components = cs->colorChannelCount(); // number of color channels per pixel */
0499         cinfo.in_color_space = color_type;   // colorspace of input image
0500 
0501         // Set default compression parameters
0502         jpeg_set_defaults(&cinfo);
0503         // Customize them
0504         jpeg_set_quality(&cinfo, options.quality, (boolean)options.baseLineJPEG);
0505 
0506         if (options.progressive) {
0507             jpeg_simple_progression(&cinfo);
0508         }
0509         // Optimize ?
0510         cinfo.optimize_coding = (boolean)options.optimize;
0511 
0512         // Smoothing
0513         cinfo.smoothing_factor = (boolean)options.smooth;
0514 
0515         // Subsampling
0516         switch (options.subsampling) {
0517         default:
0518         case 0: {
0519             cinfo.comp_info[0].h_samp_factor = 2;
0520             cinfo.comp_info[0].v_samp_factor = 2;
0521             cinfo.comp_info[1].h_samp_factor = 1;
0522             cinfo.comp_info[1].v_samp_factor = 1;
0523             cinfo.comp_info[2].h_samp_factor = 1;
0524             cinfo.comp_info[2].v_samp_factor = 1;
0525 
0526         }
0527             break;
0528         case 1: {
0529             cinfo.comp_info[0].h_samp_factor = 2;
0530             cinfo.comp_info[0].v_samp_factor = 1;
0531             cinfo.comp_info[1].h_samp_factor = 1;
0532             cinfo.comp_info[1].v_samp_factor = 1;
0533             cinfo.comp_info[2].h_samp_factor = 1;
0534             cinfo.comp_info[2].v_samp_factor = 1;
0535         }
0536             break;
0537         case 2: {
0538             cinfo.comp_info[0].h_samp_factor = 1;
0539             cinfo.comp_info[0].v_samp_factor = 2;
0540             cinfo.comp_info[1].h_samp_factor = 1;
0541             cinfo.comp_info[1].v_samp_factor = 1;
0542             cinfo.comp_info[2].h_samp_factor = 1;
0543             cinfo.comp_info[2].v_samp_factor = 1;
0544         }
0545             break;
0546         case 3: {
0547             cinfo.comp_info[0].h_samp_factor = 1;
0548             cinfo.comp_info[0].v_samp_factor = 1;
0549             cinfo.comp_info[1].h_samp_factor = 1;
0550             cinfo.comp_info[1].v_samp_factor = 1;
0551             cinfo.comp_info[2].h_samp_factor = 1;
0552             cinfo.comp_info[2].v_samp_factor = 1;
0553         }
0554             break;
0555         }
0556 
0557         // Save resolution
0558         cinfo.X_density = INCH_TO_POINT(image->xRes()); // It is the "invert" macro because we convert from pointer-per-inch to points
0559         cinfo.Y_density = INCH_TO_POINT(image->yRes()); // It is the "invert" macro because we convert from pointer-per-inch to points
0560         cinfo.density_unit = 1;
0561         cinfo.write_JFIF_header = (boolean)true;
0562 
0563         // Start compression
0564         jpeg_start_compress(&cinfo, (boolean)true);
0565         // Save exif and iptc information if any available
0566 
0567         if (metaData && !metaData->empty()) {
0568             metaData->applyFilters(options.filters);
0569             // Save EXIF
0570             if (options.exif) {
0571                 dbgFile << "Trying to save exif information";
0572 
0573                 KisMetaData::IOBackend *exifIO = KisMetadataBackendRegistry::instance()->value("exif");
0574                 Q_ASSERT(exifIO);
0575 
0576                 QBuffer buffer;
0577                 exifIO->saveTo(metaData, &buffer, KisMetaData::IOBackend::JpegHeader);
0578 
0579                 dbgFile << "Exif information size is" << buffer.data().size();
0580                 QByteArray data = buffer.data();
0581                 if (data.size() < MAX_DATA_BYTES_IN_MARKER) {
0582                     jpeg_write_marker(&cinfo, JPEG_APP0 + 1, (const JOCTET*)data.data(), data.size());
0583                 } else {
0584                     dbgFile << "EXIF information could not be saved."; // TODO: warn the user ?
0585                 }
0586             }
0587             // Save IPTC
0588             if (options.iptc) {
0589                 dbgFile << "Trying to save exif information";
0590                 KisMetaData::IOBackend *iptcIO = KisMetadataBackendRegistry::instance()->value("iptc");
0591                 Q_ASSERT(iptcIO);
0592 
0593                 QBuffer buffer;
0594                 iptcIO->saveTo(metaData, &buffer, KisMetaData::IOBackend::JpegHeader);
0595 
0596                 dbgFile << "IPTC information size is" << buffer.data().size();
0597                 QByteArray data = buffer.data();
0598                 if (data.size() < MAX_DATA_BYTES_IN_MARKER) {
0599                     jpeg_write_marker(&cinfo, JPEG_APP0 + 13, (const JOCTET*)data.data(), data.size());
0600                 } else {
0601                     dbgFile << "IPTC information could not be saved."; // TODO: warn the user ?
0602                 }
0603             }
0604             // Save XMP
0605             if (options.xmp) {
0606                 dbgFile << "Trying to save XMP information";
0607                 KisMetaData::IOBackend *xmpIO = KisMetadataBackendRegistry::instance()->value("xmp");
0608                 Q_ASSERT(xmpIO);
0609 
0610                 QBuffer buffer;
0611                 xmpIO->saveTo(metaData, &buffer, KisMetaData::IOBackend::JpegHeader);
0612 
0613                 dbgFile << "XMP information size is" << buffer.data().size();
0614                 QByteArray data = buffer.data();
0615                 if (data.size() < MAX_DATA_BYTES_IN_MARKER) {
0616                     jpeg_write_marker(&cinfo, JPEG_APP0 + 14, (const JOCTET*)data.data(), data.size());
0617                 } else {
0618                     dbgFile << "XMP information could not be saved."; // TODO: warn the user ?
0619                 }
0620             }
0621         }
0622 
0623 
0624         KisPaintDeviceSP dev = new KisPaintDevice(layer->colorSpace());
0625         KoColor c(options.transparencyFillColor, layer->colorSpace());
0626         dev->fill(QRect(0, 0, width, height), c);
0627         KisPainter gc(dev);
0628         gc.bitBlt(QPoint(0, 0), layer->paintDevice(), QRect(0, 0, width, height));
0629         gc.end();
0630 
0631 
0632         if (options.saveProfile) {
0633             const KoColorProfile* colorProfile = layer->colorSpace()->profile();
0634             QByteArray colorProfileData = colorProfile->rawData();
0635             write_icc_profile(& cinfo, (uchar*) colorProfileData.data(), colorProfileData.size());
0636         }
0637 
0638         // Write data information
0639 
0640         JSAMPROW row_pointer = new JSAMPLE[width*cinfo.input_components];
0641         int color_nb_bits = 8 * layer->paintDevice()->pixelSize() / layer->paintDevice()->channelCount();
0642 
0643         for (; cinfo.next_scanline < height;) {
0644             KisHLineConstIteratorSP it = dev->createHLineConstIteratorNG(0, cinfo.next_scanline, width);
0645             quint8 *dst = row_pointer;
0646             switch (color_type) {
0647             case JCS_GRAYSCALE:
0648                 if (color_nb_bits == 16) {
0649                     do {
0650                         //const quint16 *d = reinterpret_cast<const quint16 *>(it->oldRawData());
0651                         const quint8 *d = it->oldRawData();
0652                         *(dst++) = cs->scaleToU8(d, 0);//d[0] / quint8_MAX;
0653 
0654                     } while (it->nextPixel());
0655                 } else {
0656                     do {
0657                         const quint8 *d = it->oldRawData();
0658                         *(dst++) = d[0];
0659 
0660                     } while (it->nextPixel());
0661                 }
0662                 break;
0663             case JCS_RGB:
0664                 if (color_nb_bits == 16) {
0665                     do {
0666                         //const quint16 *d = reinterpret_cast<const quint16 *>(it->oldRawData());
0667                         const quint8 *d = it->oldRawData();
0668                         *(dst++) = cs->scaleToU8(d, 2); //d[2] / quint8_MAX;
0669                         *(dst++) = cs->scaleToU8(d, 1); //d[1] / quint8_MAX;
0670                         *(dst++) = cs->scaleToU8(d, 0); //d[0] / quint8_MAX;
0671 
0672                     } while (it->nextPixel());
0673                 } else {
0674                     do {
0675                         const quint8 *d = it->oldRawData();
0676                         *(dst++) = d[2];
0677                         *(dst++) = d[1];
0678                         *(dst++) = d[0];
0679 
0680                     } while (it->nextPixel());
0681                 }
0682                 break;
0683             case JCS_CMYK:
0684                 if (color_nb_bits == 16) {
0685                     do {
0686                         //const quint16 *d = reinterpret_cast<const quint16 *>(it->oldRawData());
0687                         const quint8 *d = it->oldRawData();
0688                         *(dst++) = quint8_MAX - cs->scaleToU8(d, 0);//quint8_MAX - d[0] / quint8_MAX;
0689                         *(dst++) = quint8_MAX - cs->scaleToU8(d, 1);//quint8_MAX - d[1] / quint8_MAX;
0690                         *(dst++) = quint8_MAX - cs->scaleToU8(d, 2);//quint8_MAX - d[2] / quint8_MAX;
0691                         *(dst++) = quint8_MAX - cs->scaleToU8(d, 3);//quint8_MAX - d[3] / quint8_MAX;
0692 
0693                     } while (it->nextPixel());
0694                 } else {
0695                     do {
0696                         const quint8 *d = it->oldRawData();
0697                         *(dst++) = quint8_MAX - d[0];
0698                         *(dst++) = quint8_MAX - d[1];
0699                         *(dst++) = quint8_MAX - d[2];
0700                         *(dst++) = quint8_MAX - d[3];
0701 
0702                     } while (it->nextPixel());
0703                 }
0704                 break;
0705             default:
0706                 delete [] row_pointer;
0707                 jpeg_destroy_compress(&cinfo);
0708                 return ImportExportCodes::FormatFeaturesUnsupported;
0709             }
0710             jpeg_write_scanlines(&cinfo, &row_pointer, 1);
0711         }
0712 
0713 
0714         // Writing is over
0715         jpeg_finish_compress(&cinfo);
0716 
0717         delete [] row_pointer;
0718         // Free memory
0719         jpeg_destroy_compress(&cinfo);
0720 
0721         return ImportExportCodes::OK;
0722 
0723     } catch( std::runtime_error &) {
0724         jpeg_destroy_compress(&cinfo);
0725         return ImportExportCodes::ErrorWhileWriting;
0726     }
0727 
0728 }
0729 
0730 
0731 void KisJPEGConverter::cancel()
0732 {
0733     m_d->stop = true;
0734 }
0735 
0736