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