mirror of
				https://github.com/JakubMelka/PDF4QT.git
				synced 2025-06-05 21:59:17 +02:00 
			
		
		
		
	Issue #107: Enable/Disable image conversion GUI
This commit is contained in:
		| @@ -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 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user