Commit c5fedfb1 authored by Aleks Kissinger's avatar Aleks Kissinger

image export in progress

parent 281efdc8
#include "pdfdocument.h"
#include <QFile>
#include <QByteArray>
#include <QDebug>
#include <QSvgGenerator>
#include <QPainter>
#include <QApplication>
#include <QClipboard>
PdfDocument::PdfDocument(QString file, QObject *parent) : QObject(parent)
{
// use loadFromData to avoid holding a lock on the PDF file in windows
QFile f(file);
if (f.open(QFile::ReadOnly)) {
QByteArray data = f.readAll();
f.close();
_doc = Poppler::Document::loadFromData(data);
} else {
_doc = nullptr;
}
if (!_doc) {
_doc = nullptr;
_page = nullptr;
} else {
_doc->setRenderHint(Poppler::Document::Antialiasing);
_doc->setRenderHint(Poppler::Document::TextAntialiasing);
_doc->setRenderHint(Poppler::Document::TextHinting);
_page = _doc->page(0);
}
}
void PdfDocument::renderTo(QLabel *label, QRect rect)
{
if (!isValid()) return;
QSizeF pageSize = _page->pageSizeF();
qreal ratio = label->devicePixelRatioF();
//QRect rect = ui->scrollArea->visibleRegion().boundingRect();
int w = static_cast<int>(ratio * (rect.width() - 20));
int h = static_cast<int>(ratio * (rect.height() - 20));
qreal scale = fmin(static_cast<qreal>(w) / pageSize.width(),
static_cast<qreal>(h) / pageSize.height());
int dpi = static_cast<int>(scale * 72.0);
int w1 = static_cast<int>(scale * pageSize.width());
int h1 = static_cast<int>(scale * pageSize.height());
//qDebug() << "hidpi ratio:" << ratio;
//qDebug() << "visible width:" << w;
//qDebug() << "visible height:" << h;
//qDebug() << "doc width:" << pageSize.width();
//qDebug() << "doc height:" << pageSize.height();
//qDebug() << "scale:" << scale;
//qDebug() << "dpi:" << dpi;
QPixmap pm = QPixmap::fromImage(_page->renderToImage(dpi, dpi, (w1 - w)/2, (h1 - h)/2, w, h));
pm.setDevicePixelRatio(ratio);
label->setPixmap(pm);
}
bool PdfDocument::isValid()
{
return (_page != nullptr);
}
bool PdfDocument::exportImage(QString file, const char *format, QSize outputSize)
{
QImage img = asImage(outputSize);
if (!img.isNull()) return img.save(file, format);
else return false;
}
bool PdfDocument::exportPdf(QString file)
{
if (!isValid()) return false;
Poppler::PDFConverter *conv = _doc->pdfConverter();
conv->setOutputFileName(file);
bool success = conv->convert();
delete conv;
return success;
}
void PdfDocument::copyImageToClipboard(QSize outputSize)
{
QImage img = asImage(outputSize);
if (!img.isNull()) {
QApplication::clipboard()->setImage(img, QClipboard::Clipboard);
}
}
QImage PdfDocument::asImage(QSize outputSize)
{
if (!isValid()) return QImage();
if (outputSize.isNull()) outputSize = size();
QSize pageSize = _page->pageSize();
int dpix = (72 * outputSize.width()) / pageSize.width();
int dpiy = (72 * outputSize.width()) / pageSize.width();
QImage img = _page->renderToImage(dpix, dpiy, 0, 0,
outputSize.width(), outputSize.height());
return img;
}
// CRASHES TikZiT when figures contain text, due to limitations of Arthur backend
//void PdfDocument::exportToSvg(QString file, QSize size) {
// QSvgGenerator gen;
// gen.setFileName(file);
// gen.setSize(size);
// gen.setViewBox(QRect(0,0,size.width(),size.height()));
// gen.setDescription("SVG generated from PDF by TikZiT");
// QPainter painter;
// // set the backend to Qt for renderToPainter() support
// Poppler::Document::RenderBackend backend = _doc->renderBackend();
// _doc->setRenderBackend(Poppler::Document::ArthurBackend);
// painter.begin(&gen);
// _page->renderToPainter(&painter);
// painter.end();
// _doc->setRenderBackend(backend);
//}
QSize PdfDocument::size()
{
if (isValid()) {
return _page->pageSize();
}
}
#ifndef PDFDOCUMENT_H
#define PDFDOCUMENT_H
#include <QObject>
#include <QString>
#include <QLabel>
#include <poppler/qt5/poppler-qt5.h>
class PdfDocument : public QObject
{
Q_OBJECT
public:
explicit PdfDocument(QString file, QObject *parent = nullptr);
void renderTo(QLabel *label, QRect rect);
bool isValid();
// void exportToSvg(QString file, QSize size);
bool exportImage(QString file, const char *format, QSize outputSize=QSize());
bool exportPdf(QString file);
void copyImageToClipboard(QSize outputSize=QSize());
QImage asImage(QSize outputSize=QSize());
QSize size();
private:
Poppler::Document *_doc;
Poppler::Page *_page;
};
#endif // PDFDOCUMENT_H
#include "exportdialog.h"
#include "ui_exportdialog.h"
#include "tikzit.h"
ExportDialog::ExportDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::ExportDialog)
{
ui->setupUi(this);
QIntValidator *v = new QIntValidator(this);
v->setBottom(1);
ui->width->setValidator(v);
ui->height->setValidator(v);
connect(ui->width, SIGNAL(editingFinished()),
this, SLOT(setHeightFromWidth()));
connect(ui->height, SIGNAL(editingFinished()),
this, SLOT(setWidthFromHeight()));
PdfDocument *doc = tikzit->previewWindow()->doc();
if (doc) {
QSize size = doc->size() * 4;
ui->width->blockSignals(true);
ui->height->blockSignals(true);
ui->width->setText(QString::number(size.width()));
ui->height->setText(QString::number(size.height()));
ui->width->blockSignals(false);
ui->height->blockSignals(false);
}
}
ExportDialog::~ExportDialog()
{
delete ui;
}
void ExportDialog::setHeightFromWidth()
{
if (ui->keepAspect->isChecked()) {
PdfDocument *doc = tikzit->previewWindow()->doc();
if (doc == nullptr || doc->size().width() == 0 || doc->size().height() == 0) return;
int w = ui->width->text().toInt();
int h = (w * doc->size().height()) / doc->size().width();
ui->height->blockSignals(true);
ui->height->setText(QString::number(h));
ui->height->blockSignals(false);
}
}
void ExportDialog::setWidthFromHeight()
{
if (ui->keepAspect->isChecked()) {
PdfDocument *doc = tikzit->previewWindow()->doc();
if (doc == nullptr || doc->size().width() == 0 || doc->size().height() == 0) return;
int h = ui->height->text().toInt();
int w = (h * doc->size().width()) / doc->size().height();
ui->width->blockSignals(true);
ui->width->setText(QString::number(w));
ui->width->blockSignals(false);
}
}
void ExportDialog::on_keepAspect_stateChanged(int state)
{
if (state == Qt::Checked) setHeightFromWidth();
}
void ExportDialog::on_browseButton_clicked()
{
}
void ExportDialog::on_fileFormat_currentIndexChanged(int f)
{
ui->width->setEnabled(f != PDF);
ui->height->setEnabled(f != PDF);
}
#ifndef EXPORTDIALOG_H
#define EXPORTDIALOG_H
#include <QDialog>
namespace Ui {
class ExportDialog;
}
class ExportDialog : public QDialog
{
Q_OBJECT
public:
explicit ExportDialog(QWidget *parent = nullptr);
~ExportDialog();
enum Format {
PNG = 0,
JPG = 1,
PDF = 2
};
protected slots:
void setHeightFromWidth();
void setWidthFromHeight();
void on_keepAspect_stateChanged(int state);
void on_browseButton_clicked();
void on_fileFormat_currentIndexChanged(int f);
private:
Ui::ExportDialog *ui;
};
#endif // EXPORTDIALOG_H
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ExportDialog</class>
<widget class="QDialog" name="ExportDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>394</width>
<height>119</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>File</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Format</string>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLineEdit" name="filePath"/>
</item>
<item>
<widget class="QToolButton" name="browseButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="fileFormat">
<item>
<property name="text">
<string>Portable Network Graphics (PNG)</string>
</property>
</item>
<item>
<property name="text">
<string>Jpeg Image (JPG)</string>
</property>
</item>
<item>
<property name="text">
<string>Original (PDF)</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Dimensions</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="width"/>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string> X </string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="height"/>
</item>
</layout>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="keepAspect">
<property name="text">
<string>Keep aspect ratio</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ExportDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ExportDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
......@@ -19,7 +19,7 @@ LatexProcess::LatexProcess(PreviewWindow *preview, QObject *parent) : QObject(pa
connect(_proc, SIGNAL(finished(int)), this, SLOT(finished(int)));
// for debug purposes
// _workingDir.setAutoRemove(false);
_workingDir.setAutoRemove(false);
}
void LatexProcess::makePreview(QString tikz)
......
......@@ -3,6 +3,7 @@
#include "tikzit.h"
#include "latexprocess.h"
#include "exportdialog.h"
#include <QLabel>
#include <QImage>
......@@ -16,6 +17,7 @@
#include <QMessageBox>
#include <cmath>
#include <QMovie>
#include <QAction>
PreviewWindow::PreviewWindow(QWidget *parent) :
QDialog(parent),
......@@ -31,7 +33,6 @@ PreviewWindow::PreviewWindow(QWidget *parent) :
}
_doc = nullptr;
_page = nullptr;
_loader = new QLabel(ui->tabWidget->tabBar());
_loader->setMinimumSize(QSize(16,16));
......@@ -44,6 +45,27 @@ PreviewWindow::PreviewWindow(QWidget *parent) :
render();
}
void PreviewWindow::contextMenuEvent(QContextMenuEvent *event)
{
QMenu menu(this);
QAction *act;
act = new QAction("Export Image...");
connect(act, SIGNAL(triggered()), this, SLOT(exportImage()));
menu.addAction(act);
act = new QAction("Copy to Clipboard");
connect(act, SIGNAL(triggered()), this, SLOT(copyImageToClipboard()));
menu.addAction(act);
menu.exec(event->globalPos());
}
PdfDocument *PreviewWindow::doc() const
{
return _doc;
}
PreviewWindow::~PreviewWindow()
{
delete ui;
......@@ -51,30 +73,24 @@ PreviewWindow::~PreviewWindow()
void PreviewWindow::setPdf(QString file)
{
Poppler::Document *oldDoc = _doc;
// use loadFromData to avoid holding a lock on the PDF file in windows
QFile f(file);
f.open(QFile::ReadOnly);
QByteArray data = f.readAll();
f.close();
Poppler::Document *newDoc = Poppler::Document::loadFromData(data);
if (!newDoc) {
//QFile f(file);
//f.open(QFile::ReadOnly);
//QByteArray data = f.readAll();
//f.close();
PdfDocument *newDoc = new PdfDocument(file, this);
if (newDoc->isValid()) {
PdfDocument *oldDoc = _doc;
_doc = newDoc;
if (oldDoc != nullptr) delete oldDoc;
render();
} else {
QMessageBox::warning(nullptr,
"Could not read PDF",
"Could not read: '" + file + "'.");
return;
delete newDoc;
}
_doc = newDoc;
_doc->setRenderHint(Poppler::Document::Antialiasing);
_doc->setRenderHint(Poppler::Document::TextAntialiasing);
_doc->setRenderHint(Poppler::Document::TextHinting );
_page = _doc->page(0);
render();
if (oldDoc != nullptr) delete oldDoc;
}
QPlainTextEdit *PreviewWindow::outputTextEdit()
......@@ -130,30 +146,28 @@ void PreviewWindow::showEvent(QShowEvent *e) {
}
void PreviewWindow::render() {
if (_page == nullptr) return;
QSizeF size = _page->pageSizeF();
qreal ratio = devicePixelRatioF();
QRect rect = ui->scrollArea->visibleRegion().boundingRect();
int w = static_cast<int>(ratio * (rect.width() - 20));
int h = static_cast<int>(ratio * (rect.height() - 20));
qreal scale = fmin(static_cast<qreal>(w) / size.width(),
static_cast<qreal>(h) / size.height());
if (_doc != nullptr) {
_doc->renderTo(ui->pdf,
ui->scrollArea->visibleRegion().boundingRect());
ui->pdf->repaint();
}
}
void PreviewWindow::exportImage()
{
if (_doc == nullptr) return;
ExportDialog *d = new ExportDialog(this);
int ret = d->exec();
if (ret == QDialog::Accepted) {
qDebug() << "save accepted";
}
}
int dpi = static_cast<int>(scale * 72.0);
int w1 = static_cast<int>(scale * size.width());
int h1 = static_cast<int>(scale * size.height());
void PreviewWindow::copyImageToClipboard()
{
if (_doc != nullptr) {
_doc->copyImageToClipboard(_doc->size() * 4);
}
}
// qDebug() << "visible width:" << w;
// qDebug() << "visible height:" << h;
// qDebug() << "doc width:" << size.width();
// qDebug() << "doc height:" << size.height();
// qDebug() << "scale:" << scale;
// qDebug() << "dpi:" << dpi;
QPixmap pm = QPixmap::fromImage(_page->renderToImage(dpi, dpi, (w1 - w)/2, (h1 - h)/2, w, h));
pm.setDevicePixelRatio(ratio);
ui->pdf->setPixmap(pm);
}
#ifndef PREVIEWWINDOW_H
#define PREVIEWWINDOW_H
#include "pdfdocument.h"
#include <QDialog>
#include <QLabel>
#include <QPlainTextEdit>
#include <QContextMenuEvent>
#include <poppler/qt5/poppler-qt5.h>
namespace Ui {
......@@ -20,24 +22,27 @@ public:
Running, Success, Failed
};
explicit PreviewWindow(QWidget *parent = nullptr);
~PreviewWindow();
~PreviewWindow() override;
void setPdf(QString file);
QString preparePreview(QString tikz);
QPlainTextEdit *outputTextEdit();
void setStatus(Status status);
PdfDocument *doc() const;
public slots:
void render();
void exportImage();
void copyImageToClipboard();
protected:
void resizeEvent(QResizeEvent *e);
void showEvent(QShowEvent *e);
void closeEvent(QCloseEvent *e);
void resizeEvent(QResizeEvent *e) override;
void showEvent(QShowEvent *e) override;
void closeEvent(QCloseEvent *e) override;
void contextMenuEvent(QContextMenuEvent *event) override;
private:
Ui::PreviewWindow *ui;
Poppler::Document *_doc;
Poppler::Page *_page;
PdfDocument *_doc;
QLabel *_loader;
};
......
......@@ -489,6 +489,11 @@ void Tikzit::cleanupLatex()
}
}
PreviewWindow *Tikzit::previewWindow() const
{
return _preview;
}
//StylePalette *Tikzit::stylePalette() const
//{
// return _stylePalette;
......
......@@ -136,6 +136,8 @@ public:
QString styleFilePath() const;
void updateRecentFiles();
PreviewWindow *previewWindow() const;
public slots:
void clearRecentFiles();
void setCheckForUpdates(bool check);
......
# CONFIG += debug
QT += core gui widgets network
QT += core gui widgets network svg
test {
CONFIG += testcase
......@@ -73,7 +73,9 @@ SOURCES += src/gui/mainwindow.cpp \
src/gui/styleeditor.cpp \
src/data/stylelist.cpp \
src/gui/previewwindow.cpp \
src/gui/latexprocess.cpp
src/gui/latexprocess.cpp \
src/data/pdfdocument.cpp \
src/gui/exportdialog.cpp
HEADERS += src/gui/mainwindow.h \
src/gui/toolpalette.h \
......@@ -101,14 +103,17 @@ HEADERS += src/gui/mainwindow.h \
src/gui/styleeditor.h \
src/data/stylelist.h \
src/gui/previewwindow.h \
src/gui/latexprocess.h
src/gui/latexprocess.h \
src/data/pdfdocument.h \
src/gui/exportdialog.h
FORMS += src/gui/mainwindow.ui \
src/gui/propertypalette.ui \
src/gui/mainmenu.ui \
src/gui/stylepalette.ui \
src/gui/styleeditor.ui \
src/gui/previewwindow.ui
src/gui/previewwindow.ui \
src/gui/exportdialog.ui
INCLUDEPATH += src src/gui src/data
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment