Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_webp_export.cpp
Go to the documentation of this file.
1/*
2 * This file is part of Krita
3 *
4 * SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#include <kpluginfactory.h>
10#include <webp/encode.h>
11#include <webp/mux.h>
12#include <webp/mux_types.h>
13
14#include <QBuffer>
15
16#include <cmath>
17#include <memory>
18
19#include <KisDocument.h>
24#include <KoColorProfile.h>
25#include <KoColorSpace.h>
27#include <kis_debug.h>
29#include <kis_image.h>
31#include <kis_layer_utils.h>
33#include <kis_paint_device.h>
34#include <kis_paint_layer.h>
37#include <kis_time_span.h>
38
40#include "kis_webp_export.h"
41
42K_PLUGIN_FACTORY_WITH_JSON(KisWebPExportFactory, "krita_webp_export.json", registerPlugin<KisWebPExport>();)
43
44KisWebPExport::KisWebPExport(QObject *parent, const QVariantList &)
45 : KisImportExportFilter(parent)
46{
47}
48
50
51KisPropertiesConfigurationSP KisWebPExport::defaultConfiguration(const QByteArray & /*from*/, const QByteArray & /*to*/) const
52{
54 WebPConfig preset {};
55
56 if (!WebPConfigInit(&preset)) {
57 return cfg;
58 }
59
60 if (!WebPConfigLosslessPreset(&preset, 6)) {
61 return cfg;
62 }
63
64 preset.thread_level = 1;
65
66 if (!WebPValidateConfig(&preset)) {
67 return cfg;
68 }
69
70 cfg->setProperty("haveAnimation", true);
71
72 cfg->setProperty("preset", 0);
73 cfg->setProperty("lossless", preset.lossless == 1);
74 cfg->setProperty("quality", preset.quality);
75 cfg->setProperty("method", preset.method);
76 cfg->setProperty("dithering", true);
77 cfg->setProperty("force_srgb", false);
78 cfg->setProperty("save_profile", true);
79
80 cfg->setProperty("target_size", preset.target_size);
81 cfg->setProperty("target_PSNR", preset.target_PSNR);
82 cfg->setProperty("segments", preset.segments);
83 cfg->setProperty("sns_strength", preset.sns_strength);
84 cfg->setProperty("filter_strength", preset.filter_strength);
85 cfg->setProperty("filter_sharpness", preset.filter_sharpness);
86 cfg->setProperty("filter_type", preset.filter_type);
87 cfg->setProperty("autofilter", preset.autofilter == 1);
88 cfg->setProperty("alpha_compression", preset.alpha_compression);
89 cfg->setProperty("alpha_filtering", preset.alpha_filtering);
90 cfg->setProperty("alpha_quality", preset.alpha_quality);
91 cfg->setProperty("pass", preset.pass);
92 cfg->setProperty("show_compressed", preset.show_compressed == 1);
93 cfg->setProperty("preprocessing", preset.preprocessing);
94 cfg->setProperty("partitions", preset.partitions);
95 cfg->setProperty("partition_limit", preset.partition_limit);
96 cfg->setProperty("emulate_jpeg_size", preset.emulate_jpeg_size == 1);
97 cfg->setProperty("thread_level", preset.thread_level > 0);
98 cfg->setProperty("low_memory", preset.low_memory == 1);
99 cfg->setProperty("near_lossless", preset.near_lossless);
100 cfg->setProperty("exact", preset.exact == 1);
101 cfg->setProperty("use_sharp_yuv", preset.use_sharp_yuv == 1);
102#if WEBP_ENCODER_ABI_VERSION >= 0x020f
103 cfg->setProperty("qmin", preset.qmin);
104 cfg->setProperty("qmax", preset.qmax);
105#endif
106
107 cfg->setProperty("exif", true);
108 cfg->setProperty("xmp", true);
109 cfg->setProperty("iptc", true);
110 cfg->setProperty("storeMetaData", false);
111 cfg->setProperty("filters", "");
112
113 return cfg;
114}
115
116KisConfigWidget *KisWebPExport::createConfigurationWidget(QWidget *parent, const QByteArray & /*from*/, const QByteArray & /*to*/) const
117{
118 return new KisWdgOptionsWebP(parent);
119}
120
121// RAII a WebPPicture.
124 : picture()
125 {
126 }
127
128 WebPPicture *get()
129 {
130 return &picture;
131 }
132
134 {
135 WebPPictureFree(&picture);
136 }
137
138 WebPPicture picture{};
139};
140
142{
143 using WebPMuxSP = std::unique_ptr<WebPMux, decltype(&WebPMuxDelete)>;
144 using WebPAnimEncoderSP =
145 std::unique_ptr<WebPAnimEncoder, decltype(&WebPAnimEncoderDelete)>;
146
149
150 KisImageSP image = document->savingImage();
151 const QRect bounds = document->savingImage()->bounds();
152 const KoColorSpace *cs =
153 document->savingImage()->projection()->colorSpace();
154
155 const bool needSrgbConversion = [&]() {
156 if (!cfg->getBool("force_srgb", false)) {
157 return false;
158 }
159
160 if (cs->colorModelId() != RGBAColorModelID) {
161 return true;
162 }
163
164 const bool hasPrimaries = cs->profile()->hasColorants();
166 if (hasPrimaries) {
167 const ColorPrimaries primaries = cs->profile()->getColorPrimaries();
168 if (gamma == TRC_IEC_61966_2_1 && primaries == PRIMARIES_ITU_R_BT_709_5) {
169 return false;
170 }
171 }
172 return true;
173 }();
174
175 // Then comes the animation chunk.
176 WebPData imageChunk = {nullptr, 0};
177
178 {
179 WebPAnimEncoderOptions encodingOptions;
180 if (!WebPAnimEncoderOptionsInit(&encodingOptions)) {
181 errFile << "WebP animation configuration initialization failure";
183 }
184
185 if (cfg->getBool("lossless", true)) {
186 encodingOptions.allow_mixed = false;
187 } else {
188 encodingOptions.allow_mixed = true;
189 }
190 encodingOptions.verbose = true;
191 // XXX: should we implement background selection as in JPEG?
192 encodingOptions.anim_params.loop_count = 0;
193
194 WebPAnimEncoderSP enc(WebPAnimEncoderNew(bounds.width(),
195 bounds.height(),
196 &encodingOptions),
197 &WebPAnimEncoderDelete);
198
199 WebPConfig config;
200 {
201 if (!WebPConfigInit(&config)) {
202 errFile << "WebP config initialization failed!";
204 }
205
206 config.lossless = cfg->getBool("lossless", true) ? 1 : 0;
207 config.quality = cfg->getFloat("quality", 75.0);
208 config.method = cfg->getInt("method", 4);
209
210 config.target_size = cfg->getInt("target_size", 0);
211 config.target_PSNR = cfg->getFloat("target_PSNR", 0.0f);
212 config.segments = cfg->getInt("segments", 4);
213 config.sns_strength = cfg->getInt("sns_strength", 50);
214 config.filter_strength = cfg->getInt("filter_strength", 60);
215 config.filter_sharpness = cfg->getInt("filter_sharpness", 0);
216 config.filter_type = cfg->getInt("filter_type", 1);
217 config.autofilter = cfg->getBool("autofilter", false) ? 1 : 0;
218 config.alpha_compression = cfg->getInt("alpha_compression", 1);
219 config.alpha_filtering = cfg->getInt("alpha_filtering", 1);
220 config.alpha_quality = cfg->getInt("alpha_quality", 100);
221 config.pass = cfg->getInt("pass", 1);
222 config.show_compressed =
223 cfg->getBool("show_compressed", false) ? 1 : 0;
224 config.preprocessing = cfg->getInt("preprocessing", 0);
225 config.partitions = cfg->getInt("partitions", 0);
226 config.partition_limit = cfg->getInt("partition_limit", 0);
227 config.emulate_jpeg_size =
228 cfg->getBool("emulate_jpeg_size", false) ? 1 : 0;
229 config.thread_level = cfg->getBool("thread_level", false) ? 1 : 0;
230 config.low_memory = cfg->getBool("low_memory", false) ? 1 : 0;
231 config.near_lossless = cfg->getInt("near_lossless", 100);
232 config.exact = cfg->getBool("exact", false) ? 1 : 0;
233 config.use_sharp_yuv = cfg->getBool("use_sharp_yuv", false) ? 1 : 0;
234#if WEBP_ENCODER_ABI_VERSION >= 0x020f
235 config.qmin = cfg->getInt("qmin", 0);
236 config.qmax = cfg->getInt("qmax", 100);
237#endif
238
239 if (!WebPValidateConfig(&config)) {
240 errFile << "WebP configuration validation failure";
242 }
243 }
244
245 const bool enableDithering = cfg->getBool("dithering", true);
246
247 const bool isAnimated = [&]() {
248 if (image->animationInterface()->hasAnimation() && cfg->getBool("haveAnimation", true)) {
249 KisLayerUtils::flattenImage(image, nullptr);
250 image->waitForDone();
251
252 const KisNodeSP projection = image->rootLayer()->firstChild();
253 return projection->isAnimated() && projection->hasEditablePaintDevice();
254 }
255 return false;
256 }();
257
258 if (isAnimated) {
259 // Flatten the image, projections don't have keyframes.
260 KisLayerUtils::flattenImage(image, nullptr);
261 image->waitForDone();
262
263 const KisNodeSP projection = image->rootLayer()->firstChild();
264 if (!projection->isAnimated()) return ImportExportCodes::InternalError;
265
266 const KisRasterKeyframeChannel *frames =
267 projection->paintDevice()->keyframeChannel();
268 const auto times = [&]() -> QList<int> {
269 QList<int> t;
270 QSet<int> s = frames->allKeyframeTimes();
271 t = QList<int>(s.begin(), s.end());
272 std::sort(t.begin(), t.end());
273 return t;
274 }();
275
276 // If this is not an integral number, it must be diagnosed on
277 // export and reported to the user.
278 // THE FRAME DURATION WILL BE ROUNDED.
279 const int duration =
280 std::lround(1000.0
281 / static_cast<double>(
282 image->animationInterface()->framerate()));
283
284 for (const int i : times) {
285 const int timestamp_ms = i * duration;
286
287 WebPPictureSP currentFrame;
288 if (!WebPPictureInit(currentFrame.get())) {
289 errFile << "WebP picture initialization failure";
291 }
292
293 currentFrame.get()->width = bounds.width();
294 currentFrame.get()->height = bounds.height();
295
296 // Use ARGB in lossless mode
297 if (config.lossless == 1) {
298 currentFrame.get()->use_argb = 1;
299 }
300
301 const QImage pixels = [&]() {
302 const KisRasterKeyframeSP frameData =
303 frames->keyframeAt<KisRasterKeyframe>(i);
305 *image->projection(),
307 frameData->writeFrameToDevice(dev);
308
311 || !enableDithering) {
312 dst = dev;
313 } else {
314 // We need to use gradient painter code's:
315 // to convert to RGBA samedepth;
316 // then dither to RGBA8
317 // then convert from ARGB32 to RGBA8888
318 const KisPaintDeviceSP src = dev;
319 const KoID depthId = src->colorSpace()->colorDepthId();
321 if (cs->colorModelId() == RGBAColorModelID && !needSrgbConversion) {
322 // Preserve color profile if model is RGB and force convert sRGB is off
325 src->colorSpace()->profile());
326 }
328 depthId.id(),
329 destCs->profile());
330
332 tmp->convertTo(mixCs);
333 dst = new KisPaintDevice(destCs);
334
335 const KisDitherOp *op =
336 mixCs->ditherOp(destCs->colorDepthId().id(), enableDithering ? DITHER_BEST : DITHER_NONE);
337
338 KisRandomConstAccessorSP srcIt = tmp->createRandomConstAccessorNG();
340
341 int rows = 1;
342 int columns = 1;
343
344 for (int y = bounds.y(); y <= bounds.bottom(); y += rows) {
345 rows = qMin(srcIt->numContiguousRows(y),
346 qMin(dstIt->numContiguousRows(y), bounds.bottom() - y + 1));
347
348 for (int x = bounds.x(); x <= bounds.right(); x += columns) {
349 columns = qMin(srcIt->numContiguousColumns(x),
350 qMin(dstIt->numContiguousColumns(x), bounds.right() - x + 1));
351
352 srcIt->moveTo(x, y);
353 dstIt->moveTo(x, y);
354
355 const qint32 srcRowStride = srcIt->rowStride(x, y);
356 const qint32 dstRowStride = dstIt->rowStride(x, y);
357 const quint8 *srcPtr = srcIt->rawDataConst();
358 quint8 *dstPtr = dstIt->rawData();
359
360 op->dither(srcPtr, srcRowStride, dstPtr, dstRowStride, x, y, columns, rows);
361 }
362 }
363 }
364
365 // Convert to sRGB for non-RGBA color model
366 const KoColorProfile *imageProfile = (dst->colorSpace()->colorModelId() == RGBAColorModelID)
367 ? dst->colorSpace()->profile()
368 : nullptr;
369
370 if (needSrgbConversion) {
372 }
373
374 const QImage imageOut = dst->convertToQImage(imageProfile, 0, 0, bounds.width(), bounds.height())
375 .convertToFormat(QImage::Format_RGBA8888);
376
377 return imageOut;
378 }();
379
380 if (!WebPPictureImportRGBA(currentFrame.get(),
381 pixels.constBits(),
382 bounds.width() * 4)) {
383 errFile << "WebP picture conversion failure:"
384 << currentFrame.get()->error_code;
386 }
387
388 WebPMemoryWriter writer;
389 WebPMemoryWriterInit(&writer);
390 currentFrame.get()->writer = WebPMemoryWrite;
391 currentFrame.get()->custom_ptr = &writer;
392
393 if (!WebPEncode(&config, currentFrame.get())) {
394 errFile << "WebP encoding failure:"
395 << currentFrame.get()->error_code;
397 }
398
399 if (!WebPAnimEncoderAdd(enc.get(),
400 currentFrame.get(),
401 timestamp_ms,
402 &config)) {
403 errFile << "WebPAnimEncoderAdd failed";
405 }
406
407 dbgFile << "Added frame @" << i << timestamp_ms << "ms";
408 }
409
410 const int timestamp_ms =
412 * (1000 / image->animationInterface()->framerate());
413
414 // Insert the finish beacon.
415 WebPAnimEncoderAdd(enc.get(), nullptr, timestamp_ms, nullptr);
416
417 dbgFile << "Animation finished @" << timestamp_ms << "ms";
418 } else {
419 WebPPictureSP currentFrame;
420 if (!WebPPictureInit(currentFrame.get())) {
421 errFile << "WebP picture initialization failure";
423 }
424
425 currentFrame.get()->width = bounds.width();
426 currentFrame.get()->height = bounds.height();
427
428 // Use ARGB in lossless mode
429 if (config.lossless == 1) {
430 currentFrame.get()->use_argb = 1;
431 }
432
433 // Insert the projection itself only
434 const QImage pixels = [&]() {
437 || !enableDithering) {
438 dst = document->savingImage()->projection();
439 } else {
440 // We need to use gradient painter code's:
441 // to convert to RGBA samedepth;
442 // then dither to RGBA8
443 // then convert from ARGB32 to RGBA8888
444 const KisPaintDeviceSP src = document->savingImage()->projection();
445 const KoID depthId = src->colorSpace()->colorDepthId();
447 if (cs->colorModelId() == RGBAColorModelID && !needSrgbConversion) {
448 // Preserve color profile if model is RGB and force convert sRGB is off
451 src->colorSpace()->profile());
452 }
454 depthId.id(),
455 destCs->profile());
456
458 tmp->convertTo(mixCs);
459 dst = new KisPaintDevice(destCs);
460
461 const KisDitherOp *op =
462 mixCs->ditherOp(destCs->colorDepthId().id(), enableDithering ? DITHER_BEST : DITHER_NONE);
463
464 KisRandomConstAccessorSP srcIt = tmp->createRandomConstAccessorNG();
466
467 int rows = 1;
468 int columns = 1;
469
470 for (int y = bounds.y(); y <= bounds.bottom(); y += rows) {
471 rows = qMin(srcIt->numContiguousRows(y),
472 qMin(dstIt->numContiguousRows(y), bounds.bottom() - y + 1));
473
474 for (int x = bounds.x(); x <= bounds.right(); x += columns) {
475 columns = qMin(srcIt->numContiguousColumns(x),
476 qMin(dstIt->numContiguousColumns(x), bounds.right() - x + 1));
477
478 srcIt->moveTo(x, y);
479 dstIt->moveTo(x, y);
480
481 const qint32 srcRowStride = srcIt->rowStride(x, y);
482 const qint32 dstRowStride = dstIt->rowStride(x, y);
483 const quint8 *srcPtr = srcIt->rawDataConst();
484 quint8 *dstPtr = dstIt->rawData();
485
486 op->dither(srcPtr, srcRowStride, dstPtr, dstRowStride, x, y, columns, rows);
487 }
488 }
489 }
490
491 // Convert to sRGB for non-RGBA color model
492 const KoColorProfile *imageProfile = (dst->colorSpace()->colorModelId() == RGBAColorModelID)
493 ? dst->colorSpace()->profile()
494 : nullptr;
495
496 if (needSrgbConversion) {
498 }
499
500 const QImage imageOut = dst->convertToQImage(imageProfile, 0, 0, bounds.width(), bounds.height())
501 .convertToFormat(QImage::Format_RGBA8888);
502
503 return imageOut;
504 }();
505
506 if (!WebPPictureImportRGBA(currentFrame.get(),
507 pixels.constBits(),
508 bounds.width() * 4)) {
509 errFile << "WebP picture conversion failure:"
510 << currentFrame.get()->error_code;
512 }
513
514 WebPMemoryWriter writer;
515 WebPMemoryWriterInit(&writer);
516 currentFrame.get()->writer = WebPMemoryWrite;
517 currentFrame.get()->custom_ptr = &writer;
518
519 if (!WebPEncode(&config, currentFrame.get())) {
520 errFile << "WebP encoding failure:"
521 << currentFrame.get()->error_code;
523 }
524
525 if (!WebPAnimEncoderAdd(enc.get(),
526 currentFrame.get(),
527 0,
528 &config)) {
529 errFile << "WebPAnimEncoderAdd failed";
531 }
532 }
533
534 WebPAnimEncoderAssemble(enc.get(), &imageChunk);
535 };
536
537 // Don't copy this data, it's the biggest chunk.
538 WebPMuxSP mux(WebPMuxCreate(&imageChunk, 0), &WebPMuxDelete);
539
540 if (!mux) {
541 errFile << "WebP mux initialization failure";
543 }
544
545 // According to the standard, the ICC profile must be written first.
546 if (cfg->getBool("save_profile", true)) {
547 const QByteArray profile = needSrgbConversion
549 : image->profile()->rawData();
550
551 WebPData iccChunk = {reinterpret_cast<const uint8_t *>(profile.data()),
552 static_cast<size_t>(profile.size())};
553
554 // This data will die at the end of the scope.
555 if (WEBP_MUX_OK != WebPMuxSetChunk(mux.get(), "ICCP", &iccChunk, 1)) {
556 errFile << "WebPMuxSetChunk for the ICC profile failed";
558 }
559 }
560
561 if (cfg->getBool("storeMetaData", false)) {
562 auto metaDataStore = [&]() -> std::unique_ptr<KisMetaData::Store> {
563 KisExifInfoVisitor exivInfoVisitor;
564 exivInfoVisitor.visit(image->rootLayer().data());
565 if (exivInfoVisitor.metaDataCount() == 1) {
566 return std::make_unique<KisMetaData::Store>(
567 *exivInfoVisitor.exifInfo());
568 } else {
569 return {};
570 }
571 }();
572
573 if (metaDataStore && !metaDataStore->isEmpty()) {
575 model.setEnabledFilters(cfg->getString("filters").split(","));
576 metaDataStore->applyFilters(model.enabledFilters());
577 }
578
579 if (metaDataStore && cfg->getBool("exif", true)) {
580 const KisMetaData::IOBackend *io =
582
583 QBuffer ioDevice;
584
585 // Inject the data as any other IOBackend
586 io->saveTo(metaDataStore.get(), &ioDevice);
587
588 WebPData xmp = {
589 reinterpret_cast<const uint8_t *>(ioDevice.data().constData()),
590 static_cast<size_t>(ioDevice.data().size())};
591
592 // This data will die at the end of the scope.
593 if (WEBP_MUX_OK != WebPMuxSetChunk(mux.get(), "EXIF", &xmp, 1)) {
594 errFile << "WebPMuxSetChunk for EXIF failed";
596 }
597 }
598
599 if (metaDataStore && cfg->getBool("xmp", true)) {
600 const KisMetaData::IOBackend *io =
602
603 QBuffer ioDevice;
604
605 // Inject the data as any other IOBackend
606 io->saveTo(metaDataStore.get(), &ioDevice);
607
608 WebPData xmp = {
609 reinterpret_cast<const uint8_t *>(ioDevice.data().constData()),
610 static_cast<size_t>(ioDevice.data().size())};
611
612 // This data will die at the end of the scope.
613 if (WEBP_MUX_OK != WebPMuxSetChunk(mux.get(), "XMP ", &xmp, 1)) {
614 errFile << "WebPMuxSetChunk for XMP failed";
616 }
617 }
618 }
619
620 WebPData output;
621 WebPMuxAssemble(mux.get(), &output);
622 QDataStream s(io);
623 s.setByteOrder(QDataStream::LittleEndian);
624 s.writeRawData(reinterpret_cast<const char *>(output.bytes),
625 static_cast<int>(output.size));
626 WebPDataClear(&output);
627
629}
630
632{
634 ->get("AnimationCheck")
637 ->get("IntegralFrameDurationCheck")
640 ->get("sRGBProfileCheck")
643 ->get("ExifCheck")
646 ->get("MultiLayerCheck")
649 ->get("TiffExifCheck")
651 // XXX: add check for IPTC metadata and mark as UNSUPPORTED by the standard.
652 QList<QPair<KoID, KoID>> supportedColorModels;
653 supportedColorModels << QPair<KoID, KoID>() << QPair<KoID, KoID>(RGBAColorModelID, Integer8BitsColorDepthID);
654 addSupportedColorModels(supportedColorModels, "WebP");
655}
656
657#include "kis_webp_export.moc"
@ DITHER_NONE
Definition KisDitherOp.h:22
@ DITHER_BEST
Definition KisDitherOp.h:24
VertexDescriptor get(PredecessorMap const &m, VertexDescriptor v)
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
ColorPrimaries
The colorPrimaries enum Enum of colorants, follows ITU H.273 for values 0 to 255, and has extra known...
@ PRIMARIES_ITU_R_BT_709_5
TransferCharacteristics
The transferCharacteristics enum Enum of transfer characteristics, follows ITU H.273 for values 0 to ...
@ TRC_IEC_61966_2_1
virtual quint8 * rawData()=0
virtual const quint8 * rawDataConst() const =0
virtual void dither(const quint8 *src, quint8 *dst, int x, int y) const =0
The KisExifInfoVisitor class looks for a layer with metadata.
KisMetaData::Store * exifInfo()
bool visit(KisNode *) override
static KisExportCheckRegistry * instance()
const KisTimeSpan & documentPlaybackRange() const
documentPlaybackRange
void waitForDone()
KisGroupLayerSP rootLayer() const
KisImageAnimationInterface * animationInterface() const
KisPaintDeviceSP projection() const
QRect bounds() const override
const KoColorProfile * profile() const
The base class for import and export filters.
void addSupportedColorModels(QList< QPair< KoID, KoID > > supportedColorModels, const QString &name, KisExportCheckBase::Level level=KisExportCheckBase::PARTIALLY)
void addCapability(KisExportCheckBase *capability)
QSet< int > allKeyframeTimes() const
Get a set of all integer times that map to a keyframe.
KisKeyframeSP keyframeAt(int time) const
Get a keyframe at specified time. Used primarily when the value of a given keyframe is needed.
virtual void setEnabledFilters(const QStringList &enabledFilters)
enable the filters in the given list; others will be disabled.
virtual bool saveTo(const Store *store, QIODevice *ioDevice, HeaderType headerType=NoHeader) const =0
static KisMetadataBackendRegistry * instance()
KisRasterKeyframeChannel * keyframeChannel() const
const KoColorSpace * colorSpace() const
QImage convertToQImage(const KoColorProfile *dstProfile, qint32 x, qint32 y, qint32 w, qint32 h, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags()) const
KisRandomAccessorSP createRandomAccessorNG()
virtual qint32 rowStride(qint32 x, qint32 y) const =0
virtual qint32 numContiguousRows(qint32 y) const =0
virtual void moveTo(qint32 x, qint32 y)=0
virtual qint32 numContiguousColumns(qint32 x) const =0
The KisRasterKeyframeChannel is a concrete KisKeyframeChannel subclass that stores and manages KisRas...
The KisRasterKeyframe class is a concrete subclass of KisKeyframe that wraps a physical raster image ...
int end() const
~KisWebPExport() override
KisWebPExport(QObject *parent, const QVariantList &)
KisConfigWidget * createConfigurationWidget(QWidget *parent, const QByteArray &from="", const QByteArray &to="") const override
createConfigurationWidget creates a widget that can be used to define the settings for a given import...
KisPropertiesConfigurationSP defaultConfiguration(const QByteArray &from, const QByteArray &to) const override
defaultConfiguration defines the default settings for the given import export filter
void initializeCapabilities() override
KisImportExportErrorCode convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP configuration=0) override
virtual const KisDitherOp * ditherOp(const QString &depth, DitherType type) const
virtual KoID colorModelId() const =0
virtual KoID colorDepthId() const =0
virtual const KoColorProfile * profile() const =0
const T value(const QString &id) const
Definition KoID.h:30
QString id() const
Definition KoID.cpp:63
K_PLUGIN_FACTORY_WITH_JSON(KritaASCCDLFactory, "kritaasccdl.json", registerPlugin< KritaASCCDL >();) KritaASCCDL
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define bounds(x, a, b)
#define errFile
Definition kis_debug.h:115
#define dbgFile
Definition kis_debug.h:53
void flattenImage(KisImageSP image, KisNodeSP activeNode, MergeFlags flags)
bool isAnimated() const
virtual KisPaintDeviceSP paintDevice() const =0
bool hasEditablePaintDevice() const
KisNodeSP firstChild() const
Definition kis_node.cpp:361
virtual QByteArray rawData() const
virtual ColorPrimaries getColorPrimaries() const
getColorPrimaries
virtual bool hasColorants() const =0
virtual TransferCharacteristics getTransferCharacteristics() const
getTransferCharacteristics This function should be subclassed at some point so we can get the value f...
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()
const KoColorProfile * p709SRGBProfile() const
const KoColorSpace * rgb8(const QString &profileName=QString())
WebPPicture picture
WebPPicture * get()