Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_paint_device.cc
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2002 Patrick Julien <freak@codepimps.org>
3 * SPDX-FileCopyrightText: 2004 Boudewijn Rempt <boud@valdyas.org>
4 * SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#include "kis_paint_device.h"
10
11#include <QRect>
12#include <QImage>
13#include <QList>
14#include <QHash>
15#include <QMutex>
16#include <QMutexLocker>
17#include <QIODevice>
18#include <qmath.h>
19#include <KisRegion.h>
20
21#include <klocalizedstring.h>
22
23#include <KoChannelInfo.h>
24#include <KoColorProfile.h>
25#include <KoColor.h>
26#include <KoColorSpace.h>
29#include <KoIntegerMaths.h>
30#include <KoMixColorsOp.h>
31#include <KoUpdater.h>
32
33#include "kis_image.h"
35#include "kis_selection.h"
36#include "kis_node.h"
37#include "kis_datamanager.h"
40#include "kis_pixel_selection.h"
43
47
48#include "kis_default_bounds.h"
49
50#include "kis_lod_transform.h"
51
53
57
59#include "kis_filter_strategy.h"
60#include "krita_utils.h"
62
64 qRegisterMetaType<KisPaintDeviceSP>("KisPaintDeviceSP");
65}
66
68{
74
75public:
76
79
82
83 Private(KisPaintDevice *paintDevice);
84 ~Private();
85
88 QScopedPointer<KisRasterKeyframeChannel> contentChannel;
90 QScopedPointer<KisPaintDeviceStrategy> basicStrategy;
91 QScopedPointer<KisPaintDeviceWrappedStrategy> wrappedStrategy;
93
94 QScopedPointer<KisPaintDeviceFramesInterface> framesInterface;
97
99
100 void init(const KoColorSpace *cs, const quint8 *defaultPixel);
101 void convertColorSpace(const KoColorSpace *dstColorSpace,
103 KoColorConversionTransformation::ConversionFlags conversionFlags,
104 KUndo2Command *parentCommand,
105 KoUpdater *progressUpdater);
106 bool assignProfile(const KoColorProfile * profile, KUndo2Command *parentCommand);
107
109
110
111 inline const KoColorSpace* colorSpace() const
112 {
113 return currentData()->colorSpace();
114 }
116 {
117 return currentData()->dataManager();
118 }
119
120 inline qint32 x() const
121 {
122 return currentData()->x();
123 }
124 inline qint32 y() const
125 {
126 return currentData()->y();
127 }
128 inline void setX(qint32 x)
129 {
130 currentData()->setX(x);
131 }
132 inline void setY(qint32 y)
133 {
134 currentData()->setY(y);
135 }
136
138 {
139 return currentData()->cache();
140 }
141
145
147 return currentData()->interstrokeData();
148 }
149
152 }
153
154 void cloneAllDataObjects(Private *rhs, bool copyFrames)
155 {
157 m_lodData.reset();
158 m_externalFrameData.reset();
159
160 if (!m_frames.isEmpty()) {
161 m_frames.clear();
162 }
163
164 if (!copyFrames) {
165 if (m_data) {
166 m_data->prepareClone(rhs->currentNonLodData(), true);
167 } else {
169 }
170 } else {
171 if (m_data && !rhs->m_data) {
172 m_data.clear();
173 } else if (!m_data && rhs->m_data) {
174 m_data = toQShared(new KisPaintDeviceData(q, rhs->m_data.data(), true));
175 } else if (m_data && rhs->m_data) {
176 m_data->prepareClone(rhs->m_data.data(), true);
177 }
178
179 if (!rhs->m_frames.isEmpty()) {
180 FramesHash::const_iterator it = rhs->m_frames.constBegin();
181 FramesHash::const_iterator end = rhs->m_frames.constEnd();
182
183 for (; it != end; ++it) {
184 DataSP data = toQShared(new KisPaintDeviceData(q, it.value().data(), true));
185 m_frames.insert(it.key(), data);
186 }
187 }
189 }
190
191 if (rhs->m_lodData) {
192 m_lodData.reset(new KisPaintDeviceData(q, rhs->m_lodData.data(), true));
194 }
195
197 {
198 prepareCloneImpl(src, src->m_d->currentData());
200 }
201
203 {
204 return fastBitBltPossibleImpl(src->m_d->currentData());
205 }
206
207 int currentFrameId() const
208 {
210 return -1;
211 }
213 contentChannel->activeKeyframeAt<KisRasterKeyframe>(defaultBounds->currentTime())->frameID() :
214 -1;
216
218 {
219 DataSP data = m_frames[frameId];
220 return data->dataManager();
221 }
222
223 void invalidateFrameCache(int frameId)
224 {
225 DataSP data = m_frames[frameId];
226 return data->cache()->invalidate();
227 }
228
229private:
232 typedef QHash<int, DataSP> FramesHash;
233
235 {
236 public:
237
238 FrameInsertionCommand(FramesHash *hash, DataSP data, int frameId, bool insert, KUndo2Command *parentCommand)
239 : KUndo2Command(parentCommand),
240 m_hash(hash),
241 m_data(data),
242 m_frameId(frameId),
243 m_insert(insert)
244 {
245 }
246
247 void redo() override
248 {
250 }
251
252 void undo() override
253 {
255 }
256
257 private:
258 void doSwap(bool insert)
259 {
260 if (insert) {
261 m_hash->insert(m_frameId, m_data);
262 } else {
263 DataSP deletedData = m_hash->take(m_frameId);
264 }
265 }
266
267 private:
272 };
273
274public:
275
277 int frameId = 0;
278 while (m_frames.contains(frameId = m_nextFreeFrameId++));
279 KIS_SAFE_ASSERT_RECOVER_NOOP(!m_frames.contains(frameId));
280
281 return frameId;
282 }
283
284 int createFrame(bool copy, int copySrc, const QPoint &offset, KUndo2Command *parentCommand)
285 {
286 DataSP data;
287 bool initialFrame = false;
288
289 if (m_frames.isEmpty()) {
295 data = toQShared(new Data(q, m_data.data(), true));
296 m_data->dataManager()->clear();
297 m_data->cache()->invalidate();
298 initialFrame = true;
299
300 } else if (copy) {
301 DataSP srcData = m_frames[copySrc];
302 data = toQShared(new Data(q, srcData.data(), true));
303 } else {
304 DataSP srcData = m_frames.begin().value();
305 data = toQShared(new Data(q, srcData.data(), false));
306 }
307
308 if (!initialFrame && !copy) {
309 data->setX(offset.x());
310 data->setY(offset.y());
311 }
312
313 int frameId = getNextFrameId();
314
315 if (parentCommand) {
316 KUndo2Command *cmd =
318 data,
319 frameId, true,
320 parentCommand);
321
322 cmd->redo();
323 } else {
324 m_frames.insert(frameId, data);
325 }
326
327 return frameId;
328 }
329
330 void deleteFrame(int frameID, KUndo2Command *parentCommand)
331 {
332 KIS_SAFE_ASSERT_RECOVER_RETURN(m_frames.contains(frameID));
333 DataSP deletedData = m_frames[frameID];
334
335 if(parentCommand) {
336 KUndo2Command *cmd =
338 deletedData,
339 frameID, false,
340 parentCommand);
341 cmd->redo();
342 } else {
343 m_frames.take(frameID);
344 }
345 }
346
347 QRect frameBounds(int frameId)
348 {
349 DataSP data = m_frames[frameId];
350
351 QRect extent = data->dataManager()->extent();
352 extent.translate(data->x(), data->y());
353
354 quint8 defaultOpacity = data->colorSpace()->opacityU8(data->dataManager()->defaultPixel());
355
356 if (defaultOpacity != OPACITY_TRANSPARENT_U8) {
358 }
359
360 return extent;
361 }
362
363 QPoint frameOffset(int frameId) const
364 {
365 DataSP data = m_frames[frameId];
366 return QPoint(data->x(), data->y());
367 }
368
369 void setFrameOffset(int frameId, const QPoint &offset)
370 {
371 DataSP data = m_frames[frameId];
372 data->setX(offset.x());
373 data->setY(offset.y());
374 data->cache()->invalidate();
375 }
376
377 const QList<int> frameIds() const
378 {
379 return m_frames.keys();
380 }
381
382 bool readFrame(QIODevice *stream, int frameId)
383 {
384 bool retval = false;
385 DataSP data = m_frames[frameId];
386 retval = data->dataManager()->read(stream);
387 data->cache()->invalidate();
388 return retval;
389 }
390
391 bool writeFrame(KisPaintDeviceWriter &store, int frameId)
392 {
393 DataSP data = m_frames[frameId];
394 return data->dataManager()->write(store);
395 }
396
397 void setFrameDefaultPixel(const KoColor &defPixel, int frameId)
398 {
399 DataSP data = m_frames[frameId];
400 KoColor color(defPixel);
401 color.convertTo(data->colorSpace());
402 data->dataManager()->setDefaultPixel(color.data());
403 data->cache()->invalidate();
404 }
405
406 KoColor frameDefaultPixel(int frameId) const
407 {
408 DataSP data = m_frames[frameId];
409 return KoColor(data->dataManager()->defaultPixel(),
410 data->colorSpace());
411 }
412
413 void writeFrameToDevice(int frameId, KisPaintDeviceSP targetDevice);
414 void uploadFrame(int srcFrameId, int dstFrameId, KisPaintDeviceSP srcDevice);
415 void uploadFrame(int dstFrameId, KisPaintDeviceSP srcDevice);
416 void uploadFrameData(DataSP srcData, DataSP dstData);
417
418 struct LodDataStructImpl;
420 void updateLodDataStruct(LodDataStruct *dst, const QRect &srcRect);
423
424 void updateLodDataManager(KisDataManager *srcDataManager,
425 KisDataManager *dstDataManager, const QPoint &srcOffset, const QPoint &dstOffset,
426 const QRect &originalRect, int lod);
427
428 void generateLodCloneDevice(KisPaintDeviceSP dst, const QRect &originalRect, int lod);
429
430 void testingFetchLodDevice(KisPaintDeviceSP targetDevice);
431
432
433private:
434 qint64 estimateDataSize(Data *data) const {
435 const QRect &rc = data->dataManager()->extent();
436 return qint64(rc.width()) * rc.height() * data->colorSpace()->pixelSize();
437 }
438
439public:
440
441 void estimateMemoryStats(qint64 &imageData, qint64 &temporaryData, qint64 &lodData) const {
442 imageData = 0;
443 temporaryData = 0;
444 lodData = 0;
445
446 if (m_data) {
447 imageData += estimateDataSize(m_data.data());
448 }
449
450 if (m_lodData) {
451 lodData += estimateDataSize(m_lodData.data());
452 }
453
455 temporaryData += estimateDataSize(m_externalFrameData.data());
456 }
457
458 Q_FOREACH (DataSP value, m_frames.values()) {
459 imageData += estimateDataSize(value.data());
460 }
461 }
462
463
464private:
465
467 {
468 DataSP data;
469
470 const int vFramesCount = contentChannel->keyframeCount();
471
472 if (vFramesCount >= 1) {
474 if (!keyframe || keyframe->frameID() < 0) {
475 return m_data;
476 }
477
478 const int frameID = keyframe->frameID();
479 KIS_ASSERT_RECOVER(m_frames.contains(frameID)) {
480 return m_data;
481 }
482
483 data = m_frames[frameID];
484 } else {
485 data = m_data;
486 }
487
488 return data;
489 }
490
491 inline Data* currentNonLodData() const
492 {
493 Data *data = m_data.data();
494
495 if (contentChannel) {
496 data = currentFrameData().data();
498 if (!m_externalFrameData) {
499 QMutexLocker l(&m_dataSwitchLock);
500 if (!m_externalFrameData) {
501 m_externalFrameData.reset(new Data(q, m_data.data(), false));
502 }
503 }
504 data = m_externalFrameData.data();
505 }
506
507 return data;
508 }
509
510 inline void ensureLodDataPresent() const
511 {
512 if (!m_lodData) {
513 Data *srcData = currentNonLodData();
514
515 QMutexLocker l(&m_dataSwitchLock);
516 if (!m_lodData) {
517 m_lodData.reset(new Data(q, srcData, false));
518 }
519 }
520 }
521
522 inline Data* currentData() const
523 {
524 Data *data;
525
528 data = m_lodData.data();
529 } else {
530 data = currentNonLodData();
531 }
532
533 return data;
534 }
535
537 {
545 q->setDefaultBounds(src->defaultBounds());
546 q->setSupportsWraparoundMode(src->supportsWraproundMode());
547
548 currentData()->prepareClone(srcData);
549
550
557 KIS_SAFE_ASSERT_RECOVER_RETURN(*colorSpace() == *src->colorSpace());
559
560 }
561
563 {
564 return x() == srcData->x() && y() == srcData->y() &&
565 *colorSpace() == *srcData->colorSpace();
566 }
567
569 {
570 QList<Data*> dataObjects;
571
572 if (m_frames.isEmpty()) {
573 dataObjects << m_data.data();
574 }
575 dataObjects << m_lodData.data();
576 dataObjects << m_externalFrameData.data();
577
578 Q_FOREACH (DataSP value, m_frames.values()) {
579 dataObjects << value.data();
580 }
581
582 return dataObjects;
583 }
584
585 void transferFromData(Data *data, KisPaintDeviceSP targetDevice);
586
587 struct Q_DECL_HIDDEN StrategyPolicy;
590
591private:
593
594private:
596 mutable QScopedPointer<Data> m_lodData;
597 mutable QScopedPointer<Data> m_externalFrameData;
598 mutable QMutex m_dataSwitchLock;
599
602};
603
605
607
609 : q(paintDevice),
610 basicStrategy(new KisPaintDeviceStrategy(paintDevice, this)),
611 isProjectionDevice(false),
612 supportsWrapAroundMode(false),
613 m_data(new Data(paintDevice)),
614 m_nextFreeFrameId(0)
615{
616}
617
619{
620 contentChannel.reset();
621 m_frames.clear();
622}
623
625{
626 if (!supportsWrapAroundMode || !defaultBounds->wrapAroundMode()) {
627 return basicStrategy.data();
628 }
629
630 const QRect wrapRect = defaultBounds->imageBorderRect();
631
632 if (!wrappedStrategy || wrappedStrategy->wrapRect() != wrapRect) {
633 QMutexLocker locker(&m_wrappedStrategyMutex);
634
635 if (!wrappedStrategy) {
636 wrappedStrategy.reset(new KisPaintDeviceWrappedStrategy(wrapRect, q, this));
637 } else if (wrappedStrategy->wrapRect() != wrapRect) {
638 wrappedStrategy->setWrapRect(wrapRect);
639 }
640 }
641
642 return wrappedStrategy.data();
643}
644
676
681
683{
684 Data *srcData = currentNonLodData();
685 return srcData->dataManager()->region().translated(srcData->x(), srcData->y());
686}
687
689{
691
692 Data *srcData = currentNonLodData();
693
694 Data *lodData = new Data(q, srcData, false);
695 LodDataStruct *lodStruct = new LodDataStructImpl(lodData);
696
697 int expectedX = KisLodTransform::coordToLodCoord(srcData->x(), newLod);
698 int expectedY = KisLodTransform::coordToLodCoord(srcData->y(), newLod);
699
704 if (lodData->levelOfDetail() != newLod ||
705 lodData->colorSpace() != srcData->colorSpace() ||
706 lodData->x() != expectedX ||
707 lodData->y() != expectedY) {
708
709
710 lodData->prepareClone(srcData);
711
712 lodData->setLevelOfDetail(newLod);
713 lodData->setX(expectedX);
714 lodData->setY(expectedY);
715
716 // FIXME: different kind of synchronization
717 }
718
719 lodData->cache()->invalidate();
720
721 return lodStruct;
722}
723
725 KisDataManager *dstDataManager,
726 const QPoint &srcOffset,
727 const QPoint &dstOffset,
728 const QRect &originalRect,
729 int lod)
730{
731 if (originalRect.isEmpty()) return;
732
733 const int srcStepSize = 1 << lod;
734
736
737 const QRect srcRect = KisLodTransform::alignedRect(originalRect, lod);
738 const QRect dstRect = KisLodTransform::scaledRect(srcRect, lod);
739 if (!srcRect.isValid() || !dstRect.isValid()) return;
740
741 KIS_ASSERT_RECOVER_NOOP(srcRect.width() / srcStepSize == dstRect.width());
742
743 const int pixelSize = srcDataManager->pixelSize();
744
745 int rowsAccumulated = 0;
746 int columnsAccumulated = 0;
747
749
750 QScopedArrayPointer<quint8> blendData(new quint8[srcStepSize * srcRect.width() * pixelSize]);
751 quint8 *blendDataPtr = blendData.data();
752 int blendDataOffset = 0;
753
754 const int srcCellSize = srcStepSize * srcStepSize;
755 const int srcCellStride = srcCellSize * pixelSize;
756 const int srcStepStride = srcStepSize * pixelSize;
757 const int srcColumnStride = (srcStepSize - 1) * srcStepStride;
758
759 InternalSequentialConstIterator srcIntIt(StrategyPolicy(currentStrategy(), srcDataManager, srcOffset.x(), srcOffset.y()), srcRect);
760 InternalSequentialIterator dstIntIt(StrategyPolicy(currentStrategy(), dstDataManager, dstOffset.x(), dstOffset.y()), dstRect);
761
762 int rowsRemaining = srcRect.height();
763 while (rowsRemaining > 0) {
764
765 int colsRemaining = srcRect.width();
766 while (colsRemaining > 0 && srcIntIt.nextPixel()) {
767
768 memcpy(blendDataPtr, srcIntIt.rawDataConst(), pixelSize);
769 blendDataPtr += pixelSize;
770 columnsAccumulated++;
771
772 if (columnsAccumulated >= srcStepSize) {
773 blendDataPtr += srcColumnStride;
774 columnsAccumulated = 0;
775 }
776
777 colsRemaining--;
778 }
779
780 rowsAccumulated++;
781
782 if (rowsAccumulated >= srcStepSize) {
783
784 // blend and write the final data
785 blendDataPtr = blendData.data();
786
787 int colsRemaining = dstRect.width();
788 while (colsRemaining > 0 && dstIntIt.nextPixel()) {
789 mixOp->mixColors(blendDataPtr, srcCellSize, dstIntIt.rawData());
790 blendDataPtr += srcCellStride;
791
792 colsRemaining--;
793 }
794
795 // reset counters
796 rowsAccumulated = 0;
797 blendDataPtr = blendData.data();
798 blendDataOffset = 0;
799 } else {
800 blendDataOffset += srcStepStride;
801 blendDataPtr = blendData.data() + blendDataOffset;
802 }
803
804 rowsRemaining--;
805 }
806}
807
809{
810 LodDataStructImpl *dst = dynamic_cast<LodDataStructImpl*>(_dst);
812
813 Data *lodData = dst->lodData.data();
814 Data *srcData = currentNonLodData();
815
816 const int lod = lodData->levelOfDetail();
817
818 updateLodDataManager(srcData->dataManager().data(), lodData->dataManager().data(),
819 QPoint(srcData->x(), srcData->y()),
820 QPoint(lodData->x(), lodData->y()),
821 originalRect, lod);
822}
823
824void KisPaintDevice::Private::generateLodCloneDevice(KisPaintDeviceSP dst, const QRect &originalRect, int lod)
825{
827
828 Data *srcData = currentNonLodData();
829 updateLodDataManager(srcData->dataManager().data(), dst->dataManager().data(),
830 QPoint(srcData->x(), srcData->y()),
831 QPoint(dst->x(), dst->y()),
832 originalRect, lod);
833}
834
836{
837 LodDataStructImpl *dst = dynamic_cast<LodDataStructImpl*>(_dst);
839
841 dst->lodData->levelOfDetail() == defaultBounds->currentLevelOfDetail());
842
843 ensureLodDataPresent();
844
845 m_lodData->prepareClone(dst->lodData.data());
846 m_lodData->dataManager()->bitBltRough(dst->lodData->dataManager(), dst->lodData->dataManager()->extent());
847}
848
850{
851 QRect extent = data->dataManager()->extent();
852 extent.translate(data->x(), data->y());
853
854 targetDevice->m_d->prepareCloneImpl(q, data);
855 targetDevice->m_d->currentStrategy()->fastBitBltRough(data->dataManager(), extent);
856}
857
859{
860 DataSP data = m_frames[frameId];
861 transferFromData(data.data(), targetDevice);
862}
863
864void KisPaintDevice::Private::uploadFrame(int srcFrameId, int dstFrameId, KisPaintDeviceSP srcDevice)
865{
866 DataSP dstData = m_frames[dstFrameId];
868
869 DataSP srcData = srcDevice->m_d->m_frames[srcFrameId];
871
872 uploadFrameData(srcData, dstData);
873}
874
876{
877 DataSP dstData = m_frames[dstFrameId];
879
880 DataSP srcData = srcDevice->m_d->m_data;
882
883 uploadFrameData(srcData, dstData);
884}
885
887{
888 if (srcData->colorSpace() != dstData->colorSpace() &&
889 *srcData->colorSpace() != *dstData->colorSpace()) {
890
891 KUndo2Command tempCommand;
892
893 srcData = toQShared(new Data(q, srcData.data(), true));
894 srcData->convertDataColorSpace(dstData->colorSpace(),
897 &tempCommand);
898 }
899
900 /* If the destination data doesn't share a default pixel value
901 * with src, we should make sure that the default pixel is set
902 * properly before clearing and writing contents.
903 */
904 const int defaultPixelcmp =
905 memcmp(srcData->dataManager()->defaultPixel(),
906 dstData->dataManager()->defaultPixel(),
907 dstData->dataManager()->pixelSize());
908 if (defaultPixelcmp != 0) {
909 dstData->dataManager()->setDefaultPixel(srcData->dataManager()->defaultPixel());
910 }
911
912 dstData->dataManager()->clear();
913 dstData->cache()->invalidate();
914
915 const QRect rect = srcData->dataManager()->extent();
916 dstData->dataManager()->bitBltRough(srcData->dataManager(), rect);
917 dstData->setX(srcData->x());
918 dstData->setY(srcData->y());
919}
920
922{
923 Data *data = m_lodData.data();
924 Q_ASSERT(data);
925
926 transferFromData(data, targetDevice);
927}
928
930{
931public:
937
938 virtual void emitNotifications()
939 {
941 }
942
943 void redo() override
944 {
945 if (m_firstRun) {
946 m_firstRun = false;
947 return;
948 }
949
952 }
953
954 void undo() override
955 {
958 }
959
960protected:
962
963private:
964 bool m_firstRun {true};
965};
966
980
983 KoColorConversionTransformation::ConversionFlags conversionFlags,
984 KUndo2Command *parentCommand,
985 KoUpdater *progressUpdater)
986{
987 QList<Data*> dataObjects = allDataObjects();
988 if (dataObjects.isEmpty()) return;
989
990 KUndo2Command *mainCommand =
991 parentCommand ? new DeviceChangeColorSpaceCommand(q, parentCommand) : 0;
992
993 Q_FOREACH (Data *data, dataObjects) {
994 if (!data) continue;
995
996 data->convertDataColorSpace(dstColorSpace, renderingIntent, conversionFlags, mainCommand, progressUpdater);
997 }
998
1000}
1001
1003{
1004 if (!profile) return false;
1005
1006 const KoColorSpace *dstColorSpace =
1007 KoColorSpaceRegistry::instance()->colorSpace(colorSpace()->colorModelId().id(), colorSpace()->colorDepthId().id(), profile);
1008 if (!dstColorSpace) return false;
1009
1010 KUndo2Command *mainCommand =
1011 parentCommand ? new DeviceChangeColorSpaceCommand(q, parentCommand) : 0;
1012
1013
1014 QList<Data*> dataObjects = allDataObjects();
1015 Q_FOREACH (Data *data, dataObjects) {
1016 if (!data) continue;
1017 data->assignColorSpace(dstColorSpace, mainCommand);
1018 }
1019 q->emitProfileChanged();
1020
1021 // no undo information is provided here
1022 return true;
1023}
1024
1026{
1027 KUndo2Command *mainCommand = new KUndo2Command();
1028 currentData()->reincarnateWithDetachedHistory(copyContent, mainCommand);
1029 return mainCommand;
1030}
1031
1033{
1034 QList<Data*> dataObjects = allDataObjects();
1035 Q_FOREACH (Data *data, dataObjects) {
1036 if (!data) continue;
1037
1039 data->init(cs, dataManager);
1040 }
1041}
1042
1044 : QObject(0)
1045 , m_d(new Private(this))
1046{
1047 init(colorSpace, new KisDefaultBounds(), 0, name);
1048}
1049
1050KisPaintDevice::KisPaintDevice(KisNodeWSP parent, const KoColorSpace * colorSpace, KisDefaultBoundsBaseSP defaultBounds, const QString& name)
1051 : QObject(0)
1052 , m_d(new Private(this))
1053{
1054 init(colorSpace, defaultBounds, parent, name);
1055}
1056
1057void KisPaintDevice::init(const KoColorSpace *colorSpace,
1058 KisDefaultBoundsBaseSP defaultBounds,
1059 KisNodeWSP parent, const QString& name)
1060{
1061 Q_ASSERT(colorSpace);
1062 setObjectName(name);
1063
1064 // temporary def. bounds object for the initialization phase only
1066
1067 if (!defaultBounds) {
1068 // Reuse transitionalDefaultBounds here. Change if you change
1069 // semantics of transitionalDefaultBounds
1071 }
1072
1074 m_d->init(colorSpace, color.data());
1075
1076 Q_ASSERT(m_d->colorSpace());
1077
1079 setParentNode(parent);
1080}
1081
1083 : QObject()
1084 , KisShared()
1085 , m_d(new Private(this))
1086{
1087 if (this != &rhs) {
1088 makeFullCopyFrom(rhs, copyMode, newParentNode);
1089 }
1090}
1091
1093{
1094 // temporary def. bounds object for the initialization phase only
1096
1097 // copy data objects with or without frames
1099
1100 if (copyMode == KritaUtils::CopyAllFrames && rhs.m_d->framesInterface) {
1104 m_d->contentChannel.reset(new KisRasterKeyframeChannel(*rhs.m_d->contentChannel.data(), this));
1105 }
1106
1109 setParentNode(newParentNode);
1110}
1111
1113{
1114 delete m_d;
1115}
1116
1121
1126
1128{
1129 prepareClone(src);
1130
1131 // we guarantee that *this is totally empty, so copy pixels that
1132 // are areally present on the source image only
1133 const QRect optimizedRect = rect & src->extent();
1134
1135 fastBitBlt(src, optimizedRect);
1136}
1137
1138void KisPaintDevice::makeCloneFromRough(KisPaintDeviceSP src, const QRect &minimalRect)
1139{
1140 prepareClone(src);
1141
1142 // we guarantee that *this is totally empty, so copy pixels that
1143 // are areally present on the source image only
1144 const QRect optimizedRect = minimalRect & src->extent();
1145
1146 fastBitBltRough(src, optimizedRect);
1147}
1148
1150{
1151 m_d->cache()->invalidate();
1152 if (m_d->parent.isValid())
1153 m_d->parent->setDirty();
1154}
1155
1156void KisPaintDevice::setDirty(const QRect & rc)
1157{
1158 m_d->cache()->invalidate();
1159 if (m_d->parent.isValid())
1160 m_d->parent->setDirty(rc);
1161}
1162
1164{
1165 m_d->cache()->invalidate();
1166 if (m_d->parent.isValid())
1168}
1169
1171{
1172 m_d->cache()->invalidate();
1173 if (m_d->parent.isValid())
1174 m_d->parent->setDirty(rects);
1175}
1176
1178{
1179 if (m_d->parent.isValid()) {
1181 }
1182}
1183
1185{
1186 return m_d->cache()->sequenceNumber();
1187}
1188
1189void KisPaintDevice::estimateMemoryStats(qint64 &imageData, qint64 &temporaryData, qint64 &lodData) const
1190{
1191 m_d->estimateMemoryStats(imageData, temporaryData, lodData);
1192}
1193
1195{
1197 m_d->parent = parent;
1198}
1199
1200// for testing purposes only
1202{
1203 return m_d->parent;
1204}
1205
1211
1216
1217void KisPaintDevice::moveTo(const QPoint &pt)
1218{
1219 m_d->currentStrategy()->move(pt);
1220 m_d->cache()->invalidate();
1221}
1222
1224{
1225 return QPoint(x(), y());
1226}
1227
1228void KisPaintDevice::moveTo(qint32 x, qint32 y)
1229{
1230 moveTo(QPoint(x, y));
1231}
1232
1234{
1235 moveTo(QPoint(x, m_d->y()));
1236}
1237
1239{
1240 moveTo(QPoint(m_d->x(), y));
1241}
1242
1243qint32 KisPaintDevice::x() const
1244{
1245 return m_d->x();
1246}
1247
1248qint32 KisPaintDevice::y() const
1249{
1250 return m_d->y();
1251}
1252
1253void KisPaintDevice::extent(qint32 &x, qint32 &y, qint32 &w, qint32 &h) const
1254{
1255 QRect rc = extent();
1256 x = rc.x();
1257 y = rc.y();
1258 w = rc.width();
1259 h = rc.height();
1260}
1261
1263{
1264 return m_d->currentStrategy()->extent();
1265}
1266
1268{
1269 return m_d->currentStrategy()->region();
1270}
1271
1273{
1274 return m_d->cache()->nonDefaultPixelArea();
1275}
1276
1278{
1279 return m_d->cache()->exactBounds();
1280}
1281
1283{
1284 return m_d->cache()->exactBoundsAmortized();
1285}
1286
1287namespace Impl
1288{
1289
1292 : m_colorSpace(colorSpace)
1293 {
1294 }
1295
1296 bool isPixelEmpty(const quint8 *pixelData)
1297 {
1298 return m_colorSpace->opacityU8(pixelData) == OPACITY_TRANSPARENT_U8;
1299 }
1300
1301private:
1303};
1304
1306 CheckNonDefault(int pixelSize, const quint8 *defaultPixel)
1307 : m_pixelSize(pixelSize),
1308 m_defaultPixel(defaultPixel)
1309 {
1310 }
1311
1312 bool isPixelEmpty(const quint8 *pixelData)
1313 {
1314 return memcmp(m_defaultPixel, pixelData, m_pixelSize) == 0;
1315 }
1316
1317private:
1319 const quint8 *m_defaultPixel;
1320};
1321
1322template <class ComparePixelOp>
1323QRect calculateExactBoundsImpl(const KisPaintDevice *device, const QRect &startRect, const QRect &endRect, ComparePixelOp compareOp)
1324{
1325 if (startRect == endRect) return startRect;
1326
1327 // the passed extent might have weird invalid structure that
1328 // can overflow integer precision when calling startRect.right()
1329 if (!startRect.isValid()) return QRect();
1330
1331 // Solution n°2
1332 int x, y, w, h;
1333 int boundLeft, boundTop, boundRight, boundBottom;
1334 int endDirN, endDirE, endDirS, endDirW;
1335
1336 startRect.getRect(&x, &y, &w, &h);
1337
1338 if (endRect.isEmpty()) {
1339 endDirS = startRect.bottom();
1340 endDirN = startRect.top();
1341 endDirE = startRect.right();
1342 endDirW = startRect.left();
1343 startRect.getCoords(&boundLeft, &boundTop, &boundRight, &boundBottom);
1344 } else {
1345 endDirS = endRect.top() - 1;
1346 endDirN = endRect.bottom() + 1;
1347 endDirE = endRect.left() - 1;
1348 endDirW = endRect.right() + 1;
1349 endRect.getCoords(&boundLeft, &boundTop, &boundRight, &boundBottom);
1350 }
1351
1352 // XXX: a small optimization is possible by using H/V line iterators in the first
1353 // and third cases, at the cost of making the code a bit more complex
1354
1356
1357 bool found = false;
1358 {
1359 for (qint32 y2 = y; y2 <= endDirS; ++y2) {
1360 for (qint32 x2 = x; x2 < x + w || found; ++ x2) {
1361 accessor->moveTo(x2, y2);
1362 if (!compareOp.isPixelEmpty(accessor->rawDataConst())) {
1363 boundTop = y2;
1364 found = true;
1365 break;
1366 }
1367 }
1368 if (found) break;
1369 }
1370 }
1371
1377 if (!found && endRect.isEmpty()) {
1378 return QRect();
1379 }
1380
1381 found = false;
1382
1383 for (qint32 y2 = y + h - 1; y2 >= endDirN ; --y2) {
1384 for (qint32 x2 = x + w - 1; x2 >= x || found; --x2) {
1385 accessor->moveTo(x2, y2);
1386 if (!compareOp.isPixelEmpty(accessor->rawDataConst())) {
1387 boundBottom = y2;
1388 found = true;
1389 break;
1390 }
1391 }
1392 if (found) break;
1393 }
1394 found = false;
1395
1396 {
1397 for (qint32 x2 = x; x2 <= endDirE ; ++x2) {
1398 for (qint32 y2 = y; y2 < y + h || found; ++y2) {
1399 accessor->moveTo(x2, y2);
1400 if (!compareOp.isPixelEmpty(accessor->rawDataConst())) {
1401 boundLeft = x2;
1402 found = true;
1403 break;
1404 }
1405 }
1406 if (found) break;
1407 }
1408 }
1409
1410 found = false;
1411
1412 // Look for right edge )
1413 {
1414
1415 for (qint32 x2 = x + w - 1; x2 >= endDirW; --x2) {
1416 for (qint32 y2 = y + h - 1; y2 >= y || found; --y2) {
1417 accessor->moveTo(x2, y2);
1418 if (!compareOp.isPixelEmpty(accessor->rawDataConst())) {
1419 boundRight = x2;
1420 found = true;
1421 break;
1422 }
1423 }
1424 if (found) break;
1425 }
1426 }
1427
1428 return QRect(boundLeft, boundTop,
1429 boundRight - boundLeft + 1,
1430 boundBottom - boundTop + 1);
1431}
1432
1433}
1434
1435QRect KisPaintDevice::calculateExactBounds(bool nonDefaultOnly) const
1436{
1437 QRect startRect = extent();
1438 QRect endRect;
1439
1440 quint8 defaultOpacity = defaultPixel().opacityU8();
1441 if (defaultOpacity != OPACITY_TRANSPARENT_U8) {
1442 if (!nonDefaultOnly) {
1448 endRect = defaultBounds()->bounds();
1449 nonDefaultOnly = true;
1450
1451 } else {
1452 startRect = region().boundingRect();
1453 }
1454 }
1455
1456 if (nonDefaultOnly) {
1457 const KoColor defaultPixel = this->defaultPixel();
1459 endRect = Impl::calculateExactBoundsImpl(this, startRect, endRect, compareOp);
1460 } else {
1462 endRect = Impl::calculateExactBoundsImpl(this, startRect, endRect, compareOp);
1463 }
1464
1465 return endRect;
1466}
1467
1469{
1470 QVector<QRect> sourceRects = region().rects();
1471 QVector<QRect> resultRects;
1472
1473 const KoColor defaultPixel = this->defaultPixel();
1475
1476 Q_FOREACH (const QRect &rc1, sourceRects) {
1477 const int patchSize = 64;
1478 QVector<QRect> smallerRects = KritaUtils::splitRectIntoPatches(rc1, QSize(patchSize, patchSize));
1479 Q_FOREACH (const QRect &rc2, smallerRects) {
1480
1481 const QRect result =
1482 Impl::calculateExactBoundsImpl(this, rc2, QRect(), compareOp);
1483
1484 if (!result.isEmpty()) {
1485 resultRects << result;
1486 }
1487 }
1488 }
1489 return KisRegion(std::move(resultRects));
1490}
1491
1492void KisPaintDevice::crop(qint32 x, qint32 y, qint32 w, qint32 h)
1493{
1494 crop(QRect(x, y, w, h));
1495}
1496
1497
1498void KisPaintDevice::crop(const QRect &rect)
1499{
1501}
1502
1504{
1506 dm->purge(dm->extent());
1507}
1508
1510{
1511 KoColor color(defPixel);
1512 color.convertTo(colorSpace());
1513
1514 m_d->dataManager()->setDefaultPixel(color.data());
1515 m_d->cache()->invalidate();
1516}
1517
1522
1524{
1525 m_d->dataManager()->clear();
1526 m_d->cache()->invalidate();
1527}
1528
1529void KisPaintDevice::clear(const QRect & rc)
1530{
1531 m_d->currentStrategy()->clear(rc);
1532}
1533
1534void KisPaintDevice::fill(const QRect & rc, const KoColor &color)
1535{
1537 m_d->currentStrategy()->fill(rc, color.data());
1538}
1539
1540void KisPaintDevice::fill(qint32 x, qint32 y, qint32 w, qint32 h, const quint8 *fillPixel)
1541{
1542 m_d->currentStrategy()->fill(QRect(x, y, w, h), fillPixel);
1543}
1544
1545
1547{
1548 return m_d->dataManager()->write(store);
1549}
1550
1551bool KisPaintDevice::read(QIODevice *stream)
1552{
1553 bool retval;
1554
1555 retval = m_d->dataManager()->read(stream);
1556 m_d->cache()->invalidate();
1557
1558 return retval;
1559}
1560
1565
1570
1571void KisPaintDevice::convertTo(const KoColorSpace *dstColorSpace,
1573 KoColorConversionTransformation::ConversionFlags conversionFlags,
1574 KUndo2Command *parentCommand,
1575 KoUpdater *progressUpdater)
1576{
1577 m_d->convertColorSpace(dstColorSpace, renderingIntent, conversionFlags, parentCommand, progressUpdater);
1578}
1579
1580bool KisPaintDevice::setProfile(const KoColorProfile * profile, KUndo2Command *parentCommand)
1581{
1582 return m_d->assignProfile(profile, parentCommand);
1583}
1584
1589
1594
1595void KisPaintDevice::convertFromQImage(const QImage& _image, const KoColorProfile *profile,
1596 qint32 offsetX, qint32 offsetY)
1597{
1598 QImage image = _image;
1599
1600 if (image.format() != QImage::Format_ARGB32) {
1601 image.convertTo(QImage::Format_ARGB32);
1602 }
1603 // Don't convert if not no profile is given and both paint dev and qimage are rgba.
1604 if (!profile && colorSpace()->id() == "RGBA") {
1605 writeBytes(image.constBits(), offsetX, offsetY, image.width(), image.height());
1606 } else {
1607 try {
1608 quint8 * dstData = new quint8[image.width() * image.height() * pixelSize()];
1611 ->convertPixelsTo(image.constBits(), dstData, colorSpace(), image.width() * image.height(),
1614
1615 writeBytes(dstData, offsetX, offsetY, image.width(), image.height());
1616 delete[] dstData;
1617 } catch (const std::bad_alloc&) {
1618 warnKrita << "KisPaintDevice::convertFromQImage: Could not allocate" << image.width() * image.height() * pixelSize() << "bytes";
1619 return;
1620 }
1621 }
1622 m_d->cache()->invalidate();
1623}
1624
1625QImage KisPaintDevice::convertToQImage(const KoColorProfile *dstProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
1626{
1627 qint32 x1;
1628 qint32 y1;
1629 qint32 w;
1630 qint32 h;
1631
1632 QRect rc = exactBounds();
1633 x1 = rc.x();
1634 y1 = rc.y();
1635 w = rc.width();
1636 h = rc.height();
1637
1638 return convertToQImage(dstProfile, x1, y1, w, h, renderingIntent, conversionFlags);
1639}
1640
1642 const QRect &rc,
1644 KoColorConversionTransformation::ConversionFlags conversionFlags) const
1645{
1646 return convertToQImage(dstProfile,
1647 rc.x(), rc.y(), rc.width(), rc.height(),
1648 renderingIntent, conversionFlags);
1649}
1650
1651QImage KisPaintDevice::convertToQImage(const KoColorProfile *dstProfile, qint32 x1, qint32 y1, qint32 w, qint32 h, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
1652{
1653
1654 if (w < 0)
1655 return QImage();
1656
1657 if (h < 0)
1658 return QImage();
1659
1660 quint8 *data = 0;
1661 try {
1662 data = new quint8 [w * h * pixelSize()];
1663 } catch (const std::bad_alloc&) {
1664 warnKrita << "KisPaintDevice::convertToQImage std::bad_alloc for " << w << " * " << h << " * " << pixelSize();
1665 //delete[] data; // data is not allocated, so don't free it
1666 return QImage();
1667 }
1668 Q_CHECK_PTR(data);
1669
1670 // XXX: Is this really faster than converting line by line and building the QImage directly?
1671 // This copies potentially a lot of data.
1672 readBytes(data, x1, y1, w, h);
1673 QImage image = colorSpace()->convertToQImage(data, w, h, dstProfile, renderingIntent, conversionFlags);
1674 delete[] data;
1675
1676 return image;
1677}
1678
1679inline bool moveBy(KisSequentialConstIterator& iter, int numPixels)
1680{
1681 int pos = 0;
1682 while (pos < numPixels) {
1683 int step = std::min(iter.nConseqPixels(), numPixels - pos);
1684 if (!iter.nextPixels(step))
1685 return false;
1686 pos += step;
1687 }
1688 return true;
1689}
1690
1691static KisPaintDeviceSP createThumbnailDeviceInternal(const KisPaintDevice* srcDev, qint32 srcX0, qint32 srcY0, qint32 srcWidth, qint32 srcHeight, qint32 w, qint32 h, QRect outputRect)
1692{
1693 KisPaintDeviceSP thumbnail = new KisPaintDevice(srcDev->colorSpace());
1694 qint32 pixelSize = srcDev->pixelSize();
1695
1697 KisRandomAccessorSP dstIter = thumbnail->createRandomAccessorNG();
1698
1699 for (qint32 y = outputRect.y(); y < outputRect.y() + outputRect.height(); ++y) {
1700 qint32 iY = srcY0 + (y * srcHeight) / h;
1701 for (qint32 x = outputRect.x(); x < outputRect.x() + outputRect.width(); ++x) {
1702 qint32 iX = srcX0 + (x * srcWidth) / w;
1703 srcIter->moveTo(iX, iY);
1704 dstIter->moveTo(x, y);
1705 memcpy(dstIter->rawData(), srcIter->rawDataConst(), pixelSize);
1706 }
1707 }
1708 return thumbnail;
1709}
1710
1711QSize fixThumbnailSize(QSize size)
1712{
1713 if (!size.width() && size.height()) {
1714 size.setWidth(1);
1715 }
1716
1717 if (size.width() && !size.height()) {
1718 size.setHeight(1);
1719 }
1720
1721 return size;
1722}
1723
1724KisPaintDeviceSP KisPaintDevice::createThumbnailDevice(qint32 w, qint32 h, QRect rect, QRect outputRect) const
1725{
1726 QSize thumbnailSize(w, h);
1727
1728 QRect imageRect = rect.isValid() ? rect : extent();
1729
1730 if ((thumbnailSize.width() > imageRect.width()) || (thumbnailSize.height() > imageRect.height())) {
1731 thumbnailSize.scale(imageRect.size(), Qt::KeepAspectRatio);
1732 }
1733
1734 thumbnailSize = fixThumbnailSize(thumbnailSize);
1735
1736 //can't create thumbnail for an empty device, e.g. layer thumbnail for empty image
1737 if (imageRect.isEmpty() || thumbnailSize.isEmpty()) {
1738 return new KisPaintDevice(colorSpace());
1739 }
1740
1741 int srcWidth, srcHeight;
1742 int srcX0, srcY0;
1743 imageRect.getRect(&srcX0, &srcY0, &srcWidth, &srcHeight);
1744
1745 if (!outputRect.isValid()) {
1746 outputRect = QRect(0, 0, w, h);
1747 }
1748
1749 KisPaintDeviceSP thumbnail = createThumbnailDeviceInternal(this, imageRect.x(), imageRect.y(), imageRect.width(), imageRect.height(),
1750 thumbnailSize.width(), thumbnailSize.height(), outputRect);
1751
1752 return thumbnail;
1753}
1754
1755KisPaintDeviceSP KisPaintDevice::createThumbnailDeviceOversampled(qint32 w, qint32 h, qreal oversample, QRect rect, QRect outputTileRect) const
1756{
1757 QSize thumbnailSize(w, h);
1758 qreal oversampleAdjusted = qMax(oversample, 1.);
1759 QSize thumbnailOversampledSize = oversampleAdjusted * thumbnailSize;
1760
1761 QRect outputRect;
1762 QRect imageRect = rect.isValid() ? rect : extent();
1763
1764 qint32 hstart = thumbnailOversampledSize.height();
1765
1766 if ((thumbnailOversampledSize.width() > imageRect.width()) || (thumbnailOversampledSize.height() > imageRect.height())) {
1767 thumbnailOversampledSize.scale(imageRect.size(), Qt::KeepAspectRatio);
1768 }
1769
1770 thumbnailOversampledSize = fixThumbnailSize(thumbnailOversampledSize);
1771
1772 //can't create thumbnail for an empty device, e.g. layer thumbnail for empty image
1773 if (imageRect.isEmpty() || thumbnailSize.isEmpty() || thumbnailOversampledSize.isEmpty()) {
1774 return new KisPaintDevice(colorSpace());
1775 }
1776
1777 oversampleAdjusted *= (hstart > 0) ? ((qreal)thumbnailOversampledSize.height() / hstart) : 1.; //readjusting oversample ratio, given that we had to adjust thumbnail size
1778
1779 outputRect = QRect(0, 0, thumbnailOversampledSize.width(), thumbnailOversampledSize.height());
1780
1781 if (outputTileRect.isValid()) {
1782 //compensating output rectangle for oversampling
1783 outputTileRect = QRect(oversampleAdjusted * outputTileRect.topLeft(), oversampleAdjusted * outputTileRect.bottomRight());
1784 outputRect = outputRect.intersected(outputTileRect);
1785 }
1786
1787 KisPaintDeviceSP thumbnail = createThumbnailDeviceInternal(this, imageRect.x(), imageRect.y(), imageRect.width(), imageRect.height(),
1788 thumbnailOversampledSize.width(), thumbnailOversampledSize.height(), outputRect);
1789
1790 if (oversample != 1. && oversampleAdjusted != 1.) {
1791 KoDummyUpdaterHolder updaterHolder;
1792 KisTransformWorker worker(thumbnail, 1 / oversampleAdjusted, 1 / oversampleAdjusted, 0.0, 0.0, 0.0, 0.0, 0.0,
1793 updaterHolder.updater(), KisFilterStrategyRegistry::instance()->value("Bilinear"));
1794 worker.run();
1795 }
1796 return thumbnail;
1797}
1798
1799QImage KisPaintDevice::createThumbnail(qint32 w, qint32 h, QRect rect, qreal oversample, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
1800{
1801 QSize size = fixThumbnailSize(QSize(w, h));
1802
1803 KisPaintDeviceSP dev = createThumbnailDeviceOversampled(size.width(), size.height(), oversample, rect);
1804 QImage thumbnail = dev->convertToQImage(KoColorSpaceRegistry::instance()->rgb8()->profile(), 0, 0, w, h, renderingIntent, conversionFlags);
1805 return thumbnail;
1806}
1807
1808QImage KisPaintDevice::createThumbnail(qint32 w, qint32 h, qreal oversample, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
1809{
1810 QSize size = fixThumbnailSize(QSize(w, h));
1811
1812 return m_d->cache()->createThumbnail(size.width(), size.height(), oversample, renderingIntent, conversionFlags);
1813}
1814
1815QImage KisPaintDevice::createThumbnail(qint32 maxw, qint32 maxh,
1816 Qt::AspectRatioMode aspectRatioMode,
1818 KoColorConversionTransformation::ConversionFlags conversionFlags)
1819{
1820 const QRect deviceExtent = exactBounds();
1821 const QSize thumbnailSize = deviceExtent.size().scaled(maxw, maxh, aspectRatioMode);
1822 return createThumbnail(thumbnailSize.width(), thumbnailSize.height(),
1823 oversample, renderingIntent, conversionFlags);
1824}
1825
1827{
1828 m_d->cache()->invalidate();
1829 return m_d->currentStrategy()->createHLineIteratorNG(m_d->dataManager().data(), x, y, w, m_d->x(), m_d->y());
1830}
1831
1833{
1834 return m_d->currentStrategy()->createHLineConstIteratorNG(m_d->dataManager().data(), x, y, w, m_d->x(), m_d->y());
1835}
1836
1838{
1839 m_d->cache()->invalidate();
1841}
1842
1847
1848KisRepeatHLineConstIteratorSP KisPaintDevice::createRepeatHLineConstIterator(qint32 x, qint32 y, qint32 w, const QRect& _dataWidth) const
1849{
1850 return new KisRepeatHLineConstIteratorNG(m_d->dataManager().data(), x, y, w, m_d->x(), m_d->y(), _dataWidth, m_d->cacheInvalidator());
1851}
1852
1853KisRepeatVLineConstIteratorSP KisPaintDevice::createRepeatVLineConstIterator(qint32 x, qint32 y, qint32 h, const QRect& _dataWidth) const
1854{
1855 return new KisRepeatVLineConstIteratorNG(m_d->dataManager().data(), x, y, h, m_d->x(), m_d->y(), _dataWidth, m_d->cacheInvalidator());
1856}
1857
1863
1868
1870{
1871 KisPaintDevice* pd = const_cast<KisPaintDevice*>(this);
1872 return new KisRandomSubAccessor(pd);
1873}
1874
1876{
1878 const QRect r = selection->selectedExactRect();
1879
1880 if (r.isValid()) {
1881
1882 {
1883 KisHLineIteratorSP devIt = createHLineIteratorNG(r.x(), r.y(), r.width());
1884 KisHLineConstIteratorSP selectionIt = selection->projection()->createHLineConstIteratorNG(r.x(), r.y(), r.width());
1885
1886 const KoColor defaultPixel = this->defaultPixel();
1887 bool transparentDefault = (defaultPixel.opacityU8() == OPACITY_TRANSPARENT_U8);
1888 for (qint32 y = 0; y < r.height(); y++) {
1889
1890 do {
1891 // XXX: Optimize by using stretches
1892 colorSpace->applyInverseAlphaU8Mask(devIt->rawData(), selectionIt->rawDataConst(), 1);
1893 if (transparentDefault && colorSpace->opacityU8(devIt->rawData()) == OPACITY_TRANSPARENT_U8) {
1894 memcpy(devIt->rawData(), defaultPixel.data(), colorSpace->pixelSize());
1895 }
1896 } while (devIt->nextPixel() && selectionIt->nextPixel());
1897 devIt->nextRow();
1898 selectionIt->nextRow();
1899 }
1900 }
1901
1902 // purge() must be executed **after** all iterators have been destroyed!
1903 m_d->dataManager()->purge(r.translated(-m_d->x(), -m_d->y()));
1904
1905 setDirty(r);
1906 }
1907}
1908
1909bool KisPaintDevice::pixel(qint32 x, qint32 y, QColor *c) const
1910{
1912
1913 const quint8 *pix = iter->rawDataConst();
1914
1915 if (!pix) return false;
1916
1917 colorSpace()->toQColor(pix, c);
1918
1919 return true;
1920}
1921
1922
1923bool KisPaintDevice::pixel(qint32 x, qint32 y, KoColor * kc) const
1924{
1926
1927 const quint8 *pix = iter->rawDataConst();
1928
1929 if (!pix) return false;
1930
1931 kc->setColor(pix, m_d->colorSpace());
1932
1933 return true;
1934}
1935
1936KoColor KisPaintDevice::pixel(const QPoint &pos) const
1937{
1938 KisHLineConstIteratorSP iter = createHLineConstIteratorNG(pos.x(), pos.y(), 1);
1939 return KoColor(iter->rawDataConst(), m_d->colorSpace());
1940}
1941
1942bool KisPaintDevice::setPixel(qint32 x, qint32 y, const QColor& c)
1943{
1945
1946 colorSpace()->fromQColor(c, iter->rawData());
1947 m_d->cache()->invalidate();
1948 return true;
1949}
1950
1951bool KisPaintDevice::setPixel(qint32 x, qint32 y, const KoColor& kc)
1952{
1953 const quint8 * pix;
1955 if (kc.colorSpace() != m_d->colorSpace()) {
1956 KoColor kc2(kc, m_d->colorSpace());
1957 pix = kc2.data();
1958 memcpy(iter->rawData(), pix, m_d->colorSpace()->pixelSize());
1959 } else {
1960 pix = kc.data();
1961 memcpy(iter->rawData(), pix, m_d->colorSpace()->pixelSize());
1962 }
1963 m_d->cache()->invalidate();
1964 return true;
1965}
1966
1971
1973{
1975}
1976
1981
1986
1991
1992void KisPaintDevice::readBytes(quint8 * data, qint32 x, qint32 y, qint32 w, qint32 h) const
1993{
1994 readBytes(data, QRect(x, y, w, h));
1995}
1996
1997void KisPaintDevice::readBytes(quint8 *data, const QRect &rect) const
1998{
1999 m_d->currentStrategy()->readBytes(data, rect);
2000}
2001
2002void KisPaintDevice::writeBytes(const quint8 *data, qint32 x, qint32 y, qint32 w, qint32 h)
2003{
2004 writeBytes(data, QRect(x, y, w, h));
2005}
2006
2007void KisPaintDevice::writeBytes(const quint8 *data, const QRect &rect)
2008{
2010}
2011
2012QVector<quint8*> KisPaintDevice::readPlanarBytes(qint32 x, qint32 y, qint32 w, qint32 h) const
2013{
2014 return m_d->currentStrategy()->readPlanarBytes(x, y, w, h);
2015}
2016
2017void KisPaintDevice::writePlanarBytes(QVector<quint8*> planes, qint32 x, qint32 y, qint32 w, qint32 h)
2018{
2019 m_d->currentStrategy()->writePlanarBytes(planes, x, y, w, h);
2020}
2021
2022
2024{
2025 quint32 _pixelSize = m_d->colorSpace()->pixelSize();
2026 Q_ASSERT(_pixelSize > 0);
2027 return _pixelSize;
2028}
2029
2031{
2032 quint32 _channelCount = m_d->colorSpace()->channelCount();
2033 Q_ASSERT(_channelCount > 0);
2034 return _channelCount;
2035}
2036
2041
2046
2048{
2049 Q_ASSERT(!m_d->framesInterface);
2051
2052 Q_ASSERT(!m_d->contentChannel);
2053 if (m_d->parent.isValid()) {
2055 } else {
2056 //fallback when paint device is isolated / does not belong to a node.
2058 }
2059
2060 // Raster channels always have at least one frame (representing a static image)
2061 KUndo2Command tempParentCommand;
2062 m_d->contentChannel->addKeyframe(0);
2063
2064 return m_d->contentChannel.data();
2065}
2066
2068{
2069 if (m_d->contentChannel) {
2070 return m_d->contentChannel.data();
2071 }
2072 return 0;
2073}
2074
2076{
2077 Q_ASSERT(m_d->colorSpace() != 0);
2078 return m_d->colorSpace();
2079}
2080
2088
2099
2111
2116
2121
2123{
2124 QVector<qint32> sizes;
2126 std::sort(channels.begin(), channels.end());
2127
2128 Q_FOREACH (KoChannelInfo * channelInfo, channels) {
2129 sizes.append(channelInfo->size());
2130 }
2131 return sizes;
2132}
2133
2138
2143
2147
2152
2157
2159{
2160 m_d->updateLodDataStruct(dst, srcRect);
2161}
2162
2167
2168void KisPaintDevice::generateLodCloneDevice(KisPaintDeviceSP dst, const QRect &originalRect, int lod)
2169{
2170 m_d->generateLodCloneDevice(dst, originalRect, lod);
2171}
2172
2177
2182
2187
2189{
2190 KIS_ASSERT_RECOVER_RETURN_VALUE(m_d->framesInterface.data()->frames().contains(frameID), false);
2191
2192 // Preserve keyframe data from frameID...
2194 m_d->framesInterface->writeFrameToDevice(frameID, holder);
2195
2196 // Remove all keyframes..
2197 QSet<int> times = m_d->contentChannel->allKeyframeTimes();
2198 Q_FOREACH( const int& time, times ) {
2199 m_d->contentChannel->removeKeyframe(time);
2200 }
2201
2202 // TODO: Eventually rewrite this to completely remove contentChannel.
2203 // For now, importing it as frame 0 will be close enough.
2204 m_d->contentChannel->importFrame(0, holder, nullptr);
2205
2206 return true;
2207}
2208
2210{
2211 if (m_d->framesInterface) {
2212 return burnKeyframe(m_d->framesInterface->currentFrameId());
2213 }
2214 return true;
2215}
2216
2217/******************************************************************/
2218/* KisPaintDeviceFramesInterface */
2219/******************************************************************/
2220
2225
2230
2231int KisPaintDeviceFramesInterface::createFrame(bool copy, int copySrc, const QPoint &offset, KUndo2Command *parentCommand)
2232{
2233 return q->m_d->createFrame(copy, copySrc, offset, parentCommand);
2234}
2235
2237{
2238 return q->m_d->deleteFrame(frame, parentCommand);
2239}
2240
2242{
2243 q->m_d->writeFrameToDevice(frameId, targetDevice);
2244}
2245
2246void KisPaintDeviceFramesInterface::uploadFrame(int srcFrameId, int dstFrameId, KisPaintDeviceSP srcDevice)
2247{
2248 q->m_d->uploadFrame(srcFrameId, dstFrameId, srcDevice);
2249}
2250
2252{
2253 q->m_d->uploadFrame(dstFrameId, srcDevice);
2254}
2255
2257{
2258 return q->m_d->frameBounds(frameId);
2259}
2260
2262{
2263 return q->m_d->frameOffset(frameId);
2264}
2265
2267{
2268 KIS_ASSERT_RECOVER_RETURN(frameId >= 0);
2269 q->m_d->setFrameDefaultPixel(defPixel, frameId);
2270}
2271
2273{
2274 KIS_ASSERT_RECOVER(frameId >= 0) {
2275 return KoColor(Qt::red, q->m_d->colorSpace());
2276 }
2277 return q->m_d->frameDefaultPixel(frameId);
2278}
2279
2281{
2282 KIS_ASSERT_RECOVER(frameId >= 0) {
2283 return false;
2284 }
2285 return q->m_d->writeFrame(store, frameId);
2286}
2287
2288bool KisPaintDeviceFramesInterface::readFrame(QIODevice *stream, int frameId)
2289{
2290 KIS_ASSERT_RECOVER(frameId >= 0) {
2291 return false;
2292 }
2293 return q->m_d->readFrame(stream, frameId);
2294}
2295
2300
2302{
2303 KIS_ASSERT_RECOVER(frameId >= 0) {
2304 return q->m_d->dataManager();
2305 }
2306 return q->m_d->frameDataManager(frameId);
2307}
2308
2310{
2311 KIS_ASSERT_RECOVER_RETURN(frameId >= 0);
2312
2313 return q->m_d->invalidateFrameCache(frameId);
2314}
2315
2316void KisPaintDeviceFramesInterface::setFrameOffset(int frameId, const QPoint &offset)
2317{
2318 KIS_ASSERT_RECOVER_RETURN(frameId >= 0);
2319 return q->m_d->setFrameOffset(frameId, offset);
2320}
2321
2324{
2325 TestingDataObjects objects;
2326
2327 objects.m_data = q->m_d->m_data.data();
2328 objects.m_lodData = q->m_d->m_lodData.data();
2329 objects.m_externalFrameData = q->m_d->m_externalFrameData.data();
2330
2331 typedef KisPaintDevice::Private::FramesHash FramesHash;
2332
2333 FramesHash::const_iterator it = q->m_d->m_frames.constBegin();
2334 FramesHash::const_iterator end = q->m_d->m_frames.constEnd();
2335
2336 for (; it != end; ++it) {
2337 objects.m_frames.insert(it.key(), it.value().data());
2338 }
2339
2340 objects.m_currentData = q->m_d->currentData();
2341
2342 return objects;
2343}
2344
2349
2351{
2352 m_d->testingFetchLodDevice(targetDevice);
2353}
float value(const T *src, size_t ch)
const qreal oversample
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
const quint8 OPACITY_TRANSPARENT_U8
virtual void undo()
virtual void redo()
virtual quint8 * rawData()=0
virtual const quint8 * rawDataConst() const =0
virtual bool nextPixel()=0
void clear(qint32 x, qint32 y, qint32 w, qint32 h, quint8 def)
void purge(const QRect &area)
void setDefaultPixel(const quint8 *defPixel)
bool read(QIODevice *io)
bool write(KisPaintDeviceWriter &writer)
void extent(qint32 &x, qint32 &y, qint32 &w, qint32 &h) const
KisRegion region() const
quint32 pixelSize() const
static void releaseInternalPools()
const quint8 * defaultPixel() const
virtual bool externalFrameActive() const =0
virtual int currentLevelOfDetail() const =0
virtual bool wrapAroundMode() const =0
virtual QRect imageBorderRect() const
virtual int currentTime() const =0
virtual QRect bounds() const =0
static KisFilterStrategyRegistry * instance()
virtual void nextRow()=0
static int coordToLodCoord(int x, int lod)
static QRect alignedRect(const QRect &srcRect, int lod)
static QRect scaledRect(const QRect &srcRect, int lod)
QImage createThumbnail(qint32 w, qint32 h, qreal oversample, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
ALWAYS_INLINE KisInterstrokeDataSP interstrokeData() const
ALWAYS_INLINE qint32 levelOfDetail() const
ALWAYS_INLINE qint32 y() const
ALWAYS_INLINE KisDataManagerSP dataManager() const
void assignColorSpace(const KoColorSpace *dstColorSpace, KUndo2Command *parentCommand)
void convertDataColorSpace(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags, KUndo2Command *parentCommand, KoUpdater *updater=nullptr)
ALWAYS_INLINE KisIteratorCompleteListener * cacheInvalidator()
ALWAYS_INLINE qint32 x() const
ALWAYS_INLINE KisPaintDeviceCache * cache()
void prepareClone(const KisPaintDeviceData *srcData, bool copyContent=false)
ALWAYS_INLINE void setX(qint32 value)
ALWAYS_INLINE void setY(qint32 value)
void init(const KoColorSpace *cs, KisDataManagerSP dataManager)
ALWAYS_INLINE const KoColorSpace * colorSpace() const
ALWAYS_INLINE KUndo2Command * createChangeInterstrokeDataCommand(KisInterstrokeDataSP value)
ALWAYS_INLINE void setLevelOfDetail(qint32 value)
void setFrameOffset(int frameId, const QPoint &offset)
void writeFrameToDevice(int frameId, KisPaintDeviceSP targetDevice)
void setFrameDefaultPixel(const KoColor &defPixel, int frameId)
QPoint frameOffset(int frameId) const
KoColor frameDefaultPixel(int frameId) const
int createFrame(bool copy, int copySrc, const QPoint &offset, KUndo2Command *parentCommand)
void uploadFrame(int srcFrameId, int dstFrameId, KisPaintDeviceSP srcDevice)
QList< KisPaintDeviceData * > testingGetDataObjectsList() const
void deleteFrame(int frame, KUndo2Command *parentCommand)
bool readFrame(QIODevice *stream, int frameId)
TestingDataObjects testingGetDataObjects() const
KisDataManagerSP frameDataManager(int frameId) const
bool writeFrame(KisPaintDeviceWriter &store, int frameId)
KisPaintDeviceFramesInterface(KisPaintDevice *parentDevice)
DeviceChangeColorSpaceCommand(KisPaintDeviceSP device, KUndo2Command *parent=0)
DeviceChangeProfileCommand(KisPaintDeviceSP device, KUndo2Command *parent=0)
FrameInsertionCommand(FramesHash *hash, DataSP data, int frameId, bool insert, KUndo2Command *parentCommand)
virtual KisRandomConstAccessorSP createRandomConstAccessorNG() const
virtual KisHLineConstIteratorSP createHLineConstIteratorNG(KisDataManager *dataManager, qint32 x, qint32 y, qint32 w, qint32 offsetX, qint32 offsetY) const
virtual KisVLineConstIteratorSP createVLineConstIteratorNG(qint32 x, qint32 y, qint32 w) const
virtual QVector< quint8 * > readPlanarBytes(qint32 x, qint32 y, qint32 w, qint32 h) const
virtual void writeBytes(const quint8 *data, const QRect &rect)
virtual void fastBitBltRoughOldData(KisPaintDeviceSP src, const QRect &rect)
virtual void writePlanarBytes(QVector< quint8 * > planes, qint32 x, qint32 y, qint32 w, qint32 h)
virtual void fastBitBlt(KisPaintDeviceSP src, const QRect &rect)
virtual void fill(const QRect &rc, const quint8 *fillPixel)
virtual void fastBitBltRough(KisPaintDeviceSP src, const QRect &rect)
virtual void readBytes(quint8 *data, const QRect &rect) const
virtual KisHLineIteratorSP createHLineIteratorNG(KisDataManager *dataManager, qint32 x, qint32 y, qint32 w, qint32 offsetX, qint32 offsetY)
virtual KisVLineIteratorSP createVLineIteratorNG(qint32 x, qint32 y, qint32 w)
virtual void fastBitBltOldData(KisPaintDeviceSP src, const QRect &rect)
Private *const m_d
quint32 pixelSize() const
void crop(qint32 x, qint32 y, qint32 w, qint32 h)
bool read(QIODevice *stream)
KUndo2Command * createChangeInterstrokeDataCommand(KisInterstrokeDataSP data)
set interstroke data to the device
QVector< quint8 * > readPlanarBytes(qint32 x, qint32 y, qint32 w, qint32 h) const
KisRasterKeyframeChannel * keyframeChannel() const
bool write(KisPaintDeviceWriter &store)
void setX(qint32 x)
void profileChanged(const KoColorProfile *profile)
void uploadLodDataStruct(LodDataStruct *dst)
void fastBitBltRoughOldData(KisPaintDeviceSP src, const QRect &rect)
KisVLineConstIteratorSP createVLineConstIteratorNG(qint32 x, qint32 y, qint32 h) const
bool setPixel(qint32 x, qint32 y, const QColor &c)
void testingFetchLodDevice(KisPaintDeviceSP targetDevice)
bool supportsWraproundMode() const
void requestTimeSwitch(int time)
virtual void clear()
KisRegion region() const
void setDefaultPixel(const KoColor &defPixel)
void makeCloneFromRough(KisPaintDeviceSP src, const QRect &minimalRect)
KisRegion regionForLodSyncing() const
int sequenceNumber() const
QRect nonDefaultPixelArea() const
void setDefaultBounds(KisDefaultBoundsBaseSP bounds)
LodDataStruct * createLodDataStruct(int lod)
void updateLodDataStruct(LodDataStruct *dst, const QRect &srcRect)
bool fastBitBltPossible(KisPaintDeviceSP src)
KisPaintDeviceSP createCompositionSourceDevice() const
KisPaintDevice(const KoColorSpace *colorSpace, const QString &name=QString())
KisPaintDeviceSP createThumbnailDevice(qint32 w, qint32 h, QRect rect=QRect(), QRect outputRect=QRect()) const
virtual const KoColorSpace * compositionSourceColorSpace() const
void writePlanarBytes(QVector< quint8 * > planes, qint32 x, qint32 y, qint32 w, qint32 h)
KisInterstrokeDataSP interstrokeData() const
QImage createThumbnail(qint32 maxw, qint32 maxh, QRect rect, qreal oversample=1, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags())
void init(const KoColorSpace *colorSpace, KisDefaultBoundsBaseSP defaultBounds, KisNodeWSP parent, const QString &name)
KisRandomConstAccessorSP createRandomConstAccessorNG() const
KUndo2Command * reincarnateWithDetachedHistory(bool copyContent)
KisPaintDeviceFramesInterface * framesInterface()
quint32 channelCount() const
static MemoryReleaseObject * createMemoryReleaseObject()
QRect exactBounds() const
QRect extent() const
KisHLineIteratorSP createHLineIteratorNG(qint32 x, qint32 y, qint32 w)
KisRegion regionExact() const
void fill(const QRect &rc, const KoColor &color)
KisRepeatVLineConstIteratorSP createRepeatVLineConstIterator(qint32 x, qint32 y, qint32 h, const QRect &_dataWidth) const
void setProjectionDevice(bool value)
void generateLodCloneDevice(KisPaintDeviceSP dst, const QRect &originalRect, int lod)
friend class KisPaintDeviceFramesInterface
KisFixedPaintDeviceSP createCompositionSourceDeviceFixed() const
const KoColorSpace * colorSpace() const
QVector< qint32 > channelSizes() const
KisDataManagerSP dataManager() const
KisPaintDeviceSP createThumbnailDeviceOversampled(qint32 w, qint32 h, qreal oversample, QRect rect=QRect(), QRect outputRect=QRect()) const
QRect exactBoundsAmortized() const
KisRasterKeyframeChannel * createKeyframeChannel(const KoID &id)
void clearSelection(KisSelectionSP selection)
void setSupportsWraparoundMode(bool value)
KoColor defaultPixel() 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
void estimateMemoryStats(qint64 &imageData, qint64 &temporaryData, qint64 &lodData) const
bool pixel(qint32 x, qint32 y, QColor *c) const
KisNodeWSP parentNode() const
KisDefaultBoundsBaseSP defaultBounds() const
KisVLineIteratorSP createVLineIteratorNG(qint32 x, qint32 y, qint32 h)
void convertFromQImage(const QImage &image, const KoColorProfile *profile, qint32 offsetX=0, qint32 offsetY=0)
void fastBitBltRough(KisPaintDeviceSP src, const QRect &rect)
void setParentNode(KisNodeWSP parent)
bool setProfile(const KoColorProfile *profile, KUndo2Command *parentCommand)
void fastBitBltOldData(KisPaintDeviceSP src, const QRect &rect)
void moveTo(qint32 x, qint32 y)
void prepareClone(KisPaintDeviceSP src)
void fastBitBlt(KisPaintDeviceSP src, const QRect &rect)
void makeFullCopyFrom(const KisPaintDevice &rhs, KritaUtils::DeviceCopyMode copyMode=KritaUtils::CopySnapshot, KisNode *newParentNode=0)
void colorSpaceChanged(const KoColorSpace *colorspace)
void convertTo(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags(), KUndo2Command *parentCommand=nullptr, KoUpdater *progressUpdater=nullptr)
void readBytes(quint8 *data, qint32 x, qint32 y, qint32 w, qint32 h) const
KisRandomSubAccessorSP createRandomSubAccessor() const
KisHLineConstIteratorSP createHLineConstIteratorNG(qint32 x, qint32 y, qint32 w) const
void setY(qint32 y)
QRect calculateExactBounds(bool nonDefaultOnly) const
void makeCloneFrom(KisPaintDeviceSP src, const QRect &rect)
KisRepeatHLineConstIteratorSP createRepeatHLineConstIterator(qint32 x, qint32 y, qint32 w, const QRect &_dataWidth) const
void writeBytes(const quint8 *data, qint32 x, qint32 y, qint32 w, qint32 h)
~KisPaintDevice() override
QPoint offset() const
KisRandomAccessorSP createRandomAccessorNG()
virtual void moveTo(qint32 x, qint32 y)=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 ...
KisRegion translated(int x, int y) const
QRect boundingRect() const
QVector< QRect > rects() const
ALWAYS_INLINE quint8 * rawData()
ALWAYS_INLINE const quint8 * rawDataConst() const
bool isValid() const
qint32 size() const
virtual quint32 pixelSize() const =0
virtual QImage convertToQImage(const quint8 *data, qint32 width, qint32 height, const KoColorProfile *dstProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
virtual void toQColor(const quint8 *src, QColor *c) const =0
virtual void applyInverseAlphaU8Mask(quint8 *pixels, const quint8 *alpha, qint32 nPixels) const =0
QList< KoChannelInfo * > channels
virtual void fromQColor(const QColor &color, quint8 *dst) const =0
virtual quint32 channelCount() const =0
virtual quint8 opacityU8(const quint8 *pixel) const =0
virtual bool convertPixelsTo(const quint8 *src, quint8 *dst, const KoColorSpace *dstColorSpace, quint32 numPixels, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
KoMixColorsOp * mixColorsOp
virtual const KoColorProfile * profile() const =0
void convertTo(const KoColorSpace *cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
Definition KoColor.cpp:136
void setColor(const quint8 *data, const KoColorSpace *colorSpace=0)
Definition KoColor.cpp:186
static KoColor createTransparent(const KoColorSpace *cs)
Definition KoColor.cpp:681
quint8 * data()
Definition KoColor.h:144
quint8 opacityU8() const
Definition KoColor.cpp:341
const KoColorSpace * colorSpace() const
return the current colorSpace
Definition KoColor.h:82
A holder for an updater that does nothing.
Definition KoUpdater.h:116
KoUpdater * updater()
const T value(const QString &id) const
Definition KoID.h:30
QString id() const
Definition KoID.cpp:63
virtual void mixColors(const quint8 *const *colors, const qint16 *weights, int nColors, quint8 *dst, int weightSum=255) const =0
#define KIS_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:85
#define KIS_ASSERT_RECOVER(cond)
Definition kis_assert.h:55
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
#define warnKrita
Definition kis_debug.h:87
static KisPaintDeviceSP createThumbnailDeviceInternal(const KisPaintDevice *srcDev, qint32 srcX0, qint32 srcY0, qint32 srcWidth, qint32 srcHeight, qint32 w, qint32 h, QRect outputRect)
QSize fixThumbnailSize(QSize size)
bool moveBy(KisSequentialConstIterator &iter, int numPixels)
KIS_DECLARE_STATIC_INITIALIZER
QSharedPointer< T > toQShared(T *ptr)
KisRepeatHLineIteratorPixelBase< KisHLineIterator2 > KisRepeatHLineConstIteratorNG
Definition kis_types.h:199
KisRepeatVLineIteratorPixelBase< KisVLineIterator2 > KisRepeatVLineConstIteratorNG
Definition kis_types.h:204
QRect calculateExactBoundsImpl(const KisPaintDevice *device, const QRect &startRect, const QRect &endRect, ComparePixelOp compareOp)
QVector< QRect > splitRectIntoPatches(const QRect &rc, const QSize &patchSize)
CheckFullyTransparent(const KoColorSpace *colorSpace)
bool isPixelEmpty(const quint8 *pixelData)
const KoColorSpace * m_colorSpace
CheckNonDefault(int pixelSize, const quint8 *defaultPixel)
bool isPixelEmpty(const quint8 *pixelData)
The KisIteratorCompleteListener struct is a special interface for notifying the paint device that an ...
void requestTimeSwitch(int time)
Definition kis_node.cpp:670
virtual void setDirty()
Definition kis_node.cpp:577
StrategyPolicy(KisPaintDevice::Private::KisPaintDeviceStrategy *strategy, KisDataManager *dataManager, qint32 offsetX, qint32 offsetY)
KisHLineIteratorSP createIterator(const QRect &rect)
KisHLineConstIteratorSP createConstIterator(const QRect &rect)
void generateLodCloneDevice(KisPaintDeviceSP dst, const QRect &originalRect, int lod)
void setFrameDefaultPixel(const KoColor &defPixel, int frameId)
void init(const KoColorSpace *cs, const quint8 *defaultPixel)
KisInterstrokeDataSP interstrokeData() const
void transferFromData(Data *data, KisPaintDeviceSP targetDevice)
int createFrame(bool copy, int copySrc, const QPoint &offset, KUndo2Command *parentCommand)
bool writeFrame(KisPaintDeviceWriter &store, int frameId)
void uploadLodDataStruct(LodDataStruct *dst)
const KoColorSpace * colorSpace() const
QScopedPointer< KisRasterKeyframeChannel > contentChannel
void deleteFrame(int frameID, KUndo2Command *parentCommand)
KisDefaultBoundsBaseSP defaultBounds
KisDataManagerSP dataManager() const
bool readFrame(QIODevice *stream, int frameId)
QHash< int, DataSP > FramesHash
KUndo2Command * reincarnateWithDetachedHistory(bool copyContent)
void prepareCloneImpl(KisPaintDeviceSP src, Data *srcData)
bool fastBitBltPossibleImpl(Data *srcData)
KUndo2Command * createChangeInterstrokeDataCommand(KisInterstrokeDataSP value)
LodDataStruct * createLodDataStruct(int lod)
qint64 estimateDataSize(Data *data) const
QPoint frameOffset(int frameId) const
QScopedPointer< Data > m_externalFrameData
KisIteratorCompleteListener * cacheInvalidator()
QScopedPointer< KisPaintDeviceFramesInterface > framesInterface
static const KisDefaultBoundsSP transitionalDefaultBounds
QScopedPointer< Data > m_lodData
void estimateMemoryStats(qint64 &imageData, qint64 &temporaryData, qint64 &lodData) const
bool fastBitBltPossible(KisPaintDeviceSP src)
bool assignProfile(const KoColorProfile *profile, KUndo2Command *parentCommand)
void updateLodDataStruct(LodDataStruct *dst, const QRect &srcRect)
void testingFetchLodDevice(KisPaintDeviceSP targetDevice)
KisSequentialIteratorBase< ReadOnlyIteratorPolicy< StrategyPolicy >, StrategyPolicy > InternalSequentialConstIterator
const QList< int > frameIds() const
QRect frameBounds(int frameId)
void uploadFrame(int srcFrameId, int dstFrameId, KisPaintDeviceSP srcDevice)
KisRegion regionForLodSyncing() const
void writeFrameToDevice(int frameId, KisPaintDeviceSP targetDevice)
void cloneAllDataObjects(Private *rhs, bool copyFrames)
Private(KisPaintDevice *paintDevice)
void prepareClone(KisPaintDeviceSP src)
QScopedPointer< KisPaintDeviceStrategy > basicStrategy
void updateLodDataManager(KisDataManager *srcDataManager, KisDataManager *dstDataManager, const QPoint &srcOffset, const QPoint &dstOffset, const QRect &originalRect, int lod)
QScopedPointer< KisPaintDeviceWrappedStrategy > wrappedStrategy
KisDataManagerSP frameDataManager(int frameId) const
void setFrameOffset(int frameId, const QPoint &offset)
KisPaintDeviceCache * cache()
QList< Data * > allDataObjects() const
void convertColorSpace(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags, KUndo2Command *parentCommand, KoUpdater *progressUpdater)
void uploadFrameData(DataSP srcData, DataSP dstData)
KisPaintDeviceStrategy * currentStrategy()
KisSequentialIteratorBase< WritableIteratorPolicy< StrategyPolicy >, StrategyPolicy > InternalSequentialIterator
void invalidateFrameCache(int frameId)
QSharedPointer< Data > DataSP
KoColor frameDefaultPixel(int frameId) const
KisPixelSelectionSP projection() const
QRect selectedExactRect() const
Slow, but exact way of determining the rectangle that encloses the selection.
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()