Welcome to lark3ri.com

Video Photographer

30.05.2022

Generating a single image from a video or movie file, with or without metadata. Extracted metadata can be also edited. Spesified can also be the starting and the end times and how many pictures are taken from between those times. Application "Thumbnail me" was weird to install and use on Linux, felt kind of clunky and full of stuff that i don't need. I just wanted a clear application that can generate pictures from videos, similar results what the "Thumbnail me" application does.

I programmed my own similar program with C++ and here it is. Project download link below. AppImage is also included in it, but it might not work on every supported Linux computer due to the difficulties to actually be able to generate the AppImage in the oldest supported version of Linux.

This project uses Qt software framework and C++ language. OpenCV is also used to extract images from the video accurately. ffmpeg and stat is also used to extract the metadata of the video. You might need to install some additional libraries to be able to run the AppImage. Just see the error messages and install what it needs.

If ffmpeg or stat is not located in the paths /usr/bin/ffmpeg and /usr/bin/stat this application will not run. Instead it shows the information box to notify user that it cannot find those applications from the default paths. User can specify the specific paths with command line parameters as follows --ffmpeg <path> and --stat <path>.

Download AppImage for Linux x86_64
Current version: 1.6

The complete Qt project can be downloaded as a 7z file from this download link. Here is also a picture of the application and all of the codes as well. Specifying the license agreements: The programming codes in this site is licensed under the GNU General Public License, version 2 only, not version 3 or whatever, as mentioned in bottom of every page on this website.

main_window.cpp
/*
Copyright (C) 2022 Lari Varjonen <[email protected]>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "main_window.h"
#include "ui_main_window.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
show();
setWindowTitle(app_name);
fe = new FramesExtractor();
draw_pixmap = new DrawPixmap();
image_label = new QLabel();
image_label->setAlignment(Qt::AlignTop | Qt::AlignLeft);
image_label->setStyleSheet("background-color:black;");
ui->scroll_area->setWidget(image_label);
setAcceptDrops(true);
}
MainWindow::~MainWindow()
{
delete fe;
delete draw_pixmap;
delete ui;
delete image_label;
}
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasUrls())
{
event->acceptProposedAction();
}
}
void MainWindow::dropEvent(QDropEvent *e)
{
const QUrl url = e->mimeData()->urls().at(0);
QString new_video_path = url.toLocalFile();
if (fe->set_video(new_video_path))
{
InfoView iv(InfoView::window_type::ok,
"Invalid video file.",
"File is not a valid video file.",
this);
iv.exec();
return;
}
current_video_path = url.toLocalFile();
update_video_info();
on_generate_image_button_clicked();
}
void MainWindow::on_select_video_button_clicked()
{
QString new_video_path = QFileDialog::getOpenFileName(this, tr("Select a video file"), QDir::currentPath());
if (new_video_path.isEmpty())
{
return;
}
if (fe->set_video(new_video_path))
{
InfoView iv(InfoView::window_type::ok,
"Invalid video file.",
"File is not a valid video file.",
this);
iv.exec();
return;
}
current_video_path = new_video_path;
update_video_info();
}
void MainWindow::on_generate_image_button_clicked()
{
if (current_video_path.isEmpty())
{
return;
}
count_spin = ui->count_spin->value();
draw_pixmap->images.clear();
draw_pixmap->time_stamps.clear();
draw_pixmap->width_spin = ui->width_spin->value();
draw_pixmap->divider_spin = ui->divider_spin->value();
draw_pixmap->starting_height = 200;
on_updatetext_button_clicked();
int s_h = ui->start_h_spin->value();
int s_m = ui->start_m_spin->value();
int s_s = ui->start_s_spin->value();
start_time = (s_h * 60 * 60) + (s_m * 60) + s_s;
int e_h = ui->end_h_spin->value();
int e_m = ui->end_m_spin->value();
int e_s = ui->end_s_spin->value();
end_time = (e_h * 60 * 60) + (e_m * 60) + e_s;
double start_frame = start_time * current_video_fps;
double end_frame = end_time * current_video_fps;
if (start_frame > end_frame)
{
start_frame = end_frame;
}
if (start_frame > video_frame_count - current_video_fps)
{
start_frame = video_frame_count;
}
if (end_frame > video_frame_count - current_video_fps)
{
end_frame = video_frame_count;
}
get_pictures_from_video(start_frame, end_frame);
draw_pixmap->draw_pixmap(app_name);
image_label->setPixmap(draw_pixmap->generated_pixmap);
}
void MainWindow::on_updatetext_button_clicked()
{
if (current_video_path.isEmpty())
{
return;
}
draw_pixmap->file_text = ui->file_text->text();
draw_pixmap->video_text = ui->video_text->text();
draw_pixmap->audio_text = ui->audio_text->text();
draw_pixmap->size_text = ui->size_text->text();
draw_pixmap->draw_pixmap(app_name);
image_label->setPixmap(draw_pixmap->generated_pixmap);
}
void MainWindow::on_save_image_button_clicked()
{
if (draw_pixmap->generated_pixmap.isNull())
{
return;
}
QString new_file_path = QFileDialog::getSaveFileName(this,
tr("Save .png File"),
QDir::currentPath(),
tr("Images (*.png)"));
if (new_file_path.isEmpty())
{
return;
}
QFile file(new_file_path);
if(file.exists())
{
InfoView iv(InfoView::window_type::qa,
"File already exists.",
"File already exists. Do you want to overwrite it?",
this);
iv.exec();
if (iv.result_answer)
{
return;
}
}
draw_pixmap->generated_pixmap.save(new_file_path, "PNG");
}
void MainWindow::update_video_info()
{
QMap<QString, QString> map_ss = get_video_info(current_video_path);
video_frame_count = fe->get_video_frame_count();
current_video_fps = fe->get_video_fps();
QString duration = map_ss.value("duration-info");
QStringList strl = duration.split(":");
int duration_h = strl.at(0).toInt();
int duration_m = strl.at(1).toInt();
int duration_s = int(strl.at(2).toDouble());
ui->end_h_spin->setValue(duration_h);
ui->end_m_spin->setValue(duration_m);
ui->end_s_spin->setValue(duration_s);
QString file_text = map_ss.value("file-name");
QString video_text = map_ss.value("video-info");
QString audio_text = map_ss.value("audio-info");
QString bytes = map_ss.value("size-in-bytes");
QString in_MiB = map_ss.value("size-in-MiB");
QString size_text = tr("%1 bytes (%2), duration: %3")
.arg(bytes, in_MiB, duration);
ui->file_text->setText(file_text);
ui->video_text->setText(video_text);
ui->audio_text->setText(audio_text);
ui->size_text->setText(size_text);
ui->file_text->setCursorPosition(0);
ui->video_text->setCursorPosition(0);
ui->audio_text->setCursorPosition(0);
ui->size_text->setCursorPosition(0);
QFileInfo file_info(current_video_path);
QString file_name = file_info.fileName();
QString dir_name = file_info.absoluteDir().dirName();
setWindowTitle(tr("%1 @ %2 - %3").arg(file_name, dir_name, app_name));
}
QMap<QString, QString> MainWindow::get_video_info(QString video_path)
{
QProcess qp;
qp.setProgram(FFMPEG_EXE);
QStringList qp_args;
qp_args << "-i" << video_path;
qp.setArguments(qp_args);
qp.start();
qp.waitForFinished(-1);
QByteArray ba_result = qp.readAllStandardError();
QString s_result = QString(ba_result);
QMap<QString, QString> result_map;
s_result.replace('\n', " ");
while (s_result.contains(" "))
{
s_result.replace(" ", " ");
}
// Get name.
QString file_name = video_path.split("/").last();
result_map.insert("file-name", file_name);
QRegularExpression re;
QRegularExpressionMatch match;
// Get video.
re.setPattern(": Video: (.*?) Metadata:");
match = re.match(s_result);
if (match.hasMatch())
{
result_map.insert("video-info", match.captured(1));
}
else
{
result_map.insert("video-info", "<unknown video>");
}
// Get audio.
re.setPattern(": Audio: (.*?) Metadata:");
match = re.match(s_result);
if (match.hasMatch())
{
result_map.insert("audio-info", match.captured(1));
}
else
{
result_map.insert("audio-info", "<unknown audio>");
}
// Get duration.
re.setPattern("Duration: (.*?), ");
match = re.match(s_result);
if (match.hasMatch())
{
result_map.insert("duration-info", match.captured(1));
}
else
{
result_map.insert("duration-info", "<unknown duration>");
}
// Get bitrate.
re.setPattern(", bitrate: (.*? .*?) ");
match = re.match(s_result);
if (match.hasMatch())
{
result_map.insert("bitrate", match.captured(1));
}
else
{
result_map.insert("bitrate", "<unknown bitrate>");
}
// Get size in bytes and MiB.
qp.setProgram(STAT_EXE);
qp_args.clear();
qp_args << "--printf=\"%s\"" << video_path;
qp.setArguments(qp_args);
qp.start();
qp.waitForFinished(-1);
ba_result = qp.readAllStandardOutput();
s_result = QString(ba_result);
if (s_result.size() > 0)
{
s_result.replace("\"", "");
result_map.insert("size-in-bytes", s_result);
int bytes = s_result.toInt();
int size_MiB = ceil(bytes / 1024.0 / 1024.0);
s_result = QString::number(size_MiB) + "MiB";
result_map.insert("size-in-MiB", s_result);
}
else
{
result_map.insert("size-in-bytes", "<unknown byte size>");
result_map.insert("size-in-MiB", "<unknown MiB size>");
}
return result_map;
}
QString MainWindow::get_random_string(int size)
{
QString chars("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
QString return_str;
for(int i = 0; i < size; ++i)
{
int index = QRandomGenerator::global()->bounded(chars.size());
QChar c = chars.at(index);
return_str.append(c);
}
return return_str;
}
void MainWindow::get_pictures_from_video(double start_frame,
double end_frame)
{
QString random_name = get_random_string(8);
QString out_dir_path = tr("/tmp/%1/").arg(random_name);
while (QDir(out_dir_path).exists())
{
random_name = get_random_string(8);
out_dir_path = tr("/tmp/%1/").arg(random_name);
}
bool mkpath_result = QDir().mkpath(out_dir_path);
if (!mkpath_result)
{
return;
}
// Generate all pictures to temp dir.
Processing proc_ui(this);
fe->set(current_video_path,
out_dir_path,
count_spin,
start_frame,
end_frame,
current_video_fps);
connect(fe, &FramesExtractor::set_max, &proc_ui, &Processing::set_max);
connect(fe, &FramesExtractor::set_value, &proc_ui, &Processing::set_value);
connect(fe, &FramesExtractor::process_done, &proc_ui, &Processing::on_cancel_button_clicked);
fe->start();
proc_ui.exec();
fe->stop_work();
fe->wait();
// Read all pictures from temp dir.
QDir dir(out_dir_path);
dir.setSorting(QDir::NoSort);
dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
QStringList imgs = dir.entryList(QStringList() << "*.jpg", QDir::Files);
if (imgs.isEmpty())
{
if (!QDir(out_dir_path).removeRecursively())
{
qCritical() << "Unable to remove temp directory.";
}
return;
}
QCollator coll;
coll.setNumericMode(true);
std::sort(imgs.begin(), imgs.end(), coll);
for (qsizetype i = 0; i < imgs.size(); i++)
{
QString file_name = imgs.at(i);
// Get image.
QUrl url = QUrl(tr("file://") + out_dir_path + file_name);
QImage image(url.path());
QImage img_scaled(image.scaledToWidth(
draw_pixmap->width_spin/draw_pixmap->divider_spin,
Qt::FastTransformation
));
draw_pixmap->images.push_back(img_scaled);
// Get image timestamp.
QRegularExpression re;
QRegularExpressionMatch match;
re.setPattern("\\[(.*)\\]");
match = re.match(file_name);
if (match.hasMatch())
{
draw_pixmap->time_stamps.push_back(match.captured(1));
}
}
// Fixing the last timestamp
// because the video fps value is just not accurate enough.
int e_h = ui->end_h_spin->value();
int e_m = ui->end_m_spin->value();
int e_s = ui->end_s_spin->value();
QString se_h = QString::number(e_h).rightJustified(2, '0');
QString se_m = QString::number(e_m).rightJustified(2, '0');
QString se_s = QString::number(e_s).rightJustified(2, '0');
QString new_last_timestamp = QString("%1:%2:%3").arg(se_h, se_m, se_s);
draw_pixmap->time_stamps.last() = new_last_timestamp;
if (!QDir(out_dir_path).removeRecursively())
{
qCritical() << "Unable to remove temp directory.";
}
}
void MainWindow::on_action_About_triggered()
{
AboutWindow aw(app_name, app_version, this);
aw.exec();
}
void MainWindow::on_action_Exit_triggered()
{
QApplication::quit();
}
void MainWindow::on_action_hide_signature_changed()
{
draw_pixmap->hide_signature = ui->action_hide_signature->isChecked();
on_updatetext_button_clicked();
}
void MainWindow::on_action_hide_timestamp_changed()
{
draw_pixmap->hide_timestamp = ui->action_hide_timestamp->isChecked();
draw_pixmap->draw_pixmap(app_name);
image_label->setPixmap(draw_pixmap->generated_pixmap);
}
/* Copyright (C) 2022 Lari Varjonen <[email protected]> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "main_window.h" #include "ui_main_window.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); show(); setWindowTitle(app_name); fe = new FramesExtractor(); draw_pixmap = new DrawPixmap(); image_label = new QLabel(); image_label->setAlignment(Qt::AlignTop | Qt::AlignLeft); image_label->setStyleSheet("background-color:black;"); ui->scroll_area->setWidget(image_label); setAcceptDrops(true); } MainWindow::~MainWindow() { delete fe; delete draw_pixmap; delete ui; delete image_label; } void MainWindow::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasUrls()) { event->acceptProposedAction(); } } void MainWindow::dropEvent(QDropEvent *e) { const QUrl url = e->mimeData()->urls().at(0); QString new_video_path = url.toLocalFile(); if (fe->set_video(new_video_path)) { InfoView iv(InfoView::window_type::ok, "Invalid video file.", "File is not a valid video file.", this); iv.exec(); return; } current_video_path = url.toLocalFile(); update_video_info(); on_generate_image_button_clicked(); } void MainWindow::on_select_video_button_clicked() { QString new_video_path = QFileDialog::getOpenFileName(this, tr("Select a video file"), QDir::currentPath()); if (new_video_path.isEmpty()) { return; } if (fe->set_video(new_video_path)) { InfoView iv(InfoView::window_type::ok, "Invalid video file.", "File is not a valid video file.", this); iv.exec(); return; } current_video_path = new_video_path; update_video_info(); } void MainWindow::on_generate_image_button_clicked() { if (current_video_path.isEmpty()) { return; } count_spin = ui->count_spin->value(); draw_pixmap->images.clear(); draw_pixmap->time_stamps.clear(); draw_pixmap->width_spin = ui->width_spin->value(); draw_pixmap->divider_spin = ui->divider_spin->value(); draw_pixmap->starting_height = 200; on_updatetext_button_clicked(); int s_h = ui->start_h_spin->value(); int s_m = ui->start_m_spin->value(); int s_s = ui->start_s_spin->value(); start_time = (s_h * 60 * 60) + (s_m * 60) + s_s; int e_h = ui->end_h_spin->value(); int e_m = ui->end_m_spin->value(); int e_s = ui->end_s_spin->value(); end_time = (e_h * 60 * 60) + (e_m * 60) + e_s; double start_frame = start_time * current_video_fps; double end_frame = end_time * current_video_fps; if (start_frame > end_frame) { start_frame = end_frame; } if (start_frame > video_frame_count - current_video_fps) { start_frame = video_frame_count; } if (end_frame > video_frame_count - current_video_fps) { end_frame = video_frame_count; } get_pictures_from_video(start_frame, end_frame); draw_pixmap->draw_pixmap(app_name); image_label->setPixmap(draw_pixmap->generated_pixmap); } void MainWindow::on_updatetext_button_clicked() { if (current_video_path.isEmpty()) { return; } draw_pixmap->file_text = ui->file_text->text(); draw_pixmap->video_text = ui->video_text->text(); draw_pixmap->audio_text = ui->audio_text->text(); draw_pixmap->size_text = ui->size_text->text(); draw_pixmap->draw_pixmap(app_name); image_label->setPixmap(draw_pixmap->generated_pixmap); } void MainWindow::on_save_image_button_clicked() { if (draw_pixmap->generated_pixmap.isNull()) { return; } QString new_file_path = QFileDialog::getSaveFileName(this, tr("Save .png File"), QDir::currentPath(), tr("Images (*.png)")); if (new_file_path.isEmpty()) { return; } QFile file(new_file_path); if(file.exists()) { InfoView iv(InfoView::window_type::qa, "File already exists.", "File already exists. Do you want to overwrite it?", this); iv.exec(); if (iv.result_answer) { return; } } draw_pixmap->generated_pixmap.save(new_file_path, "PNG"); } void MainWindow::update_video_info() { QMap<QString, QString> map_ss = get_video_info(current_video_path); video_frame_count = fe->get_video_frame_count(); current_video_fps = fe->get_video_fps(); QString duration = map_ss.value("duration-info"); QStringList strl = duration.split(":"); int duration_h = strl.at(0).toInt(); int duration_m = strl.at(1).toInt(); int duration_s = int(strl.at(2).toDouble()); ui->end_h_spin->setValue(duration_h); ui->end_m_spin->setValue(duration_m); ui->end_s_spin->setValue(duration_s); QString file_text = map_ss.value("file-name"); QString video_text = map_ss.value("video-info"); QString audio_text = map_ss.value("audio-info"); QString bytes = map_ss.value("size-in-bytes"); QString in_MiB = map_ss.value("size-in-MiB"); QString size_text = tr("%1 bytes (%2), duration: %3") .arg(bytes, in_MiB, duration); ui->file_text->setText(file_text); ui->video_text->setText(video_text); ui->audio_text->setText(audio_text); ui->size_text->setText(size_text); ui->file_text->setCursorPosition(0); ui->video_text->setCursorPosition(0); ui->audio_text->setCursorPosition(0); ui->size_text->setCursorPosition(0); QFileInfo file_info(current_video_path); QString file_name = file_info.fileName(); QString dir_name = file_info.absoluteDir().dirName(); setWindowTitle(tr("%1 @ %2 - %3").arg(file_name, dir_name, app_name)); } QMap<QString, QString> MainWindow::get_video_info(QString video_path) { QProcess qp; qp.setProgram(FFMPEG_EXE); QStringList qp_args; qp_args << "-i" << video_path; qp.setArguments(qp_args); qp.start(); qp.waitForFinished(-1); QByteArray ba_result = qp.readAllStandardError(); QString s_result = QString(ba_result); QMap<QString, QString> result_map; s_result.replace('\n', " "); while (s_result.contains(" ")) { s_result.replace(" ", " "); } // Get name. QString file_name = video_path.split("/").last(); result_map.insert("file-name", file_name); QRegularExpression re; QRegularExpressionMatch match; // Get video. re.setPattern(": Video: (.*?) Metadata:"); match = re.match(s_result); if (match.hasMatch()) { result_map.insert("video-info", match.captured(1)); } else { result_map.insert("video-info", "<unknown video>"); } // Get audio. re.setPattern(": Audio: (.*?) Metadata:"); match = re.match(s_result); if (match.hasMatch()) { result_map.insert("audio-info", match.captured(1)); } else { result_map.insert("audio-info", "<unknown audio>"); } // Get duration. re.setPattern("Duration: (.*?), "); match = re.match(s_result); if (match.hasMatch()) { result_map.insert("duration-info", match.captured(1)); } else { result_map.insert("duration-info", "<unknown duration>"); } // Get bitrate. re.setPattern(", bitrate: (.*? .*?) "); match = re.match(s_result); if (match.hasMatch()) { result_map.insert("bitrate", match.captured(1)); } else { result_map.insert("bitrate", "<unknown bitrate>"); } // Get size in bytes and MiB. qp.setProgram(STAT_EXE); qp_args.clear(); qp_args << "--printf=\"%s\"" << video_path; qp.setArguments(qp_args); qp.start(); qp.waitForFinished(-1); ba_result = qp.readAllStandardOutput(); s_result = QString(ba_result); if (s_result.size() > 0) { s_result.replace("\"", ""); result_map.insert("size-in-bytes", s_result); int bytes = s_result.toInt(); int size_MiB = ceil(bytes / 1024.0 / 1024.0); s_result = QString::number(size_MiB) + "MiB"; result_map.insert("size-in-MiB", s_result); } else { result_map.insert("size-in-bytes", "<unknown byte size>"); result_map.insert("size-in-MiB", "<unknown MiB size>"); } return result_map; } QString MainWindow::get_random_string(int size) { QString chars("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); QString return_str; for(int i = 0; i < size; ++i) { int index = QRandomGenerator::global()->bounded(chars.size()); QChar c = chars.at(index); return_str.append(c); } return return_str; } void MainWindow::get_pictures_from_video(double start_frame, double end_frame) { QString random_name = get_random_string(8); QString out_dir_path = tr("/tmp/%1/").arg(random_name); while (QDir(out_dir_path).exists()) { random_name = get_random_string(8); out_dir_path = tr("/tmp/%1/").arg(random_name); } bool mkpath_result = QDir().mkpath(out_dir_path); if (!mkpath_result) { return; } // Generate all pictures to temp dir. Processing proc_ui(this); fe->set(current_video_path, out_dir_path, count_spin, start_frame, end_frame, current_video_fps); connect(fe, &FramesExtractor::set_max, &proc_ui, &Processing::set_max); connect(fe, &FramesExtractor::set_value, &proc_ui, &Processing::set_value); connect(fe, &FramesExtractor::process_done, &proc_ui, &Processing::on_cancel_button_clicked); fe->start(); proc_ui.exec(); fe->stop_work(); fe->wait(); // Read all pictures from temp dir. QDir dir(out_dir_path); dir.setSorting(QDir::NoSort); dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot); QStringList imgs = dir.entryList(QStringList() << "*.jpg", QDir::Files); if (imgs.isEmpty()) { if (!QDir(out_dir_path).removeRecursively()) { qCritical() << "Unable to remove temp directory."; } return; } QCollator coll; coll.setNumericMode(true); std::sort(imgs.begin(), imgs.end(), coll); for (qsizetype i = 0; i < imgs.size(); i++) { QString file_name = imgs.at(i); // Get image. QUrl url = QUrl(tr("file://") + out_dir_path + file_name); QImage image(url.path()); QImage img_scaled(image.scaledToWidth( draw_pixmap->width_spin/draw_pixmap->divider_spin, Qt::FastTransformation )); draw_pixmap->images.push_back(img_scaled); // Get image timestamp. QRegularExpression re; QRegularExpressionMatch match; re.setPattern("\\[(.*)\\]"); match = re.match(file_name); if (match.hasMatch()) { draw_pixmap->time_stamps.push_back(match.captured(1)); } } // Fixing the last timestamp // because the video fps value is just not accurate enough. int e_h = ui->end_h_spin->value(); int e_m = ui->end_m_spin->value(); int e_s = ui->end_s_spin->value(); QString se_h = QString::number(e_h).rightJustified(2, '0'); QString se_m = QString::number(e_m).rightJustified(2, '0'); QString se_s = QString::number(e_s).rightJustified(2, '0'); QString new_last_timestamp = QString("%1:%2:%3").arg(se_h, se_m, se_s); draw_pixmap->time_stamps.last() = new_last_timestamp; if (!QDir(out_dir_path).removeRecursively()) { qCritical() << "Unable to remove temp directory."; } } void MainWindow::on_action_About_triggered() { AboutWindow aw(app_name, app_version, this); aw.exec(); } void MainWindow::on_action_Exit_triggered() { QApplication::quit(); } void MainWindow::on_action_hide_signature_changed() { draw_pixmap->hide_signature = ui->action_hide_signature->isChecked(); on_updatetext_button_clicked(); } void MainWindow::on_action_hide_timestamp_changed() { draw_pixmap->hide_timestamp = ui->action_hide_timestamp->isChecked(); draw_pixmap->draw_pixmap(app_name); image_label->setPixmap(draw_pixmap->generated_pixmap); }
/*
    Copyright (C) 2022 Lari Varjonen <[email protected]>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "main_window.h"
#include "ui_main_window.h"


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    show();
    setWindowTitle(app_name);

    fe = new FramesExtractor();
    draw_pixmap = new DrawPixmap();
    image_label = new QLabel();

    image_label->setAlignment(Qt::AlignTop | Qt::AlignLeft);
    image_label->setStyleSheet("background-color:black;");

    ui->scroll_area->setWidget(image_label);
    setAcceptDrops(true);
}

MainWindow::~MainWindow()
{
    delete fe;
    delete draw_pixmap;
    delete ui;
    delete image_label;
}

void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
    if (event->mimeData()->hasUrls())
    {
        event->acceptProposedAction();
    }
}

void MainWindow::dropEvent(QDropEvent *e)
{
    const QUrl url = e->mimeData()->urls().at(0);
    QString new_video_path = url.toLocalFile();


    if (fe->set_video(new_video_path))
    {
        InfoView iv(InfoView::window_type::ok,
                    "Invalid video file.",
                    "File is not a valid video file.",
                    this);
        iv.exec();
        return;
    }

    current_video_path = url.toLocalFile();
    update_video_info();
    on_generate_image_button_clicked();
}

void MainWindow::on_select_video_button_clicked()
{
    QString new_video_path = QFileDialog::getOpenFileName(this, tr("Select a video file"), QDir::currentPath());

    if (new_video_path.isEmpty())
    {
        return;
    }


    if (fe->set_video(new_video_path))
    {
        InfoView iv(InfoView::window_type::ok,
                    "Invalid video file.",
                    "File is not a valid video file.",
                    this);
        iv.exec();
        return;
    }

    current_video_path = new_video_path;
    update_video_info();
}

void MainWindow::on_generate_image_button_clicked()
{
    if (current_video_path.isEmpty())
    {
        return;
    }

    count_spin = ui->count_spin->value();

    draw_pixmap->images.clear();
    draw_pixmap->time_stamps.clear();

    draw_pixmap->width_spin = ui->width_spin->value();
    draw_pixmap->divider_spin = ui->divider_spin->value();
    draw_pixmap->starting_height = 200;

    on_updatetext_button_clicked();

    int s_h = ui->start_h_spin->value();
    int s_m = ui->start_m_spin->value();
    int s_s = ui->start_s_spin->value();
    start_time = (s_h * 60 * 60) + (s_m * 60) + s_s;

    int e_h = ui->end_h_spin->value();
    int e_m = ui->end_m_spin->value();
    int e_s = ui->end_s_spin->value();
    end_time = (e_h * 60 * 60) + (e_m * 60) + e_s;

    double start_frame = start_time * current_video_fps;
    double end_frame = end_time * current_video_fps;

    if (start_frame > end_frame)
    {
        start_frame = end_frame;
    }
    if (start_frame > video_frame_count - current_video_fps)
    {
        start_frame = video_frame_count;
    }
    if (end_frame > video_frame_count - current_video_fps)
    {
        end_frame = video_frame_count;
    }

    get_pictures_from_video(start_frame, end_frame);

    draw_pixmap->draw_pixmap(app_name);
    image_label->setPixmap(draw_pixmap->generated_pixmap);
}

void MainWindow::on_updatetext_button_clicked()
{
    if (current_video_path.isEmpty())
    {
        return;
    }

    draw_pixmap->file_text = ui->file_text->text();
    draw_pixmap->video_text = ui->video_text->text();
    draw_pixmap->audio_text = ui->audio_text->text();
    draw_pixmap->size_text = ui->size_text->text();

    draw_pixmap->draw_pixmap(app_name);
    image_label->setPixmap(draw_pixmap->generated_pixmap);
}

void MainWindow::on_save_image_button_clicked()
{
    if (draw_pixmap->generated_pixmap.isNull())
    {
        return;
    }
    QString new_file_path = QFileDialog::getSaveFileName(this,
                                                    tr("Save .png File"),
                                                    QDir::currentPath(),
                                                    tr("Images (*.png)"));
    if (new_file_path.isEmpty())
    {
        return;
    }
    QFile file(new_file_path);
    if(file.exists())
    {
        InfoView iv(InfoView::window_type::qa,
                    "File already exists.",
                    "File already exists. Do you want to overwrite it?",
                    this);
        iv.exec();
        if (iv.result_answer)
        {
            return;
        }
    }
    draw_pixmap->generated_pixmap.save(new_file_path, "PNG");
}

void MainWindow::update_video_info()
{
    QMap<QString, QString> map_ss = get_video_info(current_video_path);

    video_frame_count = fe->get_video_frame_count();
    current_video_fps = fe->get_video_fps();

    QString duration = map_ss.value("duration-info");
    QStringList strl = duration.split(":");

    int duration_h = strl.at(0).toInt();
    int duration_m = strl.at(1).toInt();
    int duration_s = int(strl.at(2).toDouble());

    ui->end_h_spin->setValue(duration_h);
    ui->end_m_spin->setValue(duration_m);
    ui->end_s_spin->setValue(duration_s);

    QString file_text = map_ss.value("file-name");
    QString video_text = map_ss.value("video-info");
    QString audio_text = map_ss.value("audio-info");

    QString bytes = map_ss.value("size-in-bytes");
    QString in_MiB = map_ss.value("size-in-MiB");

    QString size_text = tr("%1 bytes (%2), duration: %3")
            .arg(bytes, in_MiB, duration);

    ui->file_text->setText(file_text);
    ui->video_text->setText(video_text);
    ui->audio_text->setText(audio_text);
    ui->size_text->setText(size_text);

    ui->file_text->setCursorPosition(0);
    ui->video_text->setCursorPosition(0);
    ui->audio_text->setCursorPosition(0);
    ui->size_text->setCursorPosition(0);

    QFileInfo file_info(current_video_path);
    QString file_name = file_info.fileName();
    QString dir_name = file_info.absoluteDir().dirName();

    setWindowTitle(tr("%1 @ %2 - %3").arg(file_name, dir_name, app_name));
}

QMap<QString, QString> MainWindow::get_video_info(QString video_path)
{
    QProcess qp;
    qp.setProgram(FFMPEG_EXE);

    QStringList qp_args;
    qp_args << "-i" << video_path;

    qp.setArguments(qp_args);
    qp.start();
    qp.waitForFinished(-1);

    QByteArray ba_result = qp.readAllStandardError();
    QString s_result = QString(ba_result);
    QMap<QString, QString> result_map;

    s_result.replace('\n', " ");
    while (s_result.contains("  "))
    {
        s_result.replace("  ", " ");
    }

    // Get name.
    QString file_name = video_path.split("/").last();
    result_map.insert("file-name", file_name);

    QRegularExpression re;
    QRegularExpressionMatch match;

    // Get video.
    re.setPattern(": Video: (.*?) Metadata:");
    match = re.match(s_result);
    if (match.hasMatch())
    {
        result_map.insert("video-info", match.captured(1));
    }
    else
    {
        result_map.insert("video-info", "<unknown video>");
    }

    // Get audio.
    re.setPattern(": Audio: (.*?) Metadata:");
    match = re.match(s_result);
    if (match.hasMatch())
    {
        result_map.insert("audio-info", match.captured(1));
    }
    else
    {
        result_map.insert("audio-info", "<unknown audio>");
    }

    // Get duration.
    re.setPattern("Duration: (.*?), ");
    match = re.match(s_result);
    if (match.hasMatch())
    {
        result_map.insert("duration-info", match.captured(1));
    }
    else
    {
        result_map.insert("duration-info", "<unknown duration>");
    }

    // Get bitrate.
    re.setPattern(", bitrate: (.*? .*?) ");
    match = re.match(s_result);
    if (match.hasMatch())
    {
        result_map.insert("bitrate", match.captured(1));
    }
    else
    {
        result_map.insert("bitrate", "<unknown bitrate>");
    }


    // Get size in bytes and MiB.
    qp.setProgram(STAT_EXE);
    qp_args.clear();
    qp_args << "--printf=\"%s\"" << video_path;

    qp.setArguments(qp_args);
    qp.start();
    qp.waitForFinished(-1);

    ba_result = qp.readAllStandardOutput();
    s_result = QString(ba_result);

    if (s_result.size() > 0)
    {
        s_result.replace("\"", "");
        result_map.insert("size-in-bytes", s_result);

        int bytes = s_result.toInt();
        int size_MiB = ceil(bytes / 1024.0 / 1024.0);
        s_result = QString::number(size_MiB) + "MiB";

        result_map.insert("size-in-MiB", s_result);
    }
    else
    {
        result_map.insert("size-in-bytes", "<unknown byte size>");
        result_map.insert("size-in-MiB", "<unknown MiB size>");
    }

    return result_map;
}

QString MainWindow::get_random_string(int size)
{
   QString chars("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
   QString return_str;
   for(int i = 0; i < size; ++i)
   {
       int index = QRandomGenerator::global()->bounded(chars.size());
       QChar c = chars.at(index);
       return_str.append(c);
   }
   return return_str;
}

void MainWindow::get_pictures_from_video(double start_frame,
                                         double end_frame)
{
    QString random_name = get_random_string(8);
    QString out_dir_path = tr("/tmp/%1/").arg(random_name);

    while (QDir(out_dir_path).exists())
    {
        random_name = get_random_string(8);
        out_dir_path = tr("/tmp/%1/").arg(random_name);
    }
    bool mkpath_result = QDir().mkpath(out_dir_path);
    if (!mkpath_result)
    {
        return;
    }

    // Generate all pictures to temp dir.
    Processing proc_ui(this);
    fe->set(current_video_path,
           out_dir_path,
           count_spin,
           start_frame,
           end_frame,
           current_video_fps);

    connect(fe, &FramesExtractor::set_max, &proc_ui, &Processing::set_max);
    connect(fe, &FramesExtractor::set_value, &proc_ui, &Processing::set_value);
    connect(fe, &FramesExtractor::process_done, &proc_ui, &Processing::on_cancel_button_clicked);

    fe->start();
    proc_ui.exec();
    fe->stop_work();
    fe->wait();


    // Read all pictures from temp dir.
    QDir dir(out_dir_path);
    dir.setSorting(QDir::NoSort);
    dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
    QStringList imgs = dir.entryList(QStringList() << "*.jpg", QDir::Files);

    if (imgs.isEmpty())
    {
        if (!QDir(out_dir_path).removeRecursively())
        {
            qCritical() << "Unable to remove temp directory.";
        }
        return;
    }

    QCollator coll;
    coll.setNumericMode(true);
    std::sort(imgs.begin(), imgs.end(), coll);


    for (qsizetype i = 0; i < imgs.size(); i++)
    {
        QString file_name = imgs.at(i);

        // Get image.
        QUrl url = QUrl(tr("file://") + out_dir_path + file_name);
        QImage image(url.path());
        QImage img_scaled(image.scaledToWidth(
                              draw_pixmap->width_spin/draw_pixmap->divider_spin,
                              Qt::FastTransformation
                              ));
        draw_pixmap->images.push_back(img_scaled);

        // Get image timestamp.
        QRegularExpression re;
        QRegularExpressionMatch match;

        re.setPattern("\\[(.*)\\]");
        match = re.match(file_name);
        if (match.hasMatch())
        {
            draw_pixmap->time_stamps.push_back(match.captured(1));
        }
    }

    // Fixing the last timestamp
    // because the video fps value is just not accurate enough.
    int e_h = ui->end_h_spin->value();
    int e_m = ui->end_m_spin->value();
    int e_s = ui->end_s_spin->value();

    QString se_h = QString::number(e_h).rightJustified(2, '0');
    QString se_m = QString::number(e_m).rightJustified(2, '0');
    QString se_s = QString::number(e_s).rightJustified(2, '0');

    QString new_last_timestamp = QString("%1:%2:%3").arg(se_h, se_m, se_s);
    draw_pixmap->time_stamps.last() = new_last_timestamp;


    if (!QDir(out_dir_path).removeRecursively())
    {
        qCritical() << "Unable to remove temp directory.";
    }
}

void MainWindow::on_action_About_triggered()
{
    AboutWindow aw(app_name, app_version, this);
    aw.exec();
}

void MainWindow::on_action_Exit_triggered()
{
    QApplication::quit();
}

void MainWindow::on_action_hide_signature_changed()
{
    draw_pixmap->hide_signature = ui->action_hide_signature->isChecked();
    on_updatetext_button_clicked();
}

void MainWindow::on_action_hide_timestamp_changed()
{
    draw_pixmap->hide_timestamp = ui->action_hide_timestamp->isChecked();

    draw_pixmap->draw_pixmap(app_name);
    image_label->setPixmap(draw_pixmap->generated_pixmap);
}
main_window.h
/*
Copyright (C) 2022 Lari Varjonen <[email protected]>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef MAIN_WINDOW_H
#define MAIN_WINDOW_H
#include <QMainWindow>
#include <QRandomGenerator>
#include <QFileDialog>
#include <QProcess>
#include <QCollator>
#include <QDir>
#include <QUrl>
#include <QLabel>
#include <QDragEnterEvent>
#include <QMimeData>
#include "draw_pixmap.h"
#include "info_view.h"
#include "processing.h"
#include "draw_pixmap.h"
#include "frames_extractor.h"
#include "about_window.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
const QString app_version = "1.6";
const QString app_name = "Video Photographer";
const QString FFMPEG_EXE = ffmpeg_path();
const QString STAT_EXE = stat_path();
QString current_video_path;
int count_spin;
int start_time;
int end_time;
double current_video_fps;
int video_frame_count;
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
static QString ffmpeg_path(QString path = "")
{
static QString ffmpeg_path = "/usr/bin/ffmpeg";
if (!path.isEmpty())
{
ffmpeg_path = path;
}
return ffmpeg_path;
}
static QString stat_path(QString path = "")
{
static QString stat_path = "/usr/bin/stat";
if (!path.isEmpty())
{
stat_path = path;
}
return stat_path;
}
private slots:
void on_select_video_button_clicked();
void on_generate_image_button_clicked();
void on_updatetext_button_clicked();
void on_save_image_button_clicked();
void on_action_About_triggered();
void on_action_Exit_triggered();
void on_action_hide_signature_changed();
void on_action_hide_timestamp_changed();
private:
Ui::MainWindow *ui;
FramesExtractor *fe;
DrawPixmap *draw_pixmap;
QLabel *image_label;
void update_video_info();
QMap<QString, QString> get_video_info(QString video_path);
QString get_random_string(int size);
void get_pictures_from_video(double start_frame, double end_frame);
protected:
virtual void dragEnterEvent(QDragEnterEvent *event);
virtual void dropEvent(QDropEvent *event);
};
#endif // MAIN_WINDOW_H
/* Copyright (C) 2022 Lari Varjonen <[email protected]> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef MAIN_WINDOW_H #define MAIN_WINDOW_H #include <QMainWindow> #include <QRandomGenerator> #include <QFileDialog> #include <QProcess> #include <QCollator> #include <QDir> #include <QUrl> #include <QLabel> #include <QDragEnterEvent> #include <QMimeData> #include "draw_pixmap.h" #include "info_view.h" #include "processing.h" #include "draw_pixmap.h" #include "frames_extractor.h" #include "about_window.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT const QString app_version = "1.6"; const QString app_name = "Video Photographer"; const QString FFMPEG_EXE = ffmpeg_path(); const QString STAT_EXE = stat_path(); QString current_video_path; int count_spin; int start_time; int end_time; double current_video_fps; int video_frame_count; public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); static QString ffmpeg_path(QString path = "") { static QString ffmpeg_path = "/usr/bin/ffmpeg"; if (!path.isEmpty()) { ffmpeg_path = path; } return ffmpeg_path; } static QString stat_path(QString path = "") { static QString stat_path = "/usr/bin/stat"; if (!path.isEmpty()) { stat_path = path; } return stat_path; } private slots: void on_select_video_button_clicked(); void on_generate_image_button_clicked(); void on_updatetext_button_clicked(); void on_save_image_button_clicked(); void on_action_About_triggered(); void on_action_Exit_triggered(); void on_action_hide_signature_changed(); void on_action_hide_timestamp_changed(); private: Ui::MainWindow *ui; FramesExtractor *fe; DrawPixmap *draw_pixmap; QLabel *image_label; void update_video_info(); QMap<QString, QString> get_video_info(QString video_path); QString get_random_string(int size); void get_pictures_from_video(double start_frame, double end_frame); protected: virtual void dragEnterEvent(QDragEnterEvent *event); virtual void dropEvent(QDropEvent *event); }; #endif // MAIN_WINDOW_H
/*
    Copyright (C) 2022 Lari Varjonen <[email protected]>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#ifndef MAIN_WINDOW_H
#define MAIN_WINDOW_H

#include <QMainWindow>

#include <QRandomGenerator>
#include <QFileDialog>
#include <QProcess>
#include <QCollator>
#include <QDir>
#include <QUrl>
#include <QLabel>

#include <QDragEnterEvent>
#include <QMimeData>

#include "draw_pixmap.h"
#include "info_view.h"
#include "processing.h"
#include "draw_pixmap.h"
#include "frames_extractor.h"
#include "about_window.h"


QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE


class MainWindow : public QMainWindow
{
    Q_OBJECT

    const QString app_version = "1.6";
    const QString app_name = "Video Photographer";

    const QString FFMPEG_EXE = ffmpeg_path();
    const QString STAT_EXE = stat_path();

    QString current_video_path;

    int count_spin;
    int start_time;
    int end_time;
    double current_video_fps;
    int video_frame_count;

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    static QString ffmpeg_path(QString path = "")
    {
        static QString ffmpeg_path = "/usr/bin/ffmpeg";
        if (!path.isEmpty())
        {
            ffmpeg_path = path;
        }
        return ffmpeg_path;
    }

    static QString stat_path(QString path = "")
    {
        static QString stat_path = "/usr/bin/stat";
        if (!path.isEmpty())
        {
            stat_path = path;
        }
        return stat_path;
    }

private slots:
    void on_select_video_button_clicked();
    void on_generate_image_button_clicked();
    void on_updatetext_button_clicked();
    void on_save_image_button_clicked();

    void on_action_About_triggered();
    void on_action_Exit_triggered();
    void on_action_hide_signature_changed();
    void on_action_hide_timestamp_changed();

private:

    Ui::MainWindow *ui;
    FramesExtractor *fe;
    DrawPixmap *draw_pixmap;
    QLabel *image_label;

    void update_video_info();
    QMap<QString, QString> get_video_info(QString video_path);
    QString get_random_string(int size);
    void get_pictures_from_video(double start_frame, double end_frame);

protected:
    virtual void dragEnterEvent(QDragEnterEvent *event);
    virtual void dropEvent(QDropEvent *event);
};
#endif // MAIN_WINDOW_H
main.cpp
/*
Copyright (C) 2022 Lari Varjonen <[email protected]>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "main_window.h"
#include <QApplication>
int main(int argc, char *argv[])
{
for(int i = 1; i < argc-1; i++)
{
if (std::strcmp(argv[i], "--ffmpeg") == 0)
{
QString new_ffmpeg_path = argv[i+1];
MainWindow::ffmpeg_path(new_ffmpeg_path);
i++;
continue;
}
if (std::strcmp(argv[i], "--stat") == 0)
{
QString new_stat_path = argv[i+1];
MainWindow::stat_path(new_stat_path);
i++;
continue;
}
}
QApplication a(argc, argv);
if (!QFile::exists(MainWindow::ffmpeg_path()))
{
InfoView iv(InfoView::window_type::ok,
"FFMPEG not found.",
"Please set FFMPEG with the commandline parameter \"--ffmpeg <path to ffmpeg>\".");
iv.exec();
a.quit();
return 0;
}
if (!QFile::exists(MainWindow::stat_path()))
{
InfoView iv(InfoView::window_type::ok,
"STAT not found.",
"Please set STAT with the commandline parameter \"--stat <path to stat>\".");
iv.exec();
a.quit();
return 0;
}
MainWindow w;
w.show();
return a.exec();
}
/* Copyright (C) 2022 Lari Varjonen <[email protected]> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "main_window.h" #include <QApplication> int main(int argc, char *argv[]) { for(int i = 1; i < argc-1; i++) { if (std::strcmp(argv[i], "--ffmpeg") == 0) { QString new_ffmpeg_path = argv[i+1]; MainWindow::ffmpeg_path(new_ffmpeg_path); i++; continue; } if (std::strcmp(argv[i], "--stat") == 0) { QString new_stat_path = argv[i+1]; MainWindow::stat_path(new_stat_path); i++; continue; } } QApplication a(argc, argv); if (!QFile::exists(MainWindow::ffmpeg_path())) { InfoView iv(InfoView::window_type::ok, "FFMPEG not found.", "Please set FFMPEG with the commandline parameter \"--ffmpeg <path to ffmpeg>\"."); iv.exec(); a.quit(); return 0; } if (!QFile::exists(MainWindow::stat_path())) { InfoView iv(InfoView::window_type::ok, "STAT not found.", "Please set STAT with the commandline parameter \"--stat <path to stat>\"."); iv.exec(); a.quit(); return 0; } MainWindow w; w.show(); return a.exec(); }
/*
    Copyright (C) 2022 Lari Varjonen <[email protected]>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "main_window.h"
#include <QApplication>


int main(int argc, char *argv[])
{
    for(int i = 1; i < argc-1; i++)
    {
        if (std::strcmp(argv[i], "--ffmpeg") == 0)
        {
            QString new_ffmpeg_path = argv[i+1];
            MainWindow::ffmpeg_path(new_ffmpeg_path);
            i++;
            continue;
        }

        if (std::strcmp(argv[i], "--stat") == 0)
        {
            QString new_stat_path = argv[i+1];
            MainWindow::stat_path(new_stat_path);
            i++;
            continue;
        }
    }

    QApplication a(argc, argv);

    if (!QFile::exists(MainWindow::ffmpeg_path()))
    {
        InfoView iv(InfoView::window_type::ok,
                    "FFMPEG not found.",
                    "Please set FFMPEG with the commandline parameter \"--ffmpeg <path to ffmpeg>\".");
        iv.exec();
        a.quit();
        return 0;
    }

    if (!QFile::exists(MainWindow::stat_path()))
    {
        InfoView iv(InfoView::window_type::ok,
                    "STAT not found.",
                    "Please set STAT with the commandline parameter \"--stat <path to stat>\".");
        iv.exec();
        a.quit();
        return 0;
    }

    MainWindow w;
    w.show();
    return a.exec();
}
frames_extractor.cpp
/*
Copyright (C) 2022 Lari Varjonen <[email protected]>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "frames_extractor.h"
void FramesExtractor::run()
{
if (cap == nullptr)
{
qCritical() << "cap == nullptr";
return;
}
if(!cap->isOpened())
{
qCritical() << "Video file is invalid.";
return;
}
emit set_max(frames_wanted);
video_frame_count = cap->get(cv::CAP_PROP_FRAME_COUNT);
if (start_frame > end_frame && end_frame < start_frame)
{
return;
}
if (frames_wanted == 1 || start_frame == end_frame)
{
save_one_frame(start_frame+1, 1);
emit set_value(frames_wanted, start_frame+1, start_frame+1);
emit process_done();
return;
}
if (end_frame > video_frame_count)
{
end_frame = video_frame_count;
}
if (start_frame > 0)
{
start_frame += 1;
}
double frame_step = (end_frame - start_frame) / frames_wanted;
double current_frame = start_frame;
unsigned int frame_number = 1;
for(unsigned int i = 0; i < frames_wanted && current_frame <= end_frame;)
{
emit set_value(i, current_frame, end_frame);
if (!running)
{
break;
}
if (i == frames_wanted-1)
{
current_frame = (end_frame==video_frame_count)?end_frame-1:end_frame+1;
}
save_one_frame(current_frame, frame_number);
i++;
current_frame = start_frame + (i * frame_step);
frame_number++;
}
if (running)
{
emit process_done();
}
}
void FramesExtractor::save_one_frame(double current_frame,
int frame_number)
{
cv::Mat frame;
cap->set(cv::CAP_PROP_POS_FRAMES, current_frame);
*cap >> frame;
int i = 1;
while (frame.empty())
{
if (i == max_frames_to_backtrack)
{
qCritical() << tr("Unable to read a frame: %1 %2 %3")
.arg(current_frame)
.arg(frame_number)
.arg(video_frame_count);
return;
}
i++;
current_frame--;
cap->set(cv::CAP_PROP_POS_FRAMES, current_frame);
*cap >> frame;
}
double current_frame_secs = current_frame / video_fps;
QTime a(0,0,0);
a = a.addSecs(current_frame_secs);
QString time = a.toString();
QString file_path = out_dir_path;
file_path += QString::number(frame_number);
file_path += QString("[") + time + "].jpg";
std::vector<int> params;
params.push_back(cv::IMWRITE_JPEG_QUALITY);
params.push_back(100);
imwrite(file_path.toStdString(), frame, params);
}
bool FramesExtractor::set_video(QString file_path)
{
cv::VideoCapture cap0(file_path.toStdString());
if (!cap0.isOpened() || cap0.get(cv::CAP_PROP_FRAME_COUNT) <= 1)
{
return true;
}
delete cap;
cap = new cv::VideoCapture(file_path.toStdString());
return false;
}
int FramesExtractor::get_video_frame_count()
{
return cap->get(cv::CAP_PROP_FRAME_COUNT);
}
double FramesExtractor::get_video_fps()
{
return cap->get(cv::CAP_PROP_FPS);
}
/* Copyright (C) 2022 Lari Varjonen <[email protected]> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "frames_extractor.h" void FramesExtractor::run() { if (cap == nullptr) { qCritical() << "cap == nullptr"; return; } if(!cap->isOpened()) { qCritical() << "Video file is invalid."; return; } emit set_max(frames_wanted); video_frame_count = cap->get(cv::CAP_PROP_FRAME_COUNT); if (start_frame > end_frame && end_frame < start_frame) { return; } if (frames_wanted == 1 || start_frame == end_frame) { save_one_frame(start_frame+1, 1); emit set_value(frames_wanted, start_frame+1, start_frame+1); emit process_done(); return; } if (end_frame > video_frame_count) { end_frame = video_frame_count; } if (start_frame > 0) { start_frame += 1; } double frame_step = (end_frame - start_frame) / frames_wanted; double current_frame = start_frame; unsigned int frame_number = 1; for(unsigned int i = 0; i < frames_wanted && current_frame <= end_frame;) { emit set_value(i, current_frame, end_frame); if (!running) { break; } if (i == frames_wanted-1) { current_frame = (end_frame==video_frame_count)?end_frame-1:end_frame+1; } save_one_frame(current_frame, frame_number); i++; current_frame = start_frame + (i * frame_step); frame_number++; } if (running) { emit process_done(); } } void FramesExtractor::save_one_frame(double current_frame, int frame_number) { cv::Mat frame; cap->set(cv::CAP_PROP_POS_FRAMES, current_frame); *cap >> frame; int i = 1; while (frame.empty()) { if (i == max_frames_to_backtrack) { qCritical() << tr("Unable to read a frame: %1 %2 %3") .arg(current_frame) .arg(frame_number) .arg(video_frame_count); return; } i++; current_frame--; cap->set(cv::CAP_PROP_POS_FRAMES, current_frame); *cap >> frame; } double current_frame_secs = current_frame / video_fps; QTime a(0,0,0); a = a.addSecs(current_frame_secs); QString time = a.toString(); QString file_path = out_dir_path; file_path += QString::number(frame_number); file_path += QString("[") + time + "].jpg"; std::vector<int> params; params.push_back(cv::IMWRITE_JPEG_QUALITY); params.push_back(100); imwrite(file_path.toStdString(), frame, params); } bool FramesExtractor::set_video(QString file_path) { cv::VideoCapture cap0(file_path.toStdString()); if (!cap0.isOpened() || cap0.get(cv::CAP_PROP_FRAME_COUNT) <= 1) { return true; } delete cap; cap = new cv::VideoCapture(file_path.toStdString()); return false; } int FramesExtractor::get_video_frame_count() { return cap->get(cv::CAP_PROP_FRAME_COUNT); } double FramesExtractor::get_video_fps() { return cap->get(cv::CAP_PROP_FPS); }
/*
    Copyright (C) 2022 Lari Varjonen <[email protected]>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "frames_extractor.h"


void FramesExtractor::run()
{
    if (cap == nullptr)
    {
        qCritical() << "cap == nullptr";
        return;
    }
    if(!cap->isOpened())
    {
        qCritical() << "Video file is invalid.";
        return;
    }

    emit set_max(frames_wanted);
    video_frame_count = cap->get(cv::CAP_PROP_FRAME_COUNT);

    if (start_frame > end_frame && end_frame < start_frame)
    {
        return;
    }

    if (frames_wanted == 1 || start_frame == end_frame)
    {
        save_one_frame(start_frame+1, 1);
        emit set_value(frames_wanted, start_frame+1, start_frame+1);
        emit process_done();
        return;
    }

    if (end_frame > video_frame_count)
    {
        end_frame = video_frame_count;
    }
    if (start_frame > 0)
    {
        start_frame += 1;
    }

    double frame_step = (end_frame - start_frame) / frames_wanted;
    double current_frame = start_frame;
    unsigned int frame_number = 1;

    for(unsigned int i = 0; i < frames_wanted && current_frame <= end_frame;)
    {
        emit set_value(i, current_frame, end_frame);
        if (!running)
        {
            break;
        }

        if (i == frames_wanted-1)
        {
            current_frame = (end_frame==video_frame_count)?end_frame-1:end_frame+1;
        }

        save_one_frame(current_frame, frame_number);

        i++;
        current_frame = start_frame + (i * frame_step);
        frame_number++;
    }

    if (running)
    {
        emit process_done();
    }
}

void FramesExtractor::save_one_frame(double current_frame,
                                     int frame_number)
{
    cv::Mat frame;
    cap->set(cv::CAP_PROP_POS_FRAMES, current_frame);
    *cap >> frame;

    int i = 1;
    while (frame.empty())
    {
        if (i == max_frames_to_backtrack)
        {
            qCritical() << tr("Unable to read a frame: %1 %2 %3")
                           .arg(current_frame)
                           .arg(frame_number)
                           .arg(video_frame_count);
            return;
        }
        i++;

        current_frame--;
        cap->set(cv::CAP_PROP_POS_FRAMES, current_frame);
        *cap >> frame;
    }

    double current_frame_secs = current_frame / video_fps;
    QTime a(0,0,0);
    a = a.addSecs(current_frame_secs);
    QString time = a.toString();

    QString file_path = out_dir_path;
    file_path += QString::number(frame_number);
    file_path += QString("[") + time + "].jpg";

    std::vector<int> params;
    params.push_back(cv::IMWRITE_JPEG_QUALITY);
    params.push_back(100);

    imwrite(file_path.toStdString(), frame, params);
}

bool FramesExtractor::set_video(QString file_path)
{
    cv::VideoCapture cap0(file_path.toStdString());
    if (!cap0.isOpened() || cap0.get(cv::CAP_PROP_FRAME_COUNT) <= 1)
    {
        return true;
    }
    delete cap;
    cap = new cv::VideoCapture(file_path.toStdString());
    return false;
}

int FramesExtractor::get_video_frame_count()
{
    return cap->get(cv::CAP_PROP_FRAME_COUNT);
}

double FramesExtractor::get_video_fps()
{
    return cap->get(cv::CAP_PROP_FPS);
}
frames_extractor.h
/*
Copyright (C) 2022 Lari Varjonen <[email protected]>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef FRAMESEXTRACTOR_H
#define FRAMESEXTRACTOR_H
#include <QThread>
#include <QDialog>
#include <QString>
#include <QDebug>
#include <QTime>
#include "opencv2/video.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
class FramesExtractor : public QThread
{
Q_OBJECT
public:
~FramesExtractor()
{
delete cap;
}
void set(QString video_path,
QString out_dir_path,
unsigned int frames_wanted,
double start_frame,
double end_frame,
double video_fps)
{
this->video_path = video_path;
this->out_dir_path = out_dir_path;
this->frames_wanted = frames_wanted;
this->start_frame = start_frame;
this->end_frame = end_frame;
this->video_fps = video_fps;
running = true;
};
void stop_work()
{
running = false;
};
void run() override;
bool set_video(QString file_path);
int get_video_frame_count();
double get_video_fps();
private:
void save_one_frame(double current_frame,
int frame_number);
cv::VideoCapture *cap = nullptr;
QString video_path;
QString out_dir_path;
unsigned int video_frame_count;
unsigned int frames_wanted;
double start_frame;
double end_frame;
double video_fps;
bool running;
const int max_frames_to_backtrack = 100;
signals:
void set_max(unsigned int max);
void set_value(unsigned int new_value,
double current_frame,
double end_frame);
void process_done();
};
#endif // FRAMESEXTRACTOR_H
/* Copyright (C) 2022 Lari Varjonen <[email protected]> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef FRAMESEXTRACTOR_H #define FRAMESEXTRACTOR_H #include <QThread> #include <QDialog> #include <QString> #include <QDebug> #include <QTime> #include "opencv2/video.hpp" #include "opencv2/imgproc.hpp" #include "opencv2/videoio.hpp" #include "opencv2/highgui.hpp" class FramesExtractor : public QThread { Q_OBJECT public: ~FramesExtractor() { delete cap; } void set(QString video_path, QString out_dir_path, unsigned int frames_wanted, double start_frame, double end_frame, double video_fps) { this->video_path = video_path; this->out_dir_path = out_dir_path; this->frames_wanted = frames_wanted; this->start_frame = start_frame; this->end_frame = end_frame; this->video_fps = video_fps; running = true; }; void stop_work() { running = false; }; void run() override; bool set_video(QString file_path); int get_video_frame_count(); double get_video_fps(); private: void save_one_frame(double current_frame, int frame_number); cv::VideoCapture *cap = nullptr; QString video_path; QString out_dir_path; unsigned int video_frame_count; unsigned int frames_wanted; double start_frame; double end_frame; double video_fps; bool running; const int max_frames_to_backtrack = 100; signals: void set_max(unsigned int max); void set_value(unsigned int new_value, double current_frame, double end_frame); void process_done(); }; #endif // FRAMESEXTRACTOR_H
/*
    Copyright (C) 2022 Lari Varjonen <[email protected]>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#ifndef FRAMESEXTRACTOR_H
#define FRAMESEXTRACTOR_H

#include <QThread>
#include <QDialog>
#include <QString>
#include <QDebug>
#include <QTime>


#include "opencv2/video.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"


class FramesExtractor : public QThread
{
    Q_OBJECT
public:
    ~FramesExtractor()
    {
        delete cap;
    }
    void set(QString video_path,
              QString out_dir_path,
              unsigned int frames_wanted,
              double start_frame,
              double end_frame,
              double video_fps)
    {
        this->video_path = video_path;
        this->out_dir_path = out_dir_path;
        this->frames_wanted = frames_wanted;
        this->start_frame = start_frame;
        this->end_frame = end_frame;
        this->video_fps = video_fps;
        running = true;
    };
    void stop_work()
    {
        running = false;
    };
    void run() override;
    bool set_video(QString file_path);
    int get_video_frame_count();
    double get_video_fps();

private:
    void save_one_frame(double current_frame,
                        int frame_number);

    cv::VideoCapture *cap = nullptr;

    QString video_path;
    QString out_dir_path;
    unsigned int video_frame_count;
    unsigned int frames_wanted;
    double start_frame;
    double end_frame;
    double video_fps;
    bool running;
    const int max_frames_to_backtrack = 100;

signals:
    void set_max(unsigned int max);
    void set_value(unsigned int new_value,
                   double current_frame,
                   double end_frame);
    void process_done();
};

#endif // FRAMESEXTRACTOR_H
draw_pixmap.cpp
/*
Copyright (C) 2022 Lari Varjonen <[email protected]>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "draw_pixmap.h"
void DrawPixmap::draw_pixmap(const QString SIGNATURE_TEXT)
{
if (images.isEmpty())
{
return;
}
QPixmap *pixmap = new QPixmap(width_spin, starting_height);
pixmap->fill(Qt::black);
QPainter *painter = new QPainter(pixmap);
painter->setPen(Qt::white);
QFont font;
font.setFamily("Arial");
font.setPixelSize(16);
font.setItalic(true);
font.setWeight(QFont::Thin);
painter->setFont(font);
QPoint point;
int y_pos = 0;
if (!file_text.isEmpty())
{
y_pos += 16;
point = QPoint(2, y_pos);
painter->drawText(point, QString("File: ") + file_text);
y_pos += 2;
}
if (!size_text.isEmpty())
{
y_pos += 16;
point = QPoint(2, y_pos);
painter->drawText(point, QString("Size: ") + size_text);
y_pos += 2;
}
if (!audio_text.isEmpty())
{
y_pos += 16;
point = QPoint(2, y_pos);
painter->drawText(point, QString("Audio: ") + audio_text);
y_pos += 2;
}
if (!video_text.isEmpty())
{
y_pos += 16;
point = QPoint(2, y_pos);
painter->drawText(point, QString("Video: ") + video_text);
y_pos += 2;
}
if (!hide_signature)
{
y_pos += 16;
point = QPoint(2, y_pos);
painter->drawText(point, QString("Generated by ") + SIGNATURE_TEXT);
y_pos += 2;
}
if (y_pos != 0)
{
y_pos += 4;
}
int x = 0;
int f = divider_spin;
int img_scaled_height = images.at(0).height();
for (qsizetype i = 0; i < images.size(); i++)
{
if (i == f)
{
f = i + divider_spin;
y_pos += images.at(i).height();
x = 0;
}
if (y_pos + images.at(i).height() > starting_height)
{
starting_height = y_pos + images.at(i).height();
QPixmap *new_pixmap = new QPixmap(width_spin, starting_height);
new_pixmap->fill(Qt::black);
QPainter *new_painter = new QPainter(new_pixmap);
new_painter->drawPixmap(0, 0, pixmap->width(), pixmap->height(), *pixmap);
delete painter;
delete pixmap;
pixmap = new_pixmap;
painter = new_painter;
}
point = QPoint(x, y_pos);
painter->drawImage(point, images.at(i));
if (!hide_timestamp)
{
font.setFamily("Arial");
font.setStyle(QFont::StyleItalic);
font.setStyleHint(QFont::AnyStyle);
font.setPixelSize(12);
font.setItalic(true);
font.setWeight(QFont::Thin);
painter->setFont(font);
QString time = time_stamps[i];
QFontMetrics fm(font);
int text_width = fm.horizontalAdvance(time);
int text_x = x + images.at(i).width() - text_width - 1;
int text_y = (y_pos + images.at(i).height()) - 1;
point = QPoint(text_x, text_y);
painter->setPen(Qt::black);
painter->drawText(point, time);
point = QPoint(text_x - 1, text_y - 1);
painter->setPen(Qt::white);
painter->drawText(point, time);
}
x += images.at(i).width();
}
QRect rect(0, 0, width_spin, y_pos + img_scaled_height);
generated_pixmap = pixmap->copy(rect);
delete painter;
delete pixmap;
}
/* Copyright (C) 2022 Lari Varjonen <[email protected]> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "draw_pixmap.h" void DrawPixmap::draw_pixmap(const QString SIGNATURE_TEXT) { if (images.isEmpty()) { return; } QPixmap *pixmap = new QPixmap(width_spin, starting_height); pixmap->fill(Qt::black); QPainter *painter = new QPainter(pixmap); painter->setPen(Qt::white); QFont font; font.setFamily("Arial"); font.setPixelSize(16); font.setItalic(true); font.setWeight(QFont::Thin); painter->setFont(font); QPoint point; int y_pos = 0; if (!file_text.isEmpty()) { y_pos += 16; point = QPoint(2, y_pos); painter->drawText(point, QString("File: ") + file_text); y_pos += 2; } if (!size_text.isEmpty()) { y_pos += 16; point = QPoint(2, y_pos); painter->drawText(point, QString("Size: ") + size_text); y_pos += 2; } if (!audio_text.isEmpty()) { y_pos += 16; point = QPoint(2, y_pos); painter->drawText(point, QString("Audio: ") + audio_text); y_pos += 2; } if (!video_text.isEmpty()) { y_pos += 16; point = QPoint(2, y_pos); painter->drawText(point, QString("Video: ") + video_text); y_pos += 2; } if (!hide_signature) { y_pos += 16; point = QPoint(2, y_pos); painter->drawText(point, QString("Generated by ") + SIGNATURE_TEXT); y_pos += 2; } if (y_pos != 0) { y_pos += 4; } int x = 0; int f = divider_spin; int img_scaled_height = images.at(0).height(); for (qsizetype i = 0; i < images.size(); i++) { if (i == f) { f = i + divider_spin; y_pos += images.at(i).height(); x = 0; } if (y_pos + images.at(i).height() > starting_height) { starting_height = y_pos + images.at(i).height(); QPixmap *new_pixmap = new QPixmap(width_spin, starting_height); new_pixmap->fill(Qt::black); QPainter *new_painter = new QPainter(new_pixmap); new_painter->drawPixmap(0, 0, pixmap->width(), pixmap->height(), *pixmap); delete painter; delete pixmap; pixmap = new_pixmap; painter = new_painter; } point = QPoint(x, y_pos); painter->drawImage(point, images.at(i)); if (!hide_timestamp) { font.setFamily("Arial"); font.setStyle(QFont::StyleItalic); font.setStyleHint(QFont::AnyStyle); font.setPixelSize(12); font.setItalic(true); font.setWeight(QFont::Thin); painter->setFont(font); QString time = time_stamps[i]; QFontMetrics fm(font); int text_width = fm.horizontalAdvance(time); int text_x = x + images.at(i).width() - text_width - 1; int text_y = (y_pos + images.at(i).height()) - 1; point = QPoint(text_x, text_y); painter->setPen(Qt::black); painter->drawText(point, time); point = QPoint(text_x - 1, text_y - 1); painter->setPen(Qt::white); painter->drawText(point, time); } x += images.at(i).width(); } QRect rect(0, 0, width_spin, y_pos + img_scaled_height); generated_pixmap = pixmap->copy(rect); delete painter; delete pixmap; }
/*
    Copyright (C) 2022 Lari Varjonen <[email protected]>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "draw_pixmap.h"


void DrawPixmap::draw_pixmap(const QString SIGNATURE_TEXT)
{
    if (images.isEmpty())
    {
        return;
    }

    QPixmap *pixmap = new QPixmap(width_spin, starting_height);
    pixmap->fill(Qt::black);

    QPainter *painter = new QPainter(pixmap);
    painter->setPen(Qt::white);

    QFont font;
    font.setFamily("Arial");
    font.setPixelSize(16);
    font.setItalic(true);
    font.setWeight(QFont::Thin);
    painter->setFont(font);

    QPoint point;
    int y_pos = 0;

    if (!file_text.isEmpty())
    {
        y_pos += 16;
        point = QPoint(2, y_pos);
        painter->drawText(point, QString("File: ") + file_text);
        y_pos += 2;
    }

    if (!size_text.isEmpty())
    {
        y_pos += 16;
        point = QPoint(2, y_pos);
        painter->drawText(point, QString("Size: ") + size_text);
        y_pos += 2;
    }

    if (!audio_text.isEmpty())
    {
        y_pos += 16;
        point = QPoint(2, y_pos);
        painter->drawText(point, QString("Audio: ") + audio_text);
        y_pos += 2;
    }

    if (!video_text.isEmpty())
    {
        y_pos += 16;
        point = QPoint(2, y_pos);
        painter->drawText(point, QString("Video: ") + video_text);
        y_pos += 2;
    }

    if (!hide_signature)
    {
        y_pos += 16;
        point = QPoint(2, y_pos);
        painter->drawText(point, QString("Generated by ") + SIGNATURE_TEXT);
        y_pos += 2;
    }

    if (y_pos != 0)
    {
        y_pos += 4;
    }

    int x = 0;
    int f = divider_spin;
    int img_scaled_height = images.at(0).height();

    for (qsizetype i = 0; i < images.size(); i++)
    {
        if (i == f)
        {
            f = i + divider_spin;
            y_pos += images.at(i).height();
            x = 0;
        }

        if (y_pos + images.at(i).height() > starting_height)
        {
            starting_height = y_pos + images.at(i).height();

            QPixmap *new_pixmap = new QPixmap(width_spin, starting_height);
            new_pixmap->fill(Qt::black);

            QPainter *new_painter = new QPainter(new_pixmap);
            new_painter->drawPixmap(0, 0, pixmap->width(), pixmap->height(), *pixmap);

            delete painter;
            delete pixmap;

            pixmap = new_pixmap;
            painter = new_painter;
        }

        point = QPoint(x, y_pos);
        painter->drawImage(point, images.at(i));

        if (!hide_timestamp)
        {
            font.setFamily("Arial");
            font.setStyle(QFont::StyleItalic);
            font.setStyleHint(QFont::AnyStyle);
            font.setPixelSize(12);
            font.setItalic(true);
            font.setWeight(QFont::Thin);
            painter->setFont(font);

            QString time = time_stamps[i];
            QFontMetrics fm(font);
            int text_width = fm.horizontalAdvance(time);

            int text_x = x + images.at(i).width() - text_width - 1;
            int text_y = (y_pos + images.at(i).height()) - 1;

            point = QPoint(text_x, text_y);
            painter->setPen(Qt::black);
            painter->drawText(point, time);

            point = QPoint(text_x - 1, text_y - 1);
            painter->setPen(Qt::white);
            painter->drawText(point, time);
        }

        x += images.at(i).width();
    }

    QRect rect(0, 0, width_spin, y_pos + img_scaled_height);
    generated_pixmap = pixmap->copy(rect);

    delete painter;
    delete pixmap;
}
draw_pixmap.h
/*
Copyright (C) 2022 Lari Varjonen <[email protected]>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef DRAWPIXMAP_H
#define DRAWPIXMAP_H
#include <QPainter>
class DrawPixmap
{
public:
void draw_pixmap(const QString SIGNATURE_TEXT);
int divider_spin;
int width_spin;
int starting_height;
bool hide_signature = false;
bool hide_timestamp = false;
QPixmap generated_pixmap;
QList<QImage> images;
QStringList time_stamps;
QString file_text;
QString size_text;
QString audio_text;
QString video_text;
};
#endif // DRAWPIXMAP_H
/* Copyright (C) 2022 Lari Varjonen <[email protected]> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef DRAWPIXMAP_H #define DRAWPIXMAP_H #include <QPainter> class DrawPixmap { public: void draw_pixmap(const QString SIGNATURE_TEXT); int divider_spin; int width_spin; int starting_height; bool hide_signature = false; bool hide_timestamp = false; QPixmap generated_pixmap; QList<QImage> images; QStringList time_stamps; QString file_text; QString size_text; QString audio_text; QString video_text; }; #endif // DRAWPIXMAP_H
/*
    Copyright (C) 2022 Lari Varjonen <[email protected]>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#ifndef DRAWPIXMAP_H
#define DRAWPIXMAP_H

#include <QPainter>


class DrawPixmap
{
public:
    void draw_pixmap(const QString SIGNATURE_TEXT);

    int divider_spin;
    int width_spin;
    int starting_height;
    bool hide_signature = false;
    bool hide_timestamp = false;

    QPixmap generated_pixmap;

    QList<QImage> images;
    QStringList time_stamps;

    QString file_text;
    QString size_text;
    QString audio_text;
    QString video_text;
};

#endif // DRAWPIXMAP_H
about_window.cpp
/*
Copyright (C) 2022 Lari Varjonen <[email protected]>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "about_window.h"
#include "ui_about_window.h"
AboutWindow::AboutWindow(const QString &app_name,
const QString &app_version,
QWidget *parent) :
QDialog(parent),
ui(new Ui::AboutWindow)
{
ui->setupUi(this);
ui->label_name->setText(app_name);
ui->label_version->setText(app_version);
}
AboutWindow::~AboutWindow()
{
delete ui;
}
/* Copyright (C) 2022 Lari Varjonen <[email protected]> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "about_window.h" #include "ui_about_window.h" AboutWindow::AboutWindow(const QString &app_name, const QString &app_version, QWidget *parent) : QDialog(parent), ui(new Ui::AboutWindow) { ui->setupUi(this); ui->label_name->setText(app_name); ui->label_version->setText(app_version); } AboutWindow::~AboutWindow() { delete ui; }
/*
    Copyright (C) 2022 Lari Varjonen <[email protected]>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "about_window.h"
#include "ui_about_window.h"


AboutWindow::AboutWindow(const QString &app_name,
                         const QString &app_version,
                         QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AboutWindow)
{
    ui->setupUi(this);
    ui->label_name->setText(app_name);
    ui->label_version->setText(app_version);
}

AboutWindow::~AboutWindow()
{
    delete ui;
}
about_window.h
/*
Copyright (C) 2022 Lari Varjonen <[email protected]>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef ABOUT_WINDOW_H
#define ABOUT_WINDOW_H
#include <QDialog>
namespace Ui {
class AboutWindow;
}
class AboutWindow : public QDialog
{
Q_OBJECT
public:
explicit AboutWindow(const QString &app_name,
const QString &app_version,
QWidget *parent = 0);
~AboutWindow();
private:
Ui::AboutWindow *ui;
};
#endif // ABOUT_WINDOW_H
/* Copyright (C) 2022 Lari Varjonen <[email protected]> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef ABOUT_WINDOW_H #define ABOUT_WINDOW_H #include <QDialog> namespace Ui { class AboutWindow; } class AboutWindow : public QDialog { Q_OBJECT public: explicit AboutWindow(const QString &app_name, const QString &app_version, QWidget *parent = 0); ~AboutWindow(); private: Ui::AboutWindow *ui; }; #endif // ABOUT_WINDOW_H
/*
        Copyright (C) 2022 Lari Varjonen <[email protected]>
    
        This program is free software; you can redistribute it and/or
        modify it under the terms of the GNU General Public License
        version 2 as published by the Free Software Foundation.
    
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
    
        You should have received a copy of the GNU General Public License
        along with this program; if not, write to the Free Software
        Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    */
    
    #ifndef ABOUT_WINDOW_H
    #define ABOUT_WINDOW_H
    
    #include <QDialog>
    
    
    namespace Ui {
    class AboutWindow;
    }
    
    class AboutWindow : public QDialog
    {
        Q_OBJECT
    
    public:
        explicit AboutWindow(const QString &app_name,
                             const QString &app_version,
                             QWidget *parent = 0);
        ~AboutWindow();
    
    private:
        Ui::AboutWindow *ui;
    };
    
    #endif // ABOUT_WINDOW_H
    
info_view.cpp
/*
Copyright (C) 2022 Lari Varjonen <[email protected]>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "info_view.h"
#include "ui_info_view.h"
InfoView::InfoView(InfoView::window_type type,
QString window_title,
QString q_text,
QWidget *parent) :
QDialog(parent),
ui(new Ui::InfoView)
{
ui->setupUi(this);
ui->q_text_label->setText(q_text);
if (type == window_type::ok)
{
ui->qa_widget->hide();
}
if (type == window_type::qa)
{
ui->ok_widget->hide();
}
setWindowTitle(window_title);
show();
adjustSize();
QSize window_size = window()->size();
resize(window_size.width(), 0);
}
InfoView::~InfoView()
{
delete ui;
}
void InfoView::on_cancel_button_clicked()
{
result_answer = true;
close();
}
void InfoView::on_continue_button_clicked()
{
result_answer = false;
close();
}
void InfoView::on_ok_button_clicked()
{
close();
}
/* Copyright (C) 2022 Lari Varjonen <[email protected]> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "info_view.h" #include "ui_info_view.h" InfoView::InfoView(InfoView::window_type type, QString window_title, QString q_text, QWidget *parent) : QDialog(parent), ui(new Ui::InfoView) { ui->setupUi(this); ui->q_text_label->setText(q_text); if (type == window_type::ok) { ui->qa_widget->hide(); } if (type == window_type::qa) { ui->ok_widget->hide(); } setWindowTitle(window_title); show(); adjustSize(); QSize window_size = window()->size(); resize(window_size.width(), 0); } InfoView::~InfoView() { delete ui; } void InfoView::on_cancel_button_clicked() { result_answer = true; close(); } void InfoView::on_continue_button_clicked() { result_answer = false; close(); } void InfoView::on_ok_button_clicked() { close(); }
/*
    Copyright (C) 2022 Lari Varjonen <[email protected]>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "info_view.h"
#include "ui_info_view.h"


InfoView::InfoView(InfoView::window_type type,
                   QString window_title,
                   QString q_text,
                   QWidget *parent) :
    QDialog(parent),
    ui(new Ui::InfoView)
{
    ui->setupUi(this);

    ui->q_text_label->setText(q_text);
    if (type == window_type::ok)
    {
        ui->qa_widget->hide();
    }
    if (type == window_type::qa)
    {
        ui->ok_widget->hide();
    }

    setWindowTitle(window_title);

    show();
    adjustSize();
    QSize window_size = window()->size();
    resize(window_size.width(), 0);
}

InfoView::~InfoView()
{
    delete ui;
}

void InfoView::on_cancel_button_clicked()
{
    result_answer = true;
    close();
}

void InfoView::on_continue_button_clicked()
{
    result_answer = false;
    close();
}

void InfoView::on_ok_button_clicked()
{
    close();
}
info_view.h
/*
Copyright (C) 2022 Lari Varjonen <[email protected]>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef INFO_VIEW_H
#define INFO_VIEW_H
#include <QDialog>
#include <QDebug>
namespace Ui {
class InfoView;
}
class InfoView : public QDialog
{
Q_OBJECT
public:
enum window_type {
ok,
qa
};
explicit InfoView(InfoView::window_type type,
QString window_title,
QString q_text,
QWidget *parent = nullptr);
~InfoView();
bool result_answer = true;
private slots:
void on_cancel_button_clicked();
void on_continue_button_clicked();
void on_ok_button_clicked();
private:
Ui::InfoView *ui;
};
#endif // INFO_VIEW_H
/* Copyright (C) 2022 Lari Varjonen <[email protected]> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef INFO_VIEW_H #define INFO_VIEW_H #include <QDialog> #include <QDebug> namespace Ui { class InfoView; } class InfoView : public QDialog { Q_OBJECT public: enum window_type { ok, qa }; explicit InfoView(InfoView::window_type type, QString window_title, QString q_text, QWidget *parent = nullptr); ~InfoView(); bool result_answer = true; private slots: void on_cancel_button_clicked(); void on_continue_button_clicked(); void on_ok_button_clicked(); private: Ui::InfoView *ui; }; #endif // INFO_VIEW_H
/*
    Copyright (C) 2022 Lari Varjonen <[email protected]>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#ifndef INFO_VIEW_H
#define INFO_VIEW_H

#include <QDialog>
#include <QDebug>


namespace Ui {
class InfoView;
}

class InfoView : public QDialog
{
    Q_OBJECT

public:
    enum window_type {
        ok,
        qa
    };

    explicit InfoView(InfoView::window_type type,
                      QString window_title,
                      QString q_text,
                      QWidget *parent = nullptr);
    ~InfoView();

    bool result_answer = true;

private slots:
    void on_cancel_button_clicked();
    void on_continue_button_clicked();
    void on_ok_button_clicked();

private:
    Ui::InfoView *ui;
};

#endif // INFO_VIEW_H
processing.cpp
/*
Copyright (C) 2022 Lari Varjonen <[email protected]>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "processing.h"
#include "ui_processing.h"
Processing::Processing(QWidget *parent) :
QDialog(parent),
ui(new Ui::Processing)
{
ui->setupUi(this);
setWindowTitle(window_title);
}
Processing::~Processing()
{
delete ui;
}
void Processing::set_max(unsigned int max)
{
ui->progress_bar->setMaximum(max);
this->progress_bar_max = max;
}
void Processing::set_value(unsigned int new_value,
double current_frame,
double end_frame)
{
QString new_window_title = window_title;
title_text_dot_count++;
if (title_text_dot_count > 3)
{
title_text_dot_count = 0;
}
for (int i = 0; i < title_text_dot_count; i++)
{
new_window_title.append(".");
}
setWindowTitle(new_window_title);
ui->progress_bar->setValue(new_value);
ui->progress_bar->setFormat(QString("(%1/%2) %3/%4")
.arg(new_value)
.arg(progress_bar_max)
.arg(current_frame)
.arg(end_frame));
}
void Processing::on_cancel_button_clicked()
{
close();
}
/* Copyright (C) 2022 Lari Varjonen <[email protected]> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "processing.h" #include "ui_processing.h" Processing::Processing(QWidget *parent) : QDialog(parent), ui(new Ui::Processing) { ui->setupUi(this); setWindowTitle(window_title); } Processing::~Processing() { delete ui; } void Processing::set_max(unsigned int max) { ui->progress_bar->setMaximum(max); this->progress_bar_max = max; } void Processing::set_value(unsigned int new_value, double current_frame, double end_frame) { QString new_window_title = window_title; title_text_dot_count++; if (title_text_dot_count > 3) { title_text_dot_count = 0; } for (int i = 0; i < title_text_dot_count; i++) { new_window_title.append("."); } setWindowTitle(new_window_title); ui->progress_bar->setValue(new_value); ui->progress_bar->setFormat(QString("(%1/%2) %3/%4") .arg(new_value) .arg(progress_bar_max) .arg(current_frame) .arg(end_frame)); } void Processing::on_cancel_button_clicked() { close(); }
/*
    Copyright (C) 2022 Lari Varjonen <[email protected]>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "processing.h"
#include "ui_processing.h"


Processing::Processing(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Processing)
{
    ui->setupUi(this);
    setWindowTitle(window_title);
}

Processing::~Processing()
{
    delete ui;
}

void Processing::set_max(unsigned int max)
{
    ui->progress_bar->setMaximum(max);
    this->progress_bar_max = max;
}

void Processing::set_value(unsigned int new_value,
                           double current_frame,
                           double end_frame)
{
    QString new_window_title = window_title;
    title_text_dot_count++;
    if (title_text_dot_count > 3)
    {
        title_text_dot_count = 0;
    }
    for (int i = 0; i < title_text_dot_count; i++)
    {
        new_window_title.append(".");
    }
    setWindowTitle(new_window_title);

    ui->progress_bar->setValue(new_value);
    ui->progress_bar->setFormat(QString("(%1/%2) %3/%4")
                                .arg(new_value)
                                .arg(progress_bar_max)
                                .arg(current_frame)
                                .arg(end_frame));
}

void Processing::on_cancel_button_clicked()
{
    close();
}
processing.h
/*
Copyright (C) 2022 Lari Varjonen <[email protected]>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef PROCESSING_H
#define PROCESSING_H
#include <QDialog>
namespace Ui {
class Processing;
}
class Processing : public QDialog
{
Q_OBJECT
public:
explicit Processing(QWidget *parent = nullptr);
~Processing();
void set_max(unsigned int max);
void set_value(unsigned int new_value,
double current_frame,
double end_frame);
public slots:
void on_cancel_button_clicked();
private:
QString window_title = "Processing";
Ui::Processing *ui;
int title_text_dot_count = 0;
int progress_bar_max;
};
#endif // PROCESSING_H
/* Copyright (C) 2022 Lari Varjonen <[email protected]> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef PROCESSING_H #define PROCESSING_H #include <QDialog> namespace Ui { class Processing; } class Processing : public QDialog { Q_OBJECT public: explicit Processing(QWidget *parent = nullptr); ~Processing(); void set_max(unsigned int max); void set_value(unsigned int new_value, double current_frame, double end_frame); public slots: void on_cancel_button_clicked(); private: QString window_title = "Processing"; Ui::Processing *ui; int title_text_dot_count = 0; int progress_bar_max; }; #endif // PROCESSING_H
/*
        Copyright (C) 2022 Lari Varjonen <[email protected]>
    
        This program is free software; you can redistribute it and/or
        modify it under the terms of the GNU General Public License
        version 2 as published by the Free Software Foundation.
    
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
    
        You should have received a copy of the GNU General Public License
        along with this program; if not, write to the Free Software
        Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    */
    
    #ifndef PROCESSING_H
    #define PROCESSING_H
    
    #include <QDialog>
    
    
    namespace Ui {
    class Processing;
    }
    
    
    class Processing : public QDialog
    {
        Q_OBJECT
    
    public:
        explicit Processing(QWidget *parent = nullptr);
        ~Processing();
    
        void set_max(unsigned int max);
        void set_value(unsigned int new_value,
                       double current_frame,
                       double end_frame);
    
    public slots:
        void on_cancel_button_clicked();
    
    private:
        QString window_title = "Processing";
        Ui::Processing *ui;
        int title_text_dot_count = 0;
        int progress_bar_max;
    };
    
    #endif // PROCESSING_H
    
« Back | ↑ Top