Krita Source Code Documentation
Loading...
Searching...
No Matches
KisJPEGConverter Class Reference

#include <kis_jpeg_converter.h>

+ Inheritance diagram for KisJPEGConverter:

Classes

struct  Private
 

Public Slots

virtual void cancel ()
 

Public Member Functions

KisImportExportErrorCode buildFile (QIODevice *io, KisPaintLayerSP layer, KisJPEGOptions options, KisMetaData::Store *metaData)
 
KisImportExportErrorCode buildImage (QIODevice *io)
 
KisImageSP image ()
 
 KisJPEGConverter (KisDocument *doc, bool batchMode=false)
 
 ~KisJPEGConverter () override
 

Private Member Functions

KisImportExportErrorCode decode (QIODevice *io)
 

Private Attributes

QScopedPointer< Privatem_d
 

Detailed Description

Definition at line 51 of file kis_jpeg_converter.h.

Constructor & Destructor Documentation

◆ KisJPEGConverter()

KisJPEGConverter::KisJPEGConverter ( KisDocument * doc,
bool batchMode = false )

Definition at line 124 of file kis_jpeg_converter.cc.

125 : m_d(new Private(doc, batchMode))
126{
127}
QScopedPointer< Private > m_d

◆ ~KisJPEGConverter()

KisJPEGConverter::~KisJPEGConverter ( )
override

Definition at line 129 of file kis_jpeg_converter.cc.

130{
131}

Member Function Documentation

◆ buildFile()

KisImportExportErrorCode KisJPEGConverter::buildFile ( QIODevice * io,
KisPaintLayerSP layer,
KisJPEGOptions options,
KisMetaData::Store * metaData )

Definition at line 456 of file kis_jpeg_converter.cc.

457{
459
460 KisImageSP image = KisImageSP(layer->image());
462
463 const KoColorSpace * cs = layer->colorSpace();
464 J_COLOR_SPACE color_type = getColorTypeforColorSpace(cs);
465
466 if (color_type == JCS_UNKNOWN) {
469 color_type = JCS_RGB;
470 }
471
472 if (options.forceSRGB) {
473 const KoColorSpace* dst = KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(), layer->colorSpace()->colorDepthId().id(), "sRGB built-in - (lcms internal)");
474 layer->paintDevice()->convertTo(dst);
475 cs = dst;
476 color_type = JCS_RGB;
477 }
478
479 uint height = image->height();
480 uint width = image->width();
481 // Initialize structure
482 struct jpeg_compress_struct cinfo;
483 // Initialize error output
484 struct jpeg_error_mgr jerr;
485 cinfo.err = jpeg_std_error(&jerr);
486 jerr.error_exit = jpegErrorExit;
487
488 try {
489
490
491 jpeg_create_compress(&cinfo);
492 // Initialize output stream
494
495 cinfo.image_width = width; // image width and height, in pixels
496 cinfo.image_height = height;
497 cinfo.input_components = cs->colorChannelCount(); // number of color channels per pixel */
498 cinfo.in_color_space = color_type; // colorspace of input image
499
500 // Set default compression parameters
501 jpeg_set_defaults(&cinfo);
502 // Customize them
503 jpeg_set_quality(&cinfo, options.quality, (boolean)options.baseLineJPEG);
504
505 if (options.progressive) {
506 jpeg_simple_progression(&cinfo);
507 }
508 // Optimize ?
509 cinfo.optimize_coding = (boolean)options.optimize;
510
511 // Smoothing
512 cinfo.smoothing_factor = (boolean)options.smooth;
513
514 // Subsampling
515 switch (options.subsampling) {
516 default:
517 case 0: {
518 cinfo.comp_info[0].h_samp_factor = 2;
519 cinfo.comp_info[0].v_samp_factor = 2;
520 cinfo.comp_info[1].h_samp_factor = 1;
521 cinfo.comp_info[1].v_samp_factor = 1;
522 cinfo.comp_info[2].h_samp_factor = 1;
523 cinfo.comp_info[2].v_samp_factor = 1;
524
525 }
526 break;
527 case 1: {
528 cinfo.comp_info[0].h_samp_factor = 2;
529 cinfo.comp_info[0].v_samp_factor = 1;
530 cinfo.comp_info[1].h_samp_factor = 1;
531 cinfo.comp_info[1].v_samp_factor = 1;
532 cinfo.comp_info[2].h_samp_factor = 1;
533 cinfo.comp_info[2].v_samp_factor = 1;
534 }
535 break;
536 case 2: {
537 cinfo.comp_info[0].h_samp_factor = 1;
538 cinfo.comp_info[0].v_samp_factor = 2;
539 cinfo.comp_info[1].h_samp_factor = 1;
540 cinfo.comp_info[1].v_samp_factor = 1;
541 cinfo.comp_info[2].h_samp_factor = 1;
542 cinfo.comp_info[2].v_samp_factor = 1;
543 }
544 break;
545 case 3: {
546 cinfo.comp_info[0].h_samp_factor = 1;
547 cinfo.comp_info[0].v_samp_factor = 1;
548 cinfo.comp_info[1].h_samp_factor = 1;
549 cinfo.comp_info[1].v_samp_factor = 1;
550 cinfo.comp_info[2].h_samp_factor = 1;
551 cinfo.comp_info[2].v_samp_factor = 1;
552 }
553 break;
554 }
555
556 // Save resolution
557 cinfo.X_density = INCH_TO_POINT(image->xRes()); // It is the "invert" macro because we convert from pointer-per-inch to points
558 cinfo.Y_density = INCH_TO_POINT(image->yRes()); // It is the "invert" macro because we convert from pointer-per-inch to points
559 cinfo.density_unit = 1;
560 cinfo.write_JFIF_header = (boolean)true;
561
562 // Start compression
563 jpeg_start_compress(&cinfo, (boolean)true);
564 // Save exif and iptc information if any available
565
566 if (metaData && !metaData->empty()) {
567 metaData->applyFilters(options.filters);
568 // Save EXIF
569 if (options.exif) {
570 dbgFile << "Trying to save exif information";
571
573 Q_ASSERT(exifIO);
574
575 QBuffer buffer;
576 exifIO->saveTo(metaData, &buffer, KisMetaData::IOBackend::JpegHeader);
577
578 dbgFile << "Exif information size is" << buffer.data().size();
579 QByteArray data = buffer.data();
580 if (data.size() < MAX_DATA_BYTES_IN_MARKER) {
581 jpeg_write_marker(&cinfo, JPEG_APP0 + 1, (const JOCTET*)data.data(), data.size());
582 } else {
583 dbgFile << "EXIF information could not be saved."; // TODO: warn the user ?
584 }
585 }
586 // Save IPTC
587 if (options.iptc) {
588 dbgFile << "Trying to save exif information";
590 Q_ASSERT(iptcIO);
591
592 QBuffer buffer;
593 iptcIO->saveTo(metaData, &buffer, KisMetaData::IOBackend::JpegHeader);
594
595 dbgFile << "IPTC information size is" << buffer.data().size();
596 QByteArray data = buffer.data();
597 if (data.size() < MAX_DATA_BYTES_IN_MARKER) {
598 jpeg_write_marker(&cinfo, JPEG_APP0 + 13, (const JOCTET*)data.data(), data.size());
599 } else {
600 dbgFile << "IPTC information could not be saved."; // TODO: warn the user ?
601 }
602 }
603 // Save XMP
604 if (options.xmp) {
605 dbgFile << "Trying to save XMP information";
607 Q_ASSERT(xmpIO);
608
609 QBuffer buffer;
610 xmpIO->saveTo(metaData, &buffer, KisMetaData::IOBackend::JpegHeader);
611
612 dbgFile << "XMP information size is" << buffer.data().size();
613 QByteArray data = buffer.data();
614 if (data.size() < MAX_DATA_BYTES_IN_MARKER) {
615 jpeg_write_marker(&cinfo, JPEG_APP0 + 14, (const JOCTET*)data.data(), data.size());
616 } else {
617 dbgFile << "XMP information could not be saved."; // TODO: warn the user ?
618 }
619 }
620 }
621
622
623 KisPaintDeviceSP dev = new KisPaintDevice(layer->colorSpace());
624 KoColor c(options.transparencyFillColor, layer->colorSpace());
625 dev->fill(QRect(0, 0, width, height), c);
626 KisPainter gc(dev);
627 gc.bitBlt(QPoint(0, 0), layer->paintDevice(), QRect(0, 0, width, height));
628 gc.end();
629
630
631 if (options.saveProfile) {
632 const KoColorProfile* colorProfile = layer->colorSpace()->profile();
633 QByteArray colorProfileData = colorProfile->rawData();
634 write_icc_profile(& cinfo, (uchar*) colorProfileData.data(), colorProfileData.size());
635 }
636
637 // Write data information
638
639 JSAMPROW row_pointer = new JSAMPLE[width*cinfo.input_components];
640 int color_nb_bits = 8 * layer->paintDevice()->pixelSize() / layer->paintDevice()->channelCount();
641
642 for (; cinfo.next_scanline < height;) {
643 KisHLineConstIteratorSP it = dev->createHLineConstIteratorNG(0, cinfo.next_scanline, width);
644 quint8 *dst = row_pointer;
645 switch (color_type) {
646 case JCS_GRAYSCALE:
647 if (color_nb_bits == 16) {
648 do {
649 //const quint16 *d = reinterpret_cast<const quint16 *>(it->oldRawData());
650 const quint8 *d = it->oldRawData();
651 *(dst++) = cs->scaleToU8(d, 0);//d[0] / quint8_MAX;
652
653 } while (it->nextPixel());
654 } else {
655 do {
656 const quint8 *d = it->oldRawData();
657 *(dst++) = d[0];
658
659 } while (it->nextPixel());
660 }
661 break;
662 case JCS_RGB:
663 if (color_nb_bits == 16) {
664 do {
665 //const quint16 *d = reinterpret_cast<const quint16 *>(it->oldRawData());
666 const quint8 *d = it->oldRawData();
667 *(dst++) = cs->scaleToU8(d, 2); //d[2] / quint8_MAX;
668 *(dst++) = cs->scaleToU8(d, 1); //d[1] / quint8_MAX;
669 *(dst++) = cs->scaleToU8(d, 0); //d[0] / quint8_MAX;
670
671 } while (it->nextPixel());
672 } else {
673 do {
674 const quint8 *d = it->oldRawData();
675 *(dst++) = d[2];
676 *(dst++) = d[1];
677 *(dst++) = d[0];
678
679 } while (it->nextPixel());
680 }
681 break;
682 case JCS_CMYK:
683 if (color_nb_bits == 16) {
684 do {
685 //const quint16 *d = reinterpret_cast<const quint16 *>(it->oldRawData());
686 const quint8 *d = it->oldRawData();
687 *(dst++) = quint8_MAX - cs->scaleToU8(d, 0);//quint8_MAX - d[0] / quint8_MAX;
688 *(dst++) = quint8_MAX - cs->scaleToU8(d, 1);//quint8_MAX - d[1] / quint8_MAX;
689 *(dst++) = quint8_MAX - cs->scaleToU8(d, 2);//quint8_MAX - d[2] / quint8_MAX;
690 *(dst++) = quint8_MAX - cs->scaleToU8(d, 3);//quint8_MAX - d[3] / quint8_MAX;
691
692 } while (it->nextPixel());
693 } else {
694 do {
695 const quint8 *d = it->oldRawData();
696 *(dst++) = quint8_MAX - d[0];
697 *(dst++) = quint8_MAX - d[1];
698 *(dst++) = quint8_MAX - d[2];
699 *(dst++) = quint8_MAX - d[3];
700
701 } while (it->nextPixel());
702 }
703 break;
704 default:
705 delete [] row_pointer;
706 jpeg_destroy_compress(&cinfo);
708 }
709 jpeg_write_scanlines(&cinfo, &row_pointer, 1);
710 }
711
712
713 // Writing is over
714 jpeg_finish_compress(&cinfo);
715
716 delete [] row_pointer;
717 // Free memory
718 jpeg_destroy_compress(&cinfo);
719
721
722 } catch( std::runtime_error &) {
723 jpeg_destroy_compress(&cinfo);
725 }
726
727}
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
unsigned int uint
constexpr qreal INCH_TO_POINT(qreal inch)
Definition KoUnit.h:38
virtual const quint8 * oldRawData() const =0
virtual bool nextPixel()=0
qint32 width() const
double xRes() const
double yRes() const
qint32 height() const
@ JpegHeader
Append Jpeg-style header.
virtual bool saveTo(const Store *store, QIODevice *ioDevice, HeaderType headerType=NoHeader) const =0
void applyFilters(const QList< const Filter * > &filters)
static KisMetadataBackendRegistry * instance()
quint32 pixelSize() const
quint32 channelCount() const
void fill(const QRect &rc, const KoColor &color)
void convertTo(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags(), KUndo2Command *parentCommand=nullptr, KoUpdater *progressUpdater=nullptr)
KisHLineConstIteratorSP createHLineConstIteratorNG(qint32 x, qint32 y, qint32 w) const
virtual quint8 scaleToU8(const quint8 *srcPixel, qint32 channelPos) const =0
virtual KoID colorDepthId() const =0
virtual quint32 colorChannelCount() const =0
virtual const KoColorProfile * profile() const =0
const T value(const QString &id) const
QString id() const
Definition KoID.cpp:63
void write_icc_profile(j_compress_ptr cinfo, const JOCTET *icc_data_ptr, unsigned int icc_data_len)
Definition iccjpeg.c:74
#define MAX_DATA_BYTES_IN_MARKER
Definition iccjpeg.c:62
#define KIS_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:85
#define dbgFile
Definition kis_debug.h:53
const quint8 quint8_MAX
Definition kis_global.h:24
KisSharedPtr< KisImage > KisImageSP
Definition kis_types.h:69
void setDestination(j_compress_ptr cinfo, QIODevice *destinationDevice)
KisImageWSP image
QList< const KisMetaData::Filter * > filters
const KoColorSpace * colorSpace() const override
returns the image's colorSpace or null, if there is no image
Definition kis_layer.cc:225
KisPaintDeviceSP paintDevice
virtual QByteArray rawData() const
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()
const KoColorSpace * rgb8(const QString &profileName=QString())

References KisMetaData::Store::applyFilters(), KisJPEGOptions::baseLineJPEG, KisPainter::bitBlt(), KisPaintDevice::channelCount(), KoColorSpace::colorChannelCount(), KoColorSpace::colorDepthId(), KisLayer::colorSpace(), KoColorSpaceRegistry::colorSpace(), KisPaintDevice::convertTo(), KisPaintDevice::createHLineConstIteratorNG(), dbgFile, KisMetaData::Store::empty(), KisPainter::end(), ImportExportCodes::ErrorWhileWriting, KisJPEGOptions::exif, KisPaintDevice::fill(), KisJPEGOptions::filters, KisJPEGOptions::forceSRGB, ImportExportCodes::FormatFeaturesUnsupported, KisImage::height(), KoID::id(), KisBaseNode::image, image(), INCH_TO_POINT(), KisMetadataBackendRegistry::instance(), KoColorSpaceRegistry::instance(), KoColorConversionTransformation::internalConversionFlags(), ImportExportCodes::InternalError, KoColorConversionTransformation::internalRenderingIntent(), KisJPEGOptions::iptc, KisMetaData::IOBackend::JpegHeader, KIS_ASSERT_RECOVER_RETURN_VALUE, MAX_DATA_BYTES_IN_MARKER, KisBaseConstIteratorNG::nextPixel(), ImportExportCodes::OK, KisBaseConstAccessor::oldRawData(), KisJPEGOptions::optimize, KisPaintLayer::paintDevice, KisPaintDevice::pixelSize(), KoColorSpace::profile(), KisJPEGOptions::progressive, KisJPEGOptions::quality, quint8_MAX, KoColorProfile::rawData(), KoColorSpaceRegistry::rgb8(), RGBAColorModelID, KisJPEGOptions::saveProfile, KisMetaData::IOBackend::saveTo(), KoColorSpace::scaleToU8(), KisJPEGDestination::setDestination(), KisJPEGOptions::smooth, KisJPEGOptions::subsampling, KisJPEGOptions::transparencyFillColor, KoGenericRegistry< T >::value(), KisImage::width(), write_icc_profile(), KisJPEGOptions::xmp, KisImage::xRes(), and KisImage::yRes().

◆ buildImage()

KisImportExportErrorCode KisJPEGConverter::buildImage ( QIODevice * io)

Definition at line 444 of file kis_jpeg_converter.cc.

445{
446 return decode(io);
447}
KisImportExportErrorCode decode(QIODevice *io)

References decode().

◆ cancel

void KisJPEGConverter::cancel ( )
virtualslot

Definition at line 730 of file kis_jpeg_converter.cc.

731{
732 m_d->stop = true;
733}

References m_d.

◆ decode()

KisImportExportErrorCode KisJPEGConverter::decode ( QIODevice * io)
private

Definition at line 133 of file kis_jpeg_converter.cc.

134{
135 struct jpeg_decompress_struct cinfo;
136 struct jpeg_error_mgr jerr;
137
138 cinfo.err = jpeg_std_error(&jerr);
139 jerr.error_exit = jpegErrorExit;
140
141 try {
142 jpeg_create_decompress(&cinfo);
143
144 KisJPEGSource::setSource(&cinfo, io);
145
146 jpeg_save_markers(&cinfo, JPEG_COM, 0xFFFF);
147 /* Save APP0..APP15 markers */
148 for (int m = 0; m < 16; m++)
149 jpeg_save_markers(&cinfo, JPEG_APP0 + m, 0xFFFF);
150
151
152 // setup_read_icc_profile(&cinfo);
153 // read header
154 jpeg_read_header(&cinfo, (boolean)true);
155
156 // start reading
157 jpeg_start_decompress(&cinfo);
158
159 // Get the colorspace
160 QString modelId = getColorSpaceModelForColorType(cinfo.out_color_space);
161 if (modelId.isEmpty()) {
162 dbgFile << "unsupported colorspace :" << cinfo.out_color_space;
163 jpeg_destroy_decompress(&cinfo);
165 }
166
167 uchar* profile_data = 0;
168 uint profile_len = 0;
169 const KoColorProfile* profile = 0;
170 QByteArray profile_rawdata;
171 if (read_icc_profile(&cinfo, &profile_data, &profile_len)) {
172 profile_rawdata.resize(profile_len);
173 memcpy(profile_rawdata.data(), profile_data, profile_len);
174 cmsHPROFILE hProfile = cmsOpenProfileFromMem(profile_data, profile_len);
175
176 if (hProfile != (cmsHPROFILE) 0) {
177 profile = KoColorSpaceRegistry::instance()->createColorProfile(modelId, Integer8BitsColorDepthID.id(), profile_rawdata);
178 Q_CHECK_PTR(profile);
179 dbgFile <<"profile name:" << profile->name() <<" product information:" << profile->info();
180 if (!profile->isSuitableForOutput()) {
181 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
182 }
183 }
184
185 free(profile_data);
186 }
187
188 const QString colorSpaceId =
190
191 // Check that the profile is used by the color space
192 if (profile && !KoColorSpaceRegistry::instance()->profileIsCompatible(profile, colorSpaceId)) {
193 warnFile << "The profile " << profile->name() << " is not compatible with the color space model " << modelId;
194 profile = 0;
195 }
196
197 // Retrieve a pointer to the colorspace
198 const KoColorSpace* cs;
199 if (profile && profile->isSuitableForOutput()) {
200 dbgFile << "image has embedded profile:" << profile -> name() << "";
202 } else
204
205 if (cs == 0) {
206 dbgFile << "unknown colorspace";
207 jpeg_destroy_decompress(&cinfo);
209 }
210 // TODO fixit
211 // Create the cmsTransform if needed
212
213 KoColorTransformation* transform = 0;
214 if (profile && !profile->isSuitableForOutput()) {
216 }
217 // Apparently an invalid transform was created from the profile. See bug https://bugs.kde.org/show_bug.cgi?id=255451.
218 // After 2.3: warn the user!
219 if (transform && !transform->isValid()) {
220 delete transform;
221 transform = 0;
222 }
223
224 // Creating the KisImageSP
225 if (!m_d->image) {
226 m_d->image = new KisImage(m_d->doc->createUndoStore(), cinfo.image_width, cinfo.image_height, cs, "built image");
227 Q_CHECK_PTR(m_d->image);
228 }
229
230 // Set resolution
231 double xres = 72, yres = 72;
232 if (cinfo.density_unit == 1) {
233 xres = cinfo.X_density;
234 yres = cinfo.Y_density;
235 } else if (cinfo.density_unit == 2) {
236 xres = cinfo.X_density * 2.54;
237 yres = cinfo.Y_density * 2.54;
238 }
239 if (xres < 72) {
240 xres = 72;
241 }
242 if (yres < 72) {
243 yres = 72;
244 }
245 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
246
247 // Create layer
248 KisPaintLayerSP layer = KisPaintLayerSP(new KisPaintLayer(m_d->image.data(), m_d->image -> nextLayerName(), quint8_MAX));
249
250 // Read data
251 JSAMPROW row_pointer = new JSAMPLE[cinfo.image_width*cinfo.num_components];
252
253 for (; cinfo.output_scanline < cinfo.image_height;) {
254 KisHLineIteratorSP it = layer->paintDevice()->createHLineIteratorNG(0, cinfo.output_scanline, cinfo.image_width);
255 jpeg_read_scanlines(&cinfo, &row_pointer, 1);
256 quint8 *src = row_pointer;
257 switch (cinfo.out_color_space) {
258 case JCS_GRAYSCALE:
259 do {
260 quint8 *d = it->rawData();
261 d[0] = *(src++);
262 if (transform) transform->transform(d, d, 1);
263 d[1] = quint8_MAX;
264
265 } while (it->nextPixel());
266 break;
267 case JCS_RGB:
268 do {
269 quint8 *d = it->rawData();
270 d[2] = *(src++);
271 d[1] = *(src++);
272 d[0] = *(src++);
273 if (transform) transform->transform(d, d, 1);
274 d[3] = quint8_MAX;
275
276 } while (it->nextPixel());
277 break;
278 case JCS_CMYK:
279 do {
280 quint8 *d = it->rawData();
281 d[0] = quint8_MAX - *(src++);
282 d[1] = quint8_MAX - *(src++);
283 d[2] = quint8_MAX - *(src++);
284 d[3] = quint8_MAX - *(src++);
285 if (transform) transform->transform(d, d, 1);
286 d[4] = quint8_MAX;
287
288 } while (it->nextPixel());
289 break;
290 default:
292 }
293 }
294
295 m_d->image->addNode(KisNodeSP(layer.data()), m_d->image->rootLayer().data());
296
297 // Read exif information
298
299 dbgFile << "Looking for exif information";
300
301 for (jpeg_saved_marker_ptr marker = cinfo.marker_list; marker != 0; marker = marker->next) {
302 dbgFile << "Marker is" << marker->marker;
303 if (marker->marker != (JOCTET)(JPEG_APP0 + 1)
304 || marker->data_length < 14) {
305 continue; /* Exif data is in an APP1 marker of at least 14 octets */
306 }
307
308 if (GETJOCTET(marker->data[0]) != (JOCTET) 0x45 ||
309 GETJOCTET(marker->data[1]) != (JOCTET) 0x78 ||
310 GETJOCTET(marker->data[2]) != (JOCTET) 0x69 ||
311 GETJOCTET(marker->data[3]) != (JOCTET) 0x66 ||
312 GETJOCTET(marker->data[4]) != (JOCTET) 0x00 ||
313 GETJOCTET(marker->data[5]) != (JOCTET) 0x00)
314 continue; /* no Exif header */
315
316 dbgFile << "Found exif information of length :" << marker->data_length;
318 Q_ASSERT(exifIO);
319 QByteArray byteArray((const char*)marker->data + 6, marker->data_length - 6);
320 QBuffer buf(&byteArray);
321 exifIO->loadFrom(layer->metaData(), &buf);
322 // Interpret orientation tag
323 if (layer->metaData()->containsEntry("http://ns.adobe.com/tiff/1.0/", "Orientation")) {
324 KisMetaData::Entry& entry = layer->metaData()->getEntry("http://ns.adobe.com/tiff/1.0/", "Orientation");
325 if (entry.value().type() == KisMetaData::Value::Variant) {
326 switch (entry.value().asVariant().toInt()) {
327 case 2:
329 break;
330 case 3:
332 break;
333 case 4:
335 break;
336 case 5:
337 image()->rotateImage(M_PI / 2);
339 break;
340 case 6:
341 image()->rotateImage(M_PI / 2);
342 break;
343 case 7:
344 image()->rotateImage(M_PI / 2);
346 break;
347 case 8:
348 image()->rotateImage(-M_PI / 2 + M_PI*2);
349 break;
350 default:
351 break;
352 }
353 }
354 entry.value().setVariant(1);
355 }
356 break;
357 }
358
359 dbgFile << "Looking for IPTC information";
360
361 for (jpeg_saved_marker_ptr marker = cinfo.marker_list; marker != 0; marker = marker->next) {
362 dbgFile << "Marker is" << marker->marker;
363 if (marker->marker != (JOCTET)(JPEG_APP0 + 13) || marker->data_length < 14) {
364 continue; /* IPTC data is in an APP13 marker of at least 16 octets */
365 }
366 if (memcmp(marker->data, photoshopMarker, 14) != 0) {
367 for (int i = 0; i < 14; i++) {
368 dbgFile << (int)(*(marker->data + i)) << "" << (int)(photoshopMarker[i]);
369 }
370 dbgFile << "No photoshop marker";
371 continue; /* No IPTC Header */
372 }
373
374 dbgFile << "Found Photoshop information of length :" << marker->data_length;
376 Q_ASSERT(iptcIO);
377 const Exiv2::byte *record = 0;
378 uint32_t sizeIptc = 0;
379 uint32_t sizeHdr = 0;
380 // Find actual Iptc data within the APP13 segment
381 if (!Exiv2::Photoshop::locateIptcIrb((Exiv2::byte*)(marker->data + 14),
382#if EXIV2_TEST_VERSION(0,28,0)
383 marker->data_length - 14, &record, sizeHdr, sizeIptc)) {
384#else
385 marker->data_length - 14, &record, &sizeHdr, &sizeIptc)) {
386#endif
387 if (sizeIptc) {
388 // Decode the IPTC data
389 QByteArray byteArray((const char*)(record + sizeHdr), sizeIptc);
390 QBuffer buf(&byteArray);
391 iptcIO->loadFrom(layer->metaData(), &buf);
392 } else {
393 dbgFile << "IPTC Not found in Photoshop marker";
394 }
395 }
396 break;
397 }
398
399 dbgFile << "Looking for XMP information";
400
401 for (jpeg_saved_marker_ptr marker = cinfo.marker_list; marker != 0; marker = marker->next) {
402 dbgFile << "Marker is" << marker->marker;
403 if (marker->marker != (JOCTET)(JPEG_APP0 + 1) || marker->data_length < 31) {
404 continue; /* XMP data is in an APP1 marker of at least 31 octets */
405 }
406 if (memcmp(marker->data, xmpMarker, 29) != 0) {
407 dbgFile << "Not XMP marker";
408 continue; /* No xmp Header */
409 }
410 dbgFile << "Found XMP Marker of length " << marker->data_length;
411 QByteArray byteArray((const char*)marker->data + 29, marker->data_length - 29);
413 Q_ASSERT(xmpIO);
414 xmpIO->loadFrom(layer->metaData(), new QBuffer(&byteArray));
415 break;
416 }
417
418 // Dump loaded metadata
419 layer->metaData()->debugDump();
420
421 // Check whether the metadata has resolution info, too...
422 if (cinfo.density_unit == 0 && layer->metaData()->containsEntry("tiff:XResolution") && layer->metaData()->containsEntry("tiff:YResolution")) {
423 double xres = layer->metaData()->getEntry("tiff:XResolution").value().asDouble();
424 double yres = layer->metaData()->getEntry("tiff:YResolution").value().asDouble();
425 if (xres != 0 && yres != 0) {
426 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
427 }
428 }
429
430 // Finish decompression
431 jpeg_finish_decompress(&cinfo);
432 jpeg_destroy_decompress(&cinfo);
433 delete [] row_pointer;
435 }
436 catch( std::runtime_error &) {
437 jpeg_destroy_decompress(&cinfo);
439 }
440}
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
constexpr qreal POINT_TO_INCH(qreal px)
Definition KoUnit.h:37
KisGroupLayerSP rootLayer() const
void rotateImage(double radians)
start asynchronous operation on rotating the image
const KisMetaData::Value & value() const
virtual bool loadFrom(Store *store, QIODevice *ioDevice) const =0
bool containsEntry(const QString &entryKey) const
Entry & getEntry(const QString &entryKey)
QVariant asVariant() const
bool setVariant(const QVariant &variant)
ValueType type() const
KisHLineIteratorSP createHLineIteratorNG(qint32 x, qint32 y, qint32 w)
static void mirrorY(KisPaintDeviceSP dev, qreal axis)
static void mirrorX(KisPaintDeviceSP dev, qreal axis)
virtual KoColorConversionTransformation * createColorConverter(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
virtual bool isValid() const
virtual void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const =0
boolean read_icc_profile(j_decompress_ptr cinfo, JOCTET **icc_data_ptr, unsigned int *icc_data_len)
Definition iccjpeg.c:187
#define warnFile
Definition kis_debug.h:95
#define M_PI
Definition kis_global.h:111
const char xmpMarker[]
const char photoshopMarker[]
KisSharedPtr< KisPaintLayer > KisPaintLayerSP
KisSharedPtr< KisNode > KisNodeSP
Definition kis_types.h:86
const char * name(StandardAction id)
void setSource(j_decompress_ptr cinfo, QIODevice *inputDevice)
KisMetaData::Store * metaData()
virtual bool isSuitableForOutput() const =0
QString colorSpaceId(const QString &colorModelId, const QString &colorDepthId) const
const KoColorProfile * createColorProfile(const QString &colorModelId, const QString &colorDepthId, const QByteArray &rawData)

References KisMetaData::Value::asDouble(), KisMetaData::Value::asVariant(), KoColorSpaceRegistry::colorSpace(), KoColorSpaceRegistry::colorSpaceId(), KisMetaData::Store::containsEntry(), KoColorSpace::createColorConverter(), KoColorSpaceRegistry::createColorProfile(), KisPaintDevice::createHLineIteratorNG(), KisSharedPtr< T >::data(), dbgFile, KisMetaData::Store::debugDump(), ImportExportCodes::FileFormatIncorrect, ImportExportCodes::FormatColorSpaceUnsupported, ImportExportCodes::FormatFeaturesUnsupported, KisMetaData::Store::getEntry(), KoID::id(), KisBaseNode::image, image(), KoColorProfile::info, KisMetadataBackendRegistry::instance(), KoColorSpaceRegistry::instance(), Integer8BitsColorDepthID, KoColorConversionTransformation::internalConversionFlags(), KoColorConversionTransformation::internalRenderingIntent(), KoColorProfile::isSuitableForOutput(), KoColorTransformation::isValid(), KisMetaData::IOBackend::loadFrom(), m_d, M_PI, KisLayer::metaData(), KisTransformWorker::mirrorX(), KisTransformWorker::mirrorY(), KoColorProfile::name, ImportExportCodes::OK, KisPaintLayer::paintDevice, photoshopMarker, POINT_TO_INCH(), quint8_MAX, read_icc_profile(), KisImage::rootLayer(), KisImage::rotateImage(), KisJPEGSource::setSource(), KisMetaData::Value::setVariant(), KoColorTransformation::transform(), KisMetaData::Value::type(), KisMetaData::Entry::value(), KoGenericRegistry< T >::value(), KisMetaData::Value::Variant, warnFile, and xmpMarker.

◆ image()

KisImageSP KisJPEGConverter::image ( )

Retrieve the constructed image

Definition at line 450 of file kis_jpeg_converter.cc.

451{
452 return m_d->image;
453}

References m_d.

Member Data Documentation

◆ m_d

QScopedPointer<Private> KisJPEGConverter::m_d
private

Definition at line 69 of file kis_jpeg_converter.h.


The documentation for this class was generated from the following files: