mirror of https://github.com/JakubMelka/PDF4QT.git
Issue #107: Enable/Disable image conversion GUI
This commit is contained in:
parent
fc44dfa4bc
commit
cf7d65dc82
|
@ -58,6 +58,7 @@ private:
|
||||||
class PDF4QTLIBSHARED_EXPORT PDFImage
|
class PDF4QTLIBSHARED_EXPORT PDFImage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
PDFImage() = default;
|
||||||
|
|
||||||
/// Creates image from the content and the dictionary. If image can't be created, then exception is thrown.
|
/// Creates image from the content and the dictionary. If image can't be created, then exception is thrown.
|
||||||
/// \param document Document
|
/// \param document Document
|
||||||
|
@ -112,8 +113,6 @@ public:
|
||||||
const PDFImageData& getSoftMaskData() const { return m_softMask; }
|
const PDFImageData& getSoftMaskData() const { return m_softMask; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PDFImage() = default;
|
|
||||||
|
|
||||||
PDFImageData m_imageData;
|
PDFImageData m_imageData;
|
||||||
PDFImageData m_softMask;
|
PDFImageData m_softMask;
|
||||||
PDFColorSpacePointer m_colorSpace;
|
PDFColorSpacePointer m_colorSpace;
|
||||||
|
|
|
@ -62,7 +62,7 @@ GENERATE_EXPORT_HEADER(Pdf4QtViewer
|
||||||
PDF4QTVIEWERLIBSHARED_EXPORT
|
PDF4QTVIEWERLIBSHARED_EXPORT
|
||||||
EXPORT_FILE_NAME "${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR}/pdf4qtviewer_export.h")
|
EXPORT_FILE_NAME "${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR}/pdf4qtviewer_export.h")
|
||||||
|
|
||||||
target_link_libraries(Pdf4QtViewer PRIVATE Pdf4QtLib Qt6::Core Qt6::Gui Qt6::Widgets Qt6::PrintSupport Qt6::TextToSpeech Qt6::Xml Qt6::OpenGLWidgets)
|
target_link_libraries(Pdf4QtViewer PRIVATE Pdf4QtLib Qt6::Core Qt6::Gui Qt6::Widgets Qt6::PrintSupport Qt6::TextToSpeech Qt6::Xml Qt6::Svg Qt6::OpenGLWidgets)
|
||||||
target_include_directories(Pdf4QtViewer INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(Pdf4QtViewer INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
target_include_directories(Pdf4QtViewer PUBLIC ${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR})
|
target_include_directories(Pdf4QtViewer PUBLIC ${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR})
|
||||||
|
|
||||||
|
|
|
@ -23,16 +23,122 @@
|
||||||
#include "pdfimage.h"
|
#include "pdfimage.h"
|
||||||
#include "pdfdbgheap.h"
|
#include "pdfdbgheap.h"
|
||||||
#include "pdfexception.h"
|
#include "pdfexception.h"
|
||||||
|
#include "pdfwidgetutils.h"
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
#include <QtConcurrent/QtConcurrent>
|
#include <QtConcurrent/QtConcurrent>
|
||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QtSvg/QSvgRenderer>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QToolTip>
|
||||||
|
|
||||||
namespace pdfviewer
|
namespace pdfviewer
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class ImagePreviewDelegate : public QStyledItemDelegate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ImagePreviewDelegate(std::vector<PDFCreateBitonalDocumentDialog::ImageConversionInfo>* imageConversionInfos, QObject* parent) :
|
||||||
|
QStyledItemDelegate(parent),
|
||||||
|
m_imageConversionInfos(imageConversionInfos)
|
||||||
|
{
|
||||||
|
m_yesRenderer.load(QString(":/resources/result-ok.svg"));
|
||||||
|
m_noRenderer.load(QString(":/resources/result-error.svg"));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override
|
||||||
|
{
|
||||||
|
QStyledItemDelegate::paint(painter, option, index);
|
||||||
|
|
||||||
|
QRect markRect = getMarkRect(option);
|
||||||
|
|
||||||
|
if (index.isValid())
|
||||||
|
{
|
||||||
|
const PDFCreateBitonalDocumentDialog::ImageConversionInfo& info = m_imageConversionInfos->at(index.row());
|
||||||
|
if (info.conversionEnabled)
|
||||||
|
{
|
||||||
|
m_yesRenderer.render(painter, markRect);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_noRenderer.render(painter, markRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool editorEvent(QEvent* event,
|
||||||
|
QAbstractItemModel* model,
|
||||||
|
const QStyleOptionViewItem& option,
|
||||||
|
const QModelIndex& index)
|
||||||
|
{
|
||||||
|
Q_UNUSED(model);
|
||||||
|
Q_UNUSED(index);
|
||||||
|
|
||||||
|
if (event->type() == QEvent::MouseButtonPress && index.isValid())
|
||||||
|
{
|
||||||
|
QMouseEvent* mouseEvent = dynamic_cast<QMouseEvent*>(event);
|
||||||
|
if (mouseEvent && mouseEvent->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
// Do we click on yes/no mark?
|
||||||
|
QRectF markRect = getMarkRect(option);
|
||||||
|
if (markRect.contains(mouseEvent->position()))
|
||||||
|
{
|
||||||
|
PDFCreateBitonalDocumentDialog::ImageConversionInfo& info = m_imageConversionInfos->at(index.row());
|
||||||
|
info.conversionEnabled = !info.conversionEnabled;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool helpEvent(QHelpEvent* event,
|
||||||
|
QAbstractItemView* view,
|
||||||
|
const QStyleOptionViewItem& option,
|
||||||
|
const QModelIndex& index) override
|
||||||
|
{
|
||||||
|
Q_UNUSED(index);
|
||||||
|
|
||||||
|
if (!event || !view)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event->type() == QEvent::ToolTip)
|
||||||
|
{
|
||||||
|
// Are we hovering over yes/no mark?
|
||||||
|
QRectF markRect = getMarkRect(option);
|
||||||
|
if (markRect.contains(event->pos()))
|
||||||
|
{
|
||||||
|
event->accept();
|
||||||
|
QToolTip::showText(event->globalPos(), tr("Toggle this icon to switch image conversion to bitonic format on or off."), view);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr QSize s_iconSize = QSize(24, 24);
|
||||||
|
|
||||||
|
QRect getMarkRect(const QStyleOptionViewItem& option) const
|
||||||
|
{
|
||||||
|
QSize markSize = pdf::PDFWidgetUtils::scaleDPI(option.widget, s_iconSize);
|
||||||
|
QRect markRect(option.rect.left(), option.rect.top(), markSize.width(), markSize.height());
|
||||||
|
return markRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<PDFCreateBitonalDocumentDialog::ImageConversionInfo>* m_imageConversionInfos;
|
||||||
|
mutable QSvgRenderer m_yesRenderer;
|
||||||
|
mutable QSvgRenderer m_noRenderer;
|
||||||
|
};
|
||||||
|
|
||||||
PDFCreateBitonalDocumentDialog::PDFCreateBitonalDocumentDialog(const pdf::PDFDocument* document,
|
PDFCreateBitonalDocumentDialog::PDFCreateBitonalDocumentDialog(const pdf::PDFDocument* document,
|
||||||
const pdf::PDFCMS* cms,
|
const pdf::PDFCMS* cms,
|
||||||
QWidget* parent) :
|
QWidget* parent) :
|
||||||
|
@ -58,6 +164,8 @@ PDFCreateBitonalDocumentDialog::PDFCreateBitonalDocumentDialog(const pdf::PDFDoc
|
||||||
updateUi();
|
updateUi();
|
||||||
pdf::PDFWidgetUtils::style(this);
|
pdf::PDFWidgetUtils::style(this);
|
||||||
|
|
||||||
|
ui->imageListWidget->setItemDelegate( new ImagePreviewDelegate(&m_imagesToBeConverted, this));
|
||||||
|
|
||||||
loadImages();
|
loadImages();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,63 +198,39 @@ void PDFCreateBitonalDocumentDialog::loadImages()
|
||||||
ui->imageListWidget->setIconSize(iconSize);
|
ui->imageListWidget->setIconSize(iconSize);
|
||||||
QSize imageSize = iconSize * ui->imageListWidget->devicePixelRatioF();
|
QSize imageSize = iconSize * ui->imageListWidget->devicePixelRatioF();
|
||||||
|
|
||||||
pdf::PDFCMSGeneric genericCms;
|
int i = 0;
|
||||||
|
|
||||||
for (pdf::PDFObjectReference reference : m_imageReferences)
|
for (pdf::PDFObjectReference reference : m_imageReferences)
|
||||||
{
|
{
|
||||||
std::optional<pdf::PDFImage> pdfImage;
|
if (i++>10)
|
||||||
pdf::PDFObject imageObject = m_document->getObjectByReference(reference);
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<pdf::PDFImage> pdfImage = getImageFromReference(reference);
|
||||||
|
if (!pdfImage)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdf::PDFCMSGeneric genericCms;
|
||||||
pdf::PDFRenderErrorReporterDummy errorReporter;
|
pdf::PDFRenderErrorReporterDummy errorReporter;
|
||||||
|
|
||||||
if (!imageObject.isStream())
|
|
||||||
{
|
|
||||||
// Image is not stream
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pdf::PDFStream* stream = imageObject.getStream();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
pdf::PDFColorSpacePointer colorSpace;
|
|
||||||
const pdf::PDFDictionary* streamDictionary = stream->getDictionary();
|
|
||||||
if (streamDictionary->hasKey("ColorSpace"))
|
|
||||||
{
|
|
||||||
const pdf::PDFObject& colorSpaceObject = m_document->getObject(streamDictionary->get("ColorSpace"));
|
|
||||||
if (colorSpaceObject.isName() || colorSpaceObject.isArray())
|
|
||||||
{
|
|
||||||
pdf::PDFDictionary dummyDictionary;
|
|
||||||
colorSpace = pdf::PDFAbstractColorSpace::createColorSpace(&dummyDictionary, m_document, colorSpaceObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pdfImage.emplace(pdf::PDFImage::createImage(m_document,
|
|
||||||
stream,
|
|
||||||
colorSpace,
|
|
||||||
false,
|
|
||||||
pdf::RenderingIntent::Perceptual,
|
|
||||||
&errorReporter));
|
|
||||||
}
|
|
||||||
catch (pdf::PDFException)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
QImage image = pdfImage->getImage(&genericCms, &errorReporter, nullptr);
|
QImage image = pdfImage->getImage(&genericCms, &errorReporter, nullptr);
|
||||||
|
|
||||||
if (image.isNull())
|
if (image.isNull())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
QListWidgetItem* item = new QListWidgetItem(ui->imageListWidget);
|
QListWidgetItem* item = new QListWidgetItem(ui->imageListWidget);
|
||||||
QWidget* widget = new QWidget;
|
|
||||||
QHBoxLayout* layout = new QHBoxLayout(widget);
|
|
||||||
QCheckBox* checkbox = new QCheckBox(widget);
|
|
||||||
layout->addWidget(checkbox);
|
|
||||||
|
|
||||||
image = image.scaled(imageSize.width(), imageSize.height(), Qt::KeepAspectRatio, Qt::FastTransformation);
|
image = image.scaled(imageSize.width(), imageSize.height(), Qt::KeepAspectRatio, Qt::FastTransformation);
|
||||||
item->setIcon(QIcon(QPixmap::fromImage(image)));
|
item->setIcon(QIcon(QPixmap::fromImage(image)));
|
||||||
|
Qt::ItemFlags flags = item->flags();
|
||||||
|
flags.setFlag(Qt::ItemIsEditable, true);
|
||||||
|
item->setFlags(flags);
|
||||||
|
|
||||||
ui->imageListWidget->setItemWidget(item, widget);
|
ImageConversionInfo imageConversionInfo;
|
||||||
|
imageConversionInfo.imageReference = reference;
|
||||||
|
imageConversionInfo.conversionEnabled = true;
|
||||||
|
m_imagesToBeConverted.push_back(imageConversionInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,4 +243,45 @@ void PDFCreateBitonalDocumentDialog::updateUi()
|
||||||
m_createBitonalDocumentButton->setEnabled(!m_conversionInProgress);
|
m_createBitonalDocumentButton->setEnabled(!m_conversionInProgress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<pdf::PDFImage> PDFCreateBitonalDocumentDialog::getImageFromReference(pdf::PDFObjectReference reference) const
|
||||||
|
{
|
||||||
|
std::optional<pdf::PDFImage> pdfImage;
|
||||||
|
pdf::PDFObject imageObject = m_document->getObjectByReference(reference);
|
||||||
|
pdf::PDFRenderErrorReporterDummy errorReporter;
|
||||||
|
|
||||||
|
if (!imageObject.isStream())
|
||||||
|
{
|
||||||
|
// Image is not stream
|
||||||
|
return pdfImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pdf::PDFStream* stream = imageObject.getStream();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pdf::PDFColorSpacePointer colorSpace;
|
||||||
|
const pdf::PDFDictionary* streamDictionary = stream->getDictionary();
|
||||||
|
if (streamDictionary->hasKey("ColorSpace"))
|
||||||
|
{
|
||||||
|
const pdf::PDFObject& colorSpaceObject = m_document->getObject(streamDictionary->get("ColorSpace"));
|
||||||
|
if (colorSpaceObject.isName() || colorSpaceObject.isArray())
|
||||||
|
{
|
||||||
|
pdf::PDFDictionary dummyDictionary;
|
||||||
|
colorSpace = pdf::PDFAbstractColorSpace::createColorSpace(&dummyDictionary, m_document, colorSpaceObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pdfImage.emplace(pdf::PDFImage::createImage(m_document,
|
||||||
|
stream,
|
||||||
|
colorSpace,
|
||||||
|
false,
|
||||||
|
pdf::RenderingIntent::Perceptual,
|
||||||
|
&errorReporter));
|
||||||
|
}
|
||||||
|
catch (pdf::PDFException)
|
||||||
|
{
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
return pdfImage;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdfviewer
|
} // namespace pdfviewer
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "pdfcms.h"
|
#include "pdfcms.h"
|
||||||
#include "pdfdocument.h"
|
#include "pdfdocument.h"
|
||||||
#include "pdfobjectutils.h"
|
#include "pdfobjectutils.h"
|
||||||
|
#include "pdfimage.h"
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QFuture>
|
#include <QFuture>
|
||||||
|
@ -43,6 +44,12 @@ public:
|
||||||
|
|
||||||
pdf::PDFDocument takeBitonaldDocument() { return qMove(m_bitonalDocument); }
|
pdf::PDFDocument takeBitonaldDocument() { return qMove(m_bitonalDocument); }
|
||||||
|
|
||||||
|
struct ImageConversionInfo
|
||||||
|
{
|
||||||
|
pdf::PDFObjectReference imageReference;
|
||||||
|
bool conversionEnabled = true;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createBitonalDocument();
|
void createBitonalDocument();
|
||||||
void onCreateBitonalDocumentButtonClicked();
|
void onCreateBitonalDocumentButtonClicked();
|
||||||
|
@ -50,6 +57,8 @@ private:
|
||||||
|
|
||||||
void updateUi();
|
void updateUi();
|
||||||
|
|
||||||
|
std::optional<pdf::PDFImage> getImageFromReference(pdf::PDFObjectReference reference) const;
|
||||||
|
|
||||||
Ui::PDFCreateBitonalDocumentDialog* ui;
|
Ui::PDFCreateBitonalDocumentDialog* ui;
|
||||||
const pdf::PDFDocument* m_document;
|
const pdf::PDFDocument* m_document;
|
||||||
const pdf::PDFCMS* m_cms;
|
const pdf::PDFCMS* m_cms;
|
||||||
|
@ -60,7 +69,7 @@ private:
|
||||||
pdf::PDFDocument m_bitonalDocument;
|
pdf::PDFDocument m_bitonalDocument;
|
||||||
pdf::PDFObjectClassifier m_classifier;
|
pdf::PDFObjectClassifier m_classifier;
|
||||||
std::vector<pdf::PDFObjectReference> m_imageReferences;
|
std::vector<pdf::PDFObjectReference> m_imageReferences;
|
||||||
std::vector<pdf::PDFObjectReference> m_imagesToBeConvertedReferences;
|
std::vector<ImageConversionInfo> m_imagesToBeConverted;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pdfviewer
|
} // namespace pdfviewer
|
||||||
|
|
Loading…
Reference in New Issue