Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_jpeg_converter.cc
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2005 Cyrille Berger <cberger@cberger.net>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
7
8#include <stdio.h>
9#include <stdint.h>
10
11#include <KoConfig.h>
12#ifdef HAVE_LCMS2
13# include <lcms2.h>
14#else
15# include <lcms.h>
16#endif
17
18extern "C" {
19#include <iccjpeg.h>
20}
21
22#include <exiv2/jpgimage.hpp>
23#include <exiv2/version.hpp>
24#if EXIV2_TEST_VERSION(0,28,0)
25#include <exiv2/photoshop.hpp>
26#endif
27
28#include <QFile>
29#include <QBuffer>
30#include <QApplication>
31
32#include <klocalizedstring.h>
33
34#include <KoDocumentInfo.h>
35#include <KoColorSpace.h>
37#include <KoColorProfile.h>
38#include <KoColor.h>
39#include <KoUnit.h>
41
42#include <KisDocument.h>
43#include <kis_group_layer.h>
44#include <kis_image.h>
45#include <kis_iterator_ng.h>
47#include <kis_jpeg_source.h>
49#include <kis_meta_data_entry.h>
50#include <kis_meta_data_store.h>
51#include <kis_meta_data_value.h>
52#include <kis_paint_device.h>
53#include <kis_paint_layer.h>
54#include <kis_painter.h>
55#include <kis_transaction.h>
57
58#define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */
59#define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */
60#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */
61#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
62
63const char photoshopMarker[] = "Photoshop 3.0\0";
64//const char photoshopBimId_[] = "8BIM";
65const uint16_t photoshopIptc = 0x0404;
66const char xmpMarker[] = "http://ns.adobe.com/xap/1.0/\0";
67const QByteArray photoshopIptc_((char*)&photoshopIptc, 2);
68
69namespace
70{
71
72void jpegErrorExit (j_common_ptr cinfo)
73{
74 char jpegLastErrorMsg[JMSG_LENGTH_MAX];
75
76 ( *( cinfo->err->format_message ) ) ( cinfo, jpegLastErrorMsg );
77
78 throw std::runtime_error(jpegLastErrorMsg);
79}
80
81J_COLOR_SPACE getColorTypeforColorSpace(const KoColorSpace * cs)
82{
83 if (KoID(cs->id()) == KoID("GRAYA") || cs->id() == "GRAYAU16" || cs->id() == "GRAYA16") {
84 return JCS_GRAYSCALE;
85 }
86 if (KoID(cs->id()) == KoID("RGBA") || KoID(cs->id()) == KoID("RGBA16")) {
87 return JCS_RGB;
88 }
89 if (KoID(cs->id()) == KoID("CMYK") || KoID(cs->id()) == KoID("CMYKAU16")) {
90 return JCS_CMYK;
91 }
92 return JCS_UNKNOWN;
93}
94
95QString getColorSpaceModelForColorType(J_COLOR_SPACE color_type)
96{
97 dbgFile << "color_type =" << color_type;
98 if (color_type == JCS_GRAYSCALE) {
99 return GrayAColorModelID.id();
100 } else if (color_type == JCS_RGB) {
101 return RGBAColorModelID.id();
102 } else if (color_type == JCS_CMYK) {
103 return CMYKAColorModelID.id();
104 }
105 return "";
106}
107
108}
109
123
125 : m_d(new Private(doc, batchMode))
126{
127}
128
132
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}
441
442
443
445{
446 return decode(io);
447}
448
449
451{
452 return m_d->image;
453}
454
455
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}
728
729
731{
732 m_d->stop = true;
733}
734
735
const KoID GrayAColorModelID("GRAYA", ki18n("Grayscale/Alpha"))
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const KoID CMYKAColorModelID("CMYKA", ki18n("CMYK/Alpha"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
unsigned int uint
constexpr qreal POINT_TO_INCH(qreal px)
Definition KoUnit.h:37
constexpr qreal INCH_TO_POINT(qreal inch)
Definition KoUnit.h:38
virtual const quint8 * oldRawData() const =0
virtual bool nextPixel()=0
KisGroupLayerSP rootLayer() const
void rotateImage(double radians)
start asynchronous operation on rotating the image
qint32 width() const
double xRes() const
double yRes() const
qint32 height() const
KisImportExportErrorCode buildImage(QIODevice *io)
QScopedPointer< Private > m_d
KisJPEGConverter(KisDocument *doc, bool batchMode=false)
KisImportExportErrorCode buildFile(QIODevice *io, KisPaintLayerSP layer, KisJPEGOptions options, KisMetaData::Store *metaData)
KisImportExportErrorCode decode(QIODevice *io)
const KisMetaData::Value & value() const
@ JpegHeader
Append Jpeg-style header.
virtual bool loadFrom(Store *store, QIODevice *ioDevice) const =0
virtual bool saveTo(const Store *store, QIODevice *ioDevice, HeaderType headerType=NoHeader) const =0
void applyFilters(const QList< const Filter * > &filters)
bool containsEntry(const QString &entryKey) const
Entry & getEntry(const QString &entryKey)
QVariant asVariant() const
bool setVariant(const QVariant &variant)
ValueType type() const
static KisMetadataBackendRegistry * instance()
quint32 pixelSize() const
quint32 channelCount() const
KisHLineIteratorSP createHLineIteratorNG(qint32 x, qint32 y, qint32 w)
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
void bitBlt(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight)
static void mirrorY(KisPaintDeviceSP dev, qreal axis)
static void mirrorX(KisPaintDeviceSP dev, qreal axis)
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
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
const T value(const QString &id) const
Definition KoID.h:30
QString id() const
Definition KoID.cpp:63
boolean read_icc_profile(j_decompress_ptr cinfo, JOCTET **icc_data_ptr, unsigned int *icc_data_len)
Definition iccjpeg.c:187
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 warnFile
Definition kis_debug.h:95
#define dbgFile
Definition kis_debug.h:53
const quint8 quint8_MAX
Definition kis_global.h:24
#define M_PI
Definition kis_global.h:111
const char xmpMarker[]
const uint16_t photoshopIptc
const char photoshopMarker[]
const QByteArray photoshopIptc_((char *)&photoshopIptc, 2)
KisSharedPtr< KisPaintLayer > KisPaintLayerSP
KisSharedPtr< KisImage > KisImageSP
Definition kis_types.h:69
KisSharedPtr< KisNode > KisNodeSP
Definition kis_types.h:86
void setDestination(j_compress_ptr cinfo, QIODevice *destinationDevice)
void setSource(j_decompress_ptr cinfo, QIODevice *inputDevice)
KisImageWSP image
Private(KisDocument *doc, bool batchMode)
QList< const KisMetaData::Filter * > filters
KisMetaData::Store * metaData()
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 bool isSuitableForOutput() const =0
virtual QByteArray rawData() const
QString colorSpaceId(const QString &colorModelId, const QString &colorDepthId) const
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()
const KoColorSpace * rgb8(const QString &profileName=QString())
const KoColorProfile * createColorProfile(const QString &colorModelId, const QString &colorDepthId, const QByteArray &rawData)