19#include <QDirIterator>
20#include <QElapsedTimer>
22#include <QRegularExpression>
23#include <QApplication>
24#include <QMutexLocker>
28#include <QSharedPointer>
37 "KisToolSelectOutline",
38 "KisToolSelectPolygonal",
39 "KisToolEncloseAndFill",
43 "KisToolSelectMagnetic",
47 "KritaTransform/KisToolMove",
48 "KritaShape/KisToolLine",
49 "KritaShape/KisToolRectangle",
50 "KritaShape/KisToolEllipse",
51 "KisToolSelectRectangular",
52 "KisToolSelectElliptical",
59 threads =
static_cast<unsigned int>(
67 auto oldValue =
get();
120 auto oldValue =
inUse;
121 inUse =
static_cast<unsigned int>(
124 return oldValue !=
inUse;
181 const bool needSrgbConversion = [&]() {
197 if (
targetCs && needSrgbConversion) {
203 const quint32 width = image->
width() & bitmask;
204 const quint32 height = image->
height() & bitmask;
205 const int bufferSize = device->
pixelSize() * width * height;
213 const int outWidth = width / divider;
214 const int outHeight = height / divider;
215 uchar *outData =
reinterpret_cast<uchar *
>(
imageBuffer.data());
217 frame = QImage(outData, outWidth, outHeight, QImage::Format_ARGB32);
229 inline quint32
avg(quint32 c1, quint32 c2)
231 return (((c1 ^ c2) & 0xfefefefeUL) >> 1) + (c1 & c2);
236 quint32 *buffer =
reinterpret_cast<quint32 *
>(
imageBuffer.data());
237 quint32 *out = buffer;
245 avg(in1[x], in1[x + 1]),
246 avg(in2[x], in2[x + 1])
262 const int inverseAlpha = 255 - alpha;
264 (alpha * qRed(
source) + inverseAlpha * qRed(destination)) >> 8,
265 (alpha * qGreen(
source) + inverseAlpha * qGreen(destination)) >> 8,
266 (alpha * qBlue(
source) + inverseAlpha * qBlue(destination)) >> 8
272 const quint32 background = 0xFFFFFFFF;
273 quint32 *buffer =
reinterpret_cast<quint32 *
>(
imageBuffer.data());
275 while (buffer != end) {
276 const int alpha = qAlpha(*buffer);
281 *buffer = background;
296 const QString fileName = QString(
"%1").arg(
partIndex, 7, 10, QLatin1Char(
'0'));
311 QFile(filePath).remove();
337 if (
static_cast<int>(
id) != writerId)
408 QElapsedTimer dbgTimer;
411 QDirIterator dirIterator(directory);
415 int recordIndex = -1;
416 while (dirIterator.hasNext()) {
419 const QString &fileName = dirIterator.fileName();
420 const QRegularExpressionMatch &match = snapshotFilePattern.match(fileName);
421 if (match.hasMatch()) {
422 int index = match.captured(1).toInt();
423 if (recordIndex < index)
427 dbgTools <<
"findLastPartNumber for" << directory <<
": " << dbgTimer.elapsed() <<
"ms";
435 bool alreadyWarn =
false;
436 bool alreadyErr =
false;
441 disconnect(
q, SIGNAL(
startCapturing(
int)), el.writer.get(), SLOT(onCaptureImage(
int)));
442 disconnect(el.writer.get(), SIGNAL(capturingDone(
int,
int)),
q, SLOT(
onCapturingDone(
int,
int)));
443 if (el.thread->isRunning())
446 warnResources <<
"One of the Recorder WriterPool threads has been blocked and has to be terminated. "
447 <<
"Thread Name: " << el.thread->objectName();
450 el.thread->terminate();
454 errResources <<
"Something odd has been happen. Krita was unable to stop one of the Recorder WriterPool Threads. "
455 <<
"Thread Name: " << el.thread->objectName();
482 auto writerPtr =
writerPool[newWorkerId].writer;
483 auto threadPtr =
writerPool[newWorkerId].thread;
484 threadPtr->setObjectName(QString(
"Krita-Recorder-WriterPool#%1").arg(newWorkerId));
485 connect(
q, SIGNAL(
startCapturing(
int)), writerPtr.get(), SLOT(onCaptureImage(
int)));
486 connect(writerPtr.get(), SIGNAL(capturingDone(
int,
int)),
q, SLOT(
onCapturingDone(
int,
int)));
487 writerPtr->moveToThread(threadPtr.get());
488 threadPtr->start(QThread::IdlePriority);
495 for(
auto i = 0; i <
writerPool.size(); i++, j++)
506 : d(new
Private(this, recorderThreads))
507 , exporterSettings(es)
509 d->
timer.setTimerType(Qt::PreciseTimer);
520 bool restart =
d->
timer.isActive();
529 disconnect(proxy, SIGNAL(toolChanged(QString)),
this, SLOT(
onToolChanged(QString)));
540 connect(proxy, SIGNAL(toolChanged(QString)),
this, SLOT(
onToolChanged(QString)),
541 Qt::DirectConnection);
543 Qt::DirectConnection);
545 Qt::DirectConnection);
556 bool restart =
d->
timer.isActive();
582 connect(&
d->
timer, SIGNAL (timeout()),
this, SLOT (
onTimer()));
640 if (qobject_cast<KisMainWindow*>(QApplication::activeWindow()) ==
nullptr)
644 (
d->
canvas->image()->isIsolatingLayer() ||
d->
canvas->image()->isIsolatingGroup())) {
675 d->
writerPool[workerId].thread->setPriority(QThread::IdlePriority);
689 (
d->
canvas->image()->isIsolatingLayer() ||
d->
canvas->image()->isIsolatingGroup()))
float value(const T *src, size_t ch)
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
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 ...
const KoColorSpace * colorSpace() const
KisPaintDeviceSP projection() const
void immediateLockForReadOnly()
QRect bounds() const override
quint32 pixelSize() const
void makeCloneFromRough(KisPaintDeviceSP src, const QRect &minimalRect)
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
virtual KoID colorModelId() const =0
virtual KoID colorDepthId() const =0
virtual const KoColorProfile * profile() const =0
volatile std::atomic_bool toolActivated
QPointer< KisCanvas2 > canvas
ThreadCounter & recorderThreads
int findLastIndex(const QString &directory)
RecorderWriterManager *const q
volatile std::atomic_bool isActivateBlackTool
volatile std::atomic_bool imageModified
void searchForFreeWriter()
Private(RecorderWriterManager *q_ptr, ThreadCounter &rt)
std::atomic_int freeWriterId
volatile std::atomic_bool isForceBlackTool
RecorderWriterSettings settings
volatile std::atomic_bool enabled
bool canStartCapture() const
RecorderWriterManager()=delete
void start(bool toggleEnabled=true)
void startCapturing(int writerId)
int incrementAndGetIndex()
void onToolPrimaryActionActivated(bool activated)
void lowPerformanceWarning()
void recorderStopWarning()
void setCanvas(QPointer< KisCanvas2 > canvas)
bool stop(bool toggleEnabled=true)
void setEnabled(bool enabled)
void setup(const RecorderWriterSettings &settings)
ThreadCounter recorderThreads
const RecorderExportSettings & exporterSettings
void onCapturingDone(int workerId, int status)
void onToolChanged(const QString &toolId)
Private(Private &&)=delete
void removeFrameTransparency()
QPointer< KisCanvas2 > canvas
RecorderWriterManager * manager
quint32 avg(quint32 c1, quint32 c2)
const KoColorSpace * targetCs
void halfSizeImageBuffer()
Private & operator=(Private &&)=delete
Private & operator=(const Private &)=default
quint32 blendSourceOver(const int alpha, const quint32 source, const quint32 destination)
Private(QPointer< KisCanvas2 > c, const RecorderWriterSettings &s, const QDir &d, RecorderWriterManager *m)
const RecorderWriterSettings * settings
Private(const Private &)=default
static constexpr int STATUS_OK
static constexpr int STATUS_ERROR
void onCaptureImage(int writerId)
void capturingDone(int writerId, int status)
static constexpr int STATUS_BLOCKED
void setUsedAndNotify(int value)
bool setUsedImpl(int value)
unsigned int getUsed() const
void notifyValueChange(bool valueWasIncreased)
void setAndNotify(int value)
void notifyInUseChange(bool valueWasIncreased)
QRegularExpression snapshotFilePatternFor(const QString &extension)
constexpr int waitThreadTimeoutMs
const unsigned int MaxThreadCount
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
bool recordIsolateLayerMode
QSharedPointer< RecorderWriter > writer
QSharedPointer< QThread > thread
WriterPoolEl(RecorderWriterManager *m, unsigned int i, QPointer< KisCanvas2 > c, const RecorderWriterSettings &s, const QDir &d)