12#include <QStandardPaths>
35 m_mainWindow(mainWindow),
36 m_activeView(activeView)
40 setWindowTitle(i18nc(
"@title:window",
"Import Video Animation"));
42 QWidget *page =
new QWidget(
this);
49 QFileInfo ffmpegFileInfo(config->getPropertyLazy(
"ffmpeg_path",
""));
50 QFileInfo ffprobeFileInfo(config->getPropertyLazy(
"ffprobe_path",
""));
52 dbgFile <<
"Config data =" <<
"ffmpeg:" << ffmpegFileInfo.absoluteFilePath() <<
"ffprobe:" << ffprobeFileInfo.absoluteFilePath();
56 if (ffmpegInfo[
"enabled"].toBool()) {
57 m_ui.cmbFFMpegLocation->addItem(ffmpegInfo[
"path"].toString(),ffmpegInfo);
59 if (ffprobeFileInfo.filePath().isEmpty())
60 ffprobeFileInfo.setFile(ffmpegFileInfo.absoluteDir().filePath(
"ffprobe"));
64 m_ui.tabGeneral->setEnabled(
false);
65 QMessageBox::warning(
this, i18nc(
"@title:window",
"Krita"), i18n(
"FFMpeg not found! Please add a path to FFMpeg in the \"Advanced\" tab"));
70 if (ffprobeInfo[
"enabled"].toBool())
71 m_ui.cmbFFProbeLocation->addItem(ffprobeInfo[
"path"].toString(),ffprobeInfo);
73 m_ui.cmbFFProbeLocation->addItem(
"[Disabled]",QJsonObject({{
"path",
""},{
"enabled",
false}}));
80 m_ui.fpsSpinbox->setValue(24.0);
81 m_ui.fpsSpinbox->setSuffix(i18nc(
"FPS as a unit following a value, like 60 FPS",
" FPS"));
83 m_ui.frameSkipSpinbox->setValue(1);
84 m_ui.frameSkipSpinbox->setRange(1,20);
86 m_ui.startExportingAtSpinbox->setValue(0.0);
87 m_ui.startExportingAtSpinbox->setRange(0.0, 9999.0);
88 m_ui.startExportingAtSpinbox->setSuffix(i18nc(
"Second as a unit following a value, like 60 s",
" s"));
90 m_ui.videoPreviewSlider->setTickInterval(1);
91 m_ui.videoPreviewSlider->setValue(0);
93 m_ui.exportDurationSpinbox->setValue(3.0);
94 m_ui.exportDurationSpinbox->setSuffix(i18nc(
"Second as a unit following a value, like 60 s",
" s"));
96 m_ui.lblWarning->hide();
100 m_ui.cmbDocumentHandler->addItem(i18nc(
"Import video to New Document",
"New Document"),
"0");
103 m_ui.cmbDocumentHandler->addItem(i18nc(
"Import video to Current Document",
"Current Document"),
"1");
104 m_ui.cmbDocumentHandler->setCurrentIndex(1);
105 m_ui.fpsDocumentLabel->setText(i18nc(
"Video importer: fps of the document you're importing into"
106 ,
"<small>Document:\n %1 FPS</small>"
111 m_ui.documentWidthSpinbox->setValue(0);
112 m_ui.documentHeightSpinbox->setValue(0);
113 m_ui.documentWidthSpinbox->setRange(1,100000);
114 m_ui.documentHeightSpinbox->setRange(1,100000);
116 m_ui.videoWidthSpinbox->setValue(0);
117 m_ui.videoHeightSpinbox->setValue(0);
118 m_ui.videoWidthSpinbox->setRange(1,100000);
119 m_ui.videoHeightSpinbox->setRange(1,100000);
121 m_ui.sensitivitySpinbox->setValue(50.0f);
123 m_ui.cmbVideoScaleFilter->addItem(i18n(
"Bicubic"),
"bicubic");
124 m_ui.cmbVideoScaleFilter->addItem(i18n(
"Bilinear"),
"bilinear");
125 m_ui.cmbVideoScaleFilter->addItem(i18n(
"Lanczos3"),
"lanczos");
126 m_ui.cmbVideoScaleFilter->addItem(i18n(
"Nearest Neighbor"),
"neighbor");
127 m_ui.cmbVideoScaleFilter->addItem(i18nc(
"An interpolation method",
"Spline"),
"spline");
129 m_ui.tabWidget->setCurrentIndex(0);
162float rerange(
float value,
float oldMin,
float oldMax,
float newMin,
float newMax) {
163 return ((
value - oldMin) / (oldMax - oldMin)) * (newMax - newMin) + newMin;
172 if ( !directory.mkpath(
".") ) {
173 QMessageBox::warning(
this, i18nc(
"@title:window",
"Krita"), i18n(
"Failed to create a work directory, make sure you have write permission"));
178 const float exportDuration =
m_ui.exportDurationSpinbox->value();
179 const float fps =
m_ui.fpsSpinbox->value();
180 const float nDuplicateSensitivity =
m_ui.sensitivitySpinbox->value() /
m_ui.sensitivitySpinbox->maximum();
182 if (exportDuration / fps > 100.0) {
183 if (QMessageBox::warning(
this, i18nc(
"Title for a messagebox",
"Krita"),
184 i18n(
"Warning: you are trying to import more than 100 frames into Krita.\n\n"
185 "This means you might be overloading your system.\n"
186 "If you want to edit a clip larger than 100 frames, consider using a real video editor, like Kdenlive (https://kdenlive.org)."),
187 QMessageBox::Ok | QMessageBox::Cancel,
188 QMessageBox::Cancel) == QMessageBox::Cancel) {
194 args <<
"-ss" << QString::number(
m_ui.startExportingAtSpinbox->value())
197 const float sceneFiltrationFilterThreshold =
rerange( 1 - nDuplicateSensitivity, 0.0f, 1.0f, 0.0005f, 0.2f);
199 if (
m_ui.optionFilterDuplicates->isChecked()) {
200 args <<
"-filter:v" << QString(
"select=gt(scene\\,%1)+eq(n\\,0)").arg(sceneFiltrationFilterThreshold)
204 args <<
"-t" << QString::number(exportDuration)
205 <<
"-r" << QString::number(fps);
208 args <<
"-vf" << QString(
"scale=w=")
209 .append(QString::number(
m_ui.videoWidthSpinbox->value()))
211 .append(QString::number(
m_ui.videoHeightSpinbox->value()))
213 .append(
m_ui.cmbVideoScaleFilter->currentData().toString());
216 QJsonObject ffmpegInfo =
m_ui.cmbFFMpegLocation->currentData().toJsonObject();
217 QJsonObject ffprobeInfo =
m_ui.cmbFFProbeLocation->currentData().toJsonObject();
221 config->setProperty(
"ffmpeg_path", ffmpegInfo[
"path"].toString());
222 config->setProperty(
"ffprobe_path", ffprobeInfo[
"path"].toString());
229 ffmpegSettings.
processPath = ffmpegInfo[
"path"].toString();
230 ffmpegSettings.
args = args;
231 ffmpegSettings.
outputFile = directory.filePath(
"output_%04d.png");
232 ffmpegSettings.
logPath = QDir::tempPath() + QDir::separator() +
"krita" + QDir::separator() +
"ffmpeg.log";
233 ffmpegSettings.
totalFrames = qCeil(exportDuration * fps);
234 ffmpegSettings.
progressMessage = i18nc(
"FFMPEG animated video import message. arg1: frame progress number. arg2: file suffix."
235 ,
"Extracted %1 frames from %2 video.",
"[progress]",
"[suffix]");
239 ffmpeg->startNonBlocking(ffmpegSettings);
241 bool ffmpegSuccess = ffmpeg->waitForFinished();
242 if (!ffmpegSuccess) {
246 frameFileList = directory.entryList(
QStringList() <<
"output_*.png",QDir::Files);
247 frameFileList.replaceInStrings(
"output_", directory.absolutePath() + QDir::separator() +
"output_");
249 dbgFile <<
"Import frames list:" << frameFileList;
252 if (
m_ui.optionFilterDuplicates->isChecked()){
255 ffmpegSettings.
processPath = ffprobeInfo[
"path"].toString();
257 QString filter =
"movie=" +
m_videoInfo.
file + QString(
",setpts=N+1,select=gt(scene\\,%1)").arg(sceneFiltrationFilterThreshold);
259 <<
"-show_entries" <<
"frame=pkt_pts"
260 <<
"-of" <<
"compact=p=0:nk=1"
261 <<
"-f" <<
"lavfi" << filter;
267 QString out = QString(arr);
269 QStringList integerOuts = out.split(
"\n", Qt::SkipEmptyParts);
270 Q_FOREACH(const QString& str, integerOuts){
272 const int value = str.toUInt(&ok);
274 frameTimeList.push_back(value);
279 ffmpeg->startNonBlocking(ffmpegSettings);
281 bool ffmpegSuccess = ffmpeg->waitForFinished();
282 if (!ffmpegSuccess) {
289 if ( frameFileList.isEmpty() ) {
290 QMessageBox::critical(
this, i18nc(
"@title:window",
"Krita"), i18n(
"Failed to export frames from video"));
305 profileName = profile->
name();
309 documentInfoList << QString::number(
m_ui.frameSkipSpinbox->value())
310 << QString::number(
m_ui.fpsSpinbox->value())
311 << QString::number(qCeil(
m_ui.fpsSpinbox->value() *
m_ui.exportDurationSpinbox->value()))
314 if (
m_ui.cmbDocumentHandler->currentIndex() == 0 ) {
315 documentInfoList <<
"0"
316 << QString::number(
m_ui.documentWidthSpinbox->value())
317 << QString::number(
m_ui.documentHeightSpinbox->value())
318 << QString::number(72)
323 documentInfoList <<
"1";
326 return documentInfoList;
332 supportedMimeTypes <<
"video/x-matroska";
333 supportedMimeTypes <<
"image/gif";
334 supportedMimeTypes <<
"image/apng";
335 supportedMimeTypes <<
"image/png";
336 supportedMimeTypes <<
"video/quicktime";
337 supportedMimeTypes <<
"video/ogg";
338 supportedMimeTypes <<
"video/mp4";
339 supportedMimeTypes <<
"video/mpeg";
340 supportedMimeTypes <<
"video/webm";
343 supportedMimeTypes <<
"application/octet-stream";
345 return supportedMimeTypes;
351 dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
353 dialog.setCaption(i18n(
"Select your Video File"));
355 return dialog.filenames();
362 m_ui.videoPreviewSlider->setEnabled(toggleBool);
363 m_ui.currentFrameNumberInput->setEnabled(toggleBool);
364 m_ui.nextFrameButton->setEnabled(toggleBool);
365 m_ui.prevFrameButton->setEnabled(toggleBool);
370 const QFileInfo resultFileInfo(filename);
371 const QDir videoDir(resultFileInfo.absolutePath());
379 textInfo.append(i18nc(
"video importer: video file statistics",
"Width: %1 px", QString::number(
m_videoInfo.
width)));
380 textInfo.append(i18nc(
"video importer: video file statistics",
"Height: %1 px", QString::number(
m_videoInfo.
height)));
383 textInfo.append(i18nc(
"video importer: video file statistics"
384 ,
"Color Primaries: %1"
386 textInfo.append(i18nc(
"video importer: video file statistics"
387 ,
"Color Transfer: %1"
390 textInfo.append(i18nc(
"video importer: video file statistics",
"Duration: %1 s", QString::number(
m_videoInfo.
duration,
'f', 2)));
391 textInfo.append(i18nc(
"video importer: video file statistics",
"Frames: %1", QString::number(
m_videoInfo.
frames)));
392 textInfo.append(i18nc(
"video importer: video file statistics",
"FPS: %1", QString::number(
m_videoInfo.
fps)));
396 textInfo.append(i18nc(
"video importer: video file statistics",
"*<font size='0.5em'><em>*FPS not right in file. Modified to see full duration</em></font>"));
400 m_ui.fileLoadedDetails->setText(textInfo.join(
"\n"));
405 m_ui.exportDurationSpinbox->setRange(0, 9999.0);
407 if (
m_ui.cmbDocumentHandler->currentIndex() == 0) {
435 args <<
"-ss" << QString::number(currentDuration)
439 <<
"-vcodec" <<
"mjpeg"
440 <<
"-f" <<
"image2pipe"
445 QJsonObject ffmpegInfo =
m_ui.cmbFFMpegLocation->currentData().toJsonObject();
448 if ( byteImage.isEmpty() ) {
451 QPixmap thumbnailPixmap;
452 thumbnailPixmap.loadFromData(byteImage,
"JFIF");
454 m_ui.thumbnailImageHolder->clear();
455 const QSize previewSize =
456 m_ui.thumbnailImageHolder->contentsRect().size() *
m_ui.thumbnailImageHolder->devicePixelRatioF();
457 QPixmap img = thumbnailPixmap.scaled(previewSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
458 img.setDevicePixelRatio(
m_ui.thumbnailImageHolder->devicePixelRatioF());
459 m_ui.thumbnailImageHolder->setPixmap(img);
474 const KFormat format;
477 quint32 pixelSize = 4;
483 const qint64 frames = std::lround(qreal(
m_videoInfo.
fps) * time + 2);
491 const QString text_frames = i18nc(
"part of warning in video importer."
492 ,
"<b>Warning:</b> you are trying to import %1 frames, the maximum amount you can import is %2."
498 const QString text_video_editor = i18nc(
"part of warning in video importer.",
499 "Use a <a href=\"https://kdenlive.org\">video editor</a> instead!");
501 if (maxFrames < frames) {
502 warnings.append(text_frames);
503 text_memory = i18nc(
"part of warning in video importer."
504 ,
"You do not have enough memory to load this many frames, the computer will be overloaded.");
505 warnings.insert(0,
"<span style=\"color:#ff692e;\">");
506 warnings.append(text_memory);
507 warnings.append(text_video_editor);
508 m_ui.lblWarning->setVisible(
true);
509 }
else if (maxFrames < frames * 2) {
510 warnings.append(text_frames);
511 text_memory = i18nc(
"part of warning in video importer."
512 ,
"This will take over half the available memory, editing will be difficult.");
513 warnings.insert(0,
"<span style=\"color:#ffee00;\">");
514 warnings.append(text_memory);
515 warnings.append(text_video_editor);
516 m_ui.lblWarning->setVisible(
true);
519 warnings.append(text_frames);
520 QString text_trc = i18nc(
"part of warning in video importer."
521 ,
"Krita does not support the video transfer curve (%1), it will be loaded as linear."
523 warnings.append(text_trc);
526 if (warnings.isEmpty()) {
527 m_ui.lblWarning->setVisible(
false);
529 m_ui.lblWarning->setText(warnings.join(
" "));
530 m_ui.lblWarning->setPixmap(
531 m_ui.lblWarning->style()->standardIcon(QStyle::SP_MessageBoxWarning).pixmap(QSize(32, 32)));
532 m_ui.lblWarning->setVisible(
true);
555 dialog.setDefaultDir(QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).last());
556 dialog.setCaption(i18n(
"Open FFProbe"));
560 if (!filenames.isEmpty()) {
563 if (ffprobeInfo[
"enabled"].toBool() && ffprobeInfo[
"custom"].toBool()) {
564 m_ui.cmbFFProbeLocation->addItem(filenames[0],ffprobeInfo);
565 m_ui.cmbFFProbeLocation->setCurrentText(filenames[0]);
568 QMessageBox::warning(
this, i18nc(
"@title:window",
"Krita"), i18n(
"FFProbe is invalid!"));
576 dialog.setDefaultDir(QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).last());
577 dialog.setCaption(i18n(
"Open FFMpeg"));
581 if (!filenames.isEmpty()) {
584 if (ffmpegInfo[
"enabled"].toBool()) {
585 if (ffmpegInfo[
"custom"].toBool()) {
586 m_ui.cmbFFMpegLocation->addItem(filenames[0],ffmpegInfo);
587 m_ui.cmbFFMpegLocation->setCurrentText(filenames[0]);
589 QMessageBox::warning(
this, i18nc(
"@title:window",
"Krita"), i18n(
"FFMpeg is invalid!"));
591 m_ui.tabGeneral->setEnabled(
true);
595 m_ui.tabGeneral->setEnabled(
false);
596 QMessageBox::critical(
this, i18nc(
"@title:window",
"Krita"), i18n(
"No FFMpeg found!"));
603 bool toggleDocumentOptions = selectedIndex == 0;
605 if (toggleDocumentOptions) {
606 m_ui.fpsDocumentLabel->setText(
" ");
614 m_ui.fpsDocumentLabel->setText(i18nc(
"Video importer: fps of the document you're importing into"
615 ,
"<small>Document:\n %1 FPS</small>"
620 m_ui.optionsDocumentGroup->setEnabled(toggleDocumentOptions);
634 float currentSeconds = 0;
638 dbgFile <<
"Frame change to:" << frame;
650 m_ui.videoPreviewSliderValueLabel->setText( QString::number(currentSeconds,
'f', 2).append(i18nc(
"Second as a unit following a value, like 60 s",
" s")) );
655 QJsonObject ffmpegInfo =
m_ui.cmbFFMpegLocation->currentData().toJsonObject();
656 QJsonObject ffprobeInfo =
m_ui.cmbFFProbeLocation->currentData().toJsonObject();
660 QJsonObject ffprobeJsonObj;
662 std::function<
void(
void)> warnFFmpegFormatSupport = [
this](){
663 QMessageBox::warning(
this, i18nc(
"@title:window",
"Krita"), i18n(
"Your FFMpeg version does not support this format"));
666 if (ffprobeInfo[
"enabled"].toBool()) {
667 ffprobeJsonObj = ffprobe->ffprobe(inputFile, ffprobeInfo[
"path"].toString());
674 ffprobeJsonObj = ffmpeg->
ffmpegProbe(inputFile, ffmpegInfo[
"path"].toString(),
false);
676 dbgFile <<
"ffmpeg probe1" << ffprobeJsonObj;
678 QJsonObject ffprobeProgress = ffprobeJsonObj[
"progress"].toObject();
680 videoInfoData.
frames = ffprobeProgress[
"frame"].toString().toInt();
685 warnFFmpegFormatSupport();
689 QJsonObject ffprobeFormat = ffprobeJsonObj[
"format"].toObject();
690 QJsonArray ffprobeStreams = ffprobeJsonObj[
"streams"].toArray();
692 videoInfoData.
file = inputFile;
693 for (
const QJsonValueRef &streamItemRef : ffprobeStreams) {
694 QJsonObject streamItemObj = streamItemRef.toObject();
696 if ( streamItemObj[
"codec_type"].toString() ==
"video" ) {
697 videoInfoData.
stream = streamItemObj[
"index"].toInt();
702 if ( videoInfoData.
stream == -1 ) {
703 QMessageBox::warning(
this, i18nc(
"@title:window",
"Krita"), i18n(
"No video stream could be found!"));
707 const QJsonObject ffprobeSelectedStream = ffprobeStreams[videoInfoData.
stream].toObject();
709 const QJsonObject decoders = ffmpegInfo.value(
"codecs").toObject();
711 const QString codecName = ffprobeSelectedStream[
"codec_name"].toString();
713 const auto decoder = decoders.constFind(codecName);
715 if (decoder == decoders.constEnd() ) {
716 dbgFile <<
"Codec missing or unsupported:" << codecName;
717 warnFFmpegFormatSupport();
719 }
else if (!decoder->toObject().value(
"decoding").toBool()) {
720 dbgFile <<
"Codec not supported for decoding:" << codecName;
721 warnFFmpegFormatSupport();
725 videoInfoData.
width = ffprobeSelectedStream[
"width"].toInt();
726 videoInfoData.
height = ffprobeSelectedStream[
"height"].toInt();
727 videoInfoData.
encoding = ffprobeSelectedStream[
"codec_name"].toString();
732 if (ffprobeSelectedStream.value(
"bits_per_raw_sample").toInt() > 8) {
740 QStringList rawFrameRate = ffprobeSelectedStream[
"r_frame_rate"].toString().split(
'/');
742 if (!rawFrameRate.isEmpty())
743 videoInfoData.
fps = qCeil(rawFrameRate[0].toFloat() / rawFrameRate[1].toFloat());
745 if ( !ffprobeSelectedStream[
"nb_frames"].isNull() ) {
746 videoInfoData.
frames = ffprobeSelectedStream[
"nb_frames"].toString().toInt();
750 if ( !ffprobeSelectedStream[
"duration"].isNull() ) {
751 videoInfoData.
duration = ffprobeSelectedStream[
"duration"].toString().toFloat();
752 }
else if ( !ffprobeFormat[
"duration"].isNull() ) {
753 videoInfoData.
duration = ffprobeFormat[
"duration"].toString().toFloat();
754 }
else if ( videoInfoData.
frames ) {
758 dbgFile <<
"Initial video info from probe: "
759 <<
"stream:" << videoInfoData.
stream
760 <<
"frames:" << videoInfoData.
frames
761 <<
"duration:" << videoInfoData.
duration
762 <<
"fps:" << videoInfoData.
fps
763 <<
"encoding:" << videoInfoData.
encoding;
768 QJsonObject ffmpegJsonObj = ffmpeg->
ffmpegProbe(inputFile, ffmpegInfo[
"path"].toString(),
false);
770 dbgFile <<
"ffmpeg probe2" << ffmpegJsonObj;
773 QMessageBox::warning(
this, i18nc(
"@title:window",
"Krita"), i18n(
"Failed to load video information"));
777 QJsonObject ffmpegProgressJsonObj = ffmpegJsonObj[
"progress"].toObject();
778 float ffmpegFPS = ffmpegProgressJsonObj[
"ffmpeg_fps"].toString().toFloat();
780 videoInfoData.
frames = ffmpegProgressJsonObj[
"frame"].toString().toInt();
782 if (ffmpegFPS > 0 && videoInfoData.
frames) {
784 videoInfoData.
fps = ffmpegFPS;
786 videoInfoData.
duration = ffmpegProgressJsonObj[
"out_time_ms"].toString().toFloat() / 1000000;
798 dbgFile <<
"Final video info from probe: "
799 <<
"stream:" << videoInfoData.
stream
800 <<
"frames:" << videoInfoData.
frames
801 <<
"duration:" << videoInfoData.
duration
802 <<
"fps:" << videoInfoData.
fps
803 <<
"encoding:" << videoInfoData.
encoding;
805 const float calculatedFrameRateByDuration = videoInfoData.
frames / videoInfoData.
duration;
806 const int frameRateDifference = qAbs(videoInfoData.
fps - calculatedFrameRateByDuration);
808 if (frameRateDifference > 1) {
812 videoInfoData.
fps = calculatedFrameRateByDuration;
817 return videoInfoData;
float value(const T *src, size_t ch)
float rerange(float value, float oldMin, float oldMax, float newMin, float newMax)
QList< QString > QStringList
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
@ TRC_ITU_R_BT_2100_0_HLG
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
KisPropertiesConfigurationSP exportConfiguration(const QString &filterId, bool defaultValue=false) const
void setExportConfiguration(const QString &filterId, KisPropertiesConfigurationSP properties) const
KisBasicVideoInfo m_videoInfo
KisPropertiesConfigurationSP loadLastUsedConfiguration(QString configurationID)
QStringList showOpenFileDialog()
KisDlgImportVideoAnimation(KisMainWindow *m_mainWindow, KisView *m_activeView)
void slotVideoTimerTimeout()
void loadVideoFile(const QString &filename)
QStringList makeVideoMimeTypesList()
RenderedFrames renderFrames(const QDir &directory)
void slotImportDurationChanged(qreal time)
void slotFrameNumberChanged(int frame)
void saveLastUsedConfiguration(QString configurationID, KisPropertiesConfigurationSP config)
KisBasicVideoInfo loadVideoInfo(const QString &inputFile)
void updateVideoPreview()
QStringList documentInfo()
Ui_VideoImportDialog m_ui
void slotDocumentHandlerChanged(int selectedIndex)
QTimer * m_videoSliderTimer
void toggleInputControls(bool toggleBool)
void slotVideoSliderChanged()
void CurrentFrameChanged(int frame)
static TransferCharacteristics transferCharacteristicsFromName(QString name)
static QJsonObject findFFProbe(const QString &customLocation)
void sigReadSTDOUT(QByteArray stdoutBuffer)
QJsonObject ffmpegProbe(const QString &inputFile, const QString &ffmpegPath, bool batchMode)
static ColorPrimaries colorPrimariesFromName(QString name)
static QJsonObject findFFMpeg(const QString &customLocation)
static QByteArray runProcessAndReturn(const QString &processPath, const QStringList &args, int msecs=FFMPEG_TIMEOUT)
void fileSelected(const QString &fileName)
const KoColorSpace * colorSpace() const
KisImageWSP image() const
QPointer< KisDocument > document
virtual quint32 pixelSize() const =0
A dialog base class with standard buttons and predefined layouts.
void enableButtonOk(bool state)
void setMainWidget(QWidget *widget)
void setButtons(ButtonCodes buttonMask)
void setDefaultButton(ButtonCode id)
@ Ok
Show Ok button. (this button accept()s the dialog; result set to QDialog::Accepted)
@ Cancel
Show Cancel-button. (this button reject()s the dialog; result set to QDialog::Rejected)
typedef void(QOPENGLF_APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer)
QIcon loadIcon(const QString &name)
ColorPrimaries colorPrimaries
TransferCharacteristics colorTransfer
QStringList defaultPrependArgs
Statistics fetchMemoryStatistics(KisImageSP image) const
static KisMemoryStatisticsServer * instance()
static QString getTransferCharacteristicName(TransferCharacteristics curve)
getTransferCharacteristicName
static QString getColorPrimariesName(ColorPrimaries primaries)
getColorPrimariesName
virtual QString colorModelID() const
const KoColorProfile * profileFor(const QVector< double > &colorants, ColorPrimaries colorPrimaries, TransferCharacteristics transferFunction) const
profileFor tries to find the profile that matches these characteristics, if no such profile is found,...
static KoColorSpaceRegistry * instance()
const KoColorProfile * p709SRGBProfile() const
QList< int > renderedFrameTargetTimes
QStringList renderedFrameFiles