20#include <QDirIterator>
21#include <QElapsedTimer>
23#include <QRegularExpression>
24#include <QApplication>
25#include <QMutexLocker>
29#include <QSharedPointer>
40 "KritaShape/KisToolLine",
41 "KritaShape/KisToolRectangle",
42 "KritaShape/KisToolEllipse",
49 threads =
static_cast<unsigned int>(
57 auto oldValue =
get();
110 auto oldValue =
inUse;
111 inUse =
static_cast<unsigned int>(
114 return oldValue !=
inUse;
151 const bool needSrgbConversion = [&]() {
167 if (
targetCs && needSrgbConversion) {
173 const quint32 width = image->
width() & bitmask;
174 const quint32 height = image->
height() & bitmask;
175 const int bufferSize = device->
pixelSize() * width * height;
183 const int outWidth = width / divider;
184 const int outHeight = height / divider;
185 uchar *outData =
reinterpret_cast<uchar *
>(
imageBuffer.data());
187 frame = QImage(outData, outWidth, outHeight, QImage::Format_ARGB32);
198 inline quint32
avg(quint32 c1, quint32 c2)
200 return (((c1 ^ c2) & 0xfefefefeUL) >> 1) + (c1 & c2);
205 quint32 *buffer =
reinterpret_cast<quint32 *
>(
imageBuffer.data());
206 quint32 *out = buffer;
214 avg(in1[x], in1[x + 1]),
215 avg(in2[x], in2[x + 1])
231 const int inverseAlpha = 255 - alpha;
233 (alpha * qRed(
source) + inverseAlpha * qRed(destination)) >> 8,
234 (alpha * qGreen(
source) + inverseAlpha * qGreen(destination)) >> 8,
235 (alpha * qBlue(
source) + inverseAlpha * qBlue(destination)) >> 8
241 const quint32 background = 0xFFFFFFFF;
242 quint32 *buffer =
reinterpret_cast<quint32 *
>(
imageBuffer.data());
244 while (buffer != end) {
245 const int alpha = qAlpha(*buffer);
250 *buffer = background;
265 const QString fileName = QString(
"%1").arg(index, 7, 10, QLatin1Char(
'0'));
281 QFile(filePath).remove();
303 if (
static_cast<int>(
id) != writerId)
333 QObject* threadParent,
376 QElapsedTimer dbgTimer;
379 QDirIterator dirIterator(directory);
383 int recordIndex = -1;
384 while (dirIterator.hasNext()) {
387 const QString &fileName = dirIterator.fileName();
388 const QRegularExpressionMatch &match = snapshotFilePattern.match(fileName);
389 if (match.hasMatch()) {
390 int index = match.captured(1).toInt();
391 if (recordIndex < index)
395 dbgTools <<
"findLastPartNumber for" << directory <<
": " << dbgTimer.elapsed() <<
"ms";
403 bool alreadyWarn =
false;
404 bool alreadyErr =
false;
407 if (el.inUse && !el.writer->isActive()) {
411 canvas->image()->waitForDone();
414 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
425 disconnect(el.writer.get(), SIGNAL(capturingDone(
int,
bool)),
q, SLOT(
onCapturingDone(
int,
bool)));
426 if (el.thread->isRunning())
429 warnResources <<
"One of the Recorder WriterPool threads has been blocked and has to be terminated. "
430 <<
"Thread Name: " << el.thread->objectName();
433 el.thread->terminate();
437 errResources <<
"Something odd has been happen. Krita was unable to stop one of the Recorder WriterPool Threads. "
438 <<
"Thread Name: " << el.thread->objectName();
465 auto writerPtr =
writerPool[newWorkerId].writer;
466 auto threadPtr =
writerPool[newWorkerId].thread;
467 threadPtr->setObjectName(QString(
"Krita-Recorder-WriterPool#%1").arg(newWorkerId));
469 connect(writerPtr.get(), SIGNAL(capturingDone(
int,
bool)),
q, SLOT(
onCapturingDone(
int,
bool)));
470 writerPtr->moveToThread(threadPtr.get());
471 threadPtr->start(QThread::IdlePriority);
478 for(
auto i = 0; i <
writerPool.size(); i++, j++)
498 : d(new
Private(this, recorderThreads))
499 , exporterSettings(es)
501 d->
timer.setTimerType(Qt::PreciseTimer);
512 bool restart =
d->
timer.isActive();
521 disconnect(proxy, SIGNAL(toolChanged(QString)),
this, SLOT(
onToolChanged(QString)));
532 connect(proxy, SIGNAL(toolChanged(QString)),
this, SLOT(
onToolChanged(QString)),
533 Qt::DirectConnection);
535 Qt::DirectConnection);
537 Qt::DirectConnection);
548 bool restart =
d->
timer.isActive();
574 connect(&
d->
timer, SIGNAL (timeout()),
this, SLOT (
onTimer()));
614 if (qobject_cast<KisMainWindow*>(QApplication::activeWindow()) ==
nullptr)
618 (
d->
canvas->image()->isIsolatingLayer() ||
d->
canvas->image()->isIsolatingGroup())) {
652 d->
canvas->image()->addSpontaneousJob(job);
660 d->
writerPool[workerId].thread->setPriority(QThread::IdlePriority);
674 (
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
quint32 pixelSize() const
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
RecorderWriterManager()=delete
void start(bool toggleEnabled=true)
void onCapturingDone(int workerId, bool success)
void onToolPrimaryActionActivated(bool activated)
void startCapturing(int writerId, int index, KisPaintDeviceSP device)
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 onToolChanged(const QString &toolId)
int writeFrame(int index)
Private(Private &&)=delete
void removeFrameTransparency()
QPointer< KisCanvas2 > canvas
quint32 avg(quint32 c1, quint32 c2)
const KoColorSpace * targetCs
void halfSizeImageBuffer()
Private & operator=(Private &&)=delete
Private & operator=(const Private &)=default
void captureImage(KisPaintDeviceSP device)
quint32 blendSourceOver(const int alpha, const quint32 source, const quint32 destination)
const RecorderWriterSettings * settings
Private(QPointer< KisCanvas2 > c, const RecorderWriterSettings &s, const QDir &d)
Private(const Private &)=default
void onCaptureImage(int writerId, int index, KisPaintDeviceSP device)
void capturingDone(int writerId, bool success)
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(QObject *threadParent, unsigned int i, QPointer< KisCanvas2 > c, const RecorderWriterSettings &s, const QDir &d)