// Copyright (C) 2021 Jakub Melka // // This file is part of PDF4QT. // // PDF4QT is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // with the written consent of the copyright owner, any later version. // // PDF4QT 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with PDF4QT. If not, see . #include "objectviewerwidget.h" #include "ui_objectviewerwidget.h" #include "pdfimage.h" #include "pdfencoding.h" #include "pdfdocumentwriter.h" #include "pdfexception.h" namespace pdfplugin { ObjectViewerWidget::ObjectViewerWidget(QWidget *parent) : ObjectViewerWidget(false, parent) { } ObjectViewerWidget::ObjectViewerWidget(bool isPinned, QWidget* parent) : QWidget(parent), ui(new Ui::ObjectViewerWidget), m_cms(nullptr), m_document(nullptr), m_isPinned(isPinned), m_isRootObject(false) { ui->setupUi(this); m_printableCharacters = pdf::PDFEncoding::getPrintableCharacters(); m_printableCharacters.push_back('\n'); connect(ui->pinButton, &QPushButton::clicked, this, &ObjectViewerWidget::pinRequest); connect(ui->unpinButton, &QPushButton::clicked, this, &ObjectViewerWidget::unpinRequest); updateUi(); updatePinnedUi(); } ObjectViewerWidget::~ObjectViewerWidget() { delete ui; } ObjectViewerWidget* ObjectViewerWidget::clone(bool isPinned, QWidget* parent) { ObjectViewerWidget* cloned = new ObjectViewerWidget(isPinned, parent); cloned->setDocument(m_document); cloned->setCms(m_cms); cloned->setData(m_currentReference, m_currentObject, m_isRootObject); return cloned; } void ObjectViewerWidget::setPinned(bool isPinned) { if (m_isPinned != isPinned) { m_isPinned = isPinned; updatePinnedUi(); } } void ObjectViewerWidget::setData(pdf::PDFObjectReference currentReference, pdf::PDFObject currentObject, bool isRootObject) { if (m_currentReference != currentReference || m_currentObject != currentObject || m_isRootObject != isRootObject) { m_currentReference = currentReference; m_currentObject = currentObject; m_isRootObject = isRootObject; updateUi(); } } void ObjectViewerWidget::updateUi() { if (m_currentReference.isValid()) { QString referenceText = tr("%1 %2 R").arg(m_currentReference.objectNumber).arg(m_currentReference.generation); if (m_isRootObject) { ui->referenceEdit->setText(referenceText); } else { ui->referenceEdit->setText(tr("Part of object %1").arg(referenceText)); } } else { ui->referenceEdit->setText(tr("")); } switch (m_currentObject.getType()) { case pdf::PDFObject::Type::Null: ui->typeEdit->setText(tr("Null")); break; case pdf::PDFObject::Type::Bool: ui->typeEdit->setText(tr("Bool")); break; case pdf::PDFObject::Type::Int: ui->typeEdit->setText(tr("Integer")); break; case pdf::PDFObject::Type::Real: ui->typeEdit->setText(tr("Real")); break; case pdf::PDFObject::Type::String: ui->typeEdit->setText(tr("String")); break; case pdf::PDFObject::Type::Name: ui->typeEdit->setText(tr("Name")); break; case pdf::PDFObject::Type::Array: ui->typeEdit->setText(tr("Array")); break; case pdf::PDFObject::Type::Dictionary: ui->typeEdit->setText(tr("Dictionary")); break; case pdf::PDFObject::Type::Stream: ui->typeEdit->setText(tr("Stream")); break; case pdf::PDFObject::Type::Reference: ui->typeEdit->setText(tr("Reference")); break; default: Q_ASSERT(false); break; } QLocale locale; switch (m_currentObject.getType()) { case pdf::PDFObject::Type::Null: ui->descriptionEdit->setText(tr("null")); break; case pdf::PDFObject::Type::Bool: ui->descriptionEdit->setText(m_currentObject.getBool() ? tr("true") : tr("false")); break; case pdf::PDFObject::Type::Int: ui->descriptionEdit->setText(locale.toString(m_currentObject.getInteger())); break; case pdf::PDFObject::Type::Real: ui->descriptionEdit->setText(locale.toString(m_currentObject.getReal())); break; case pdf::PDFObject::Type::String: ui->descriptionEdit->setText(QString("\"%1\"").arg(pdf::PDFEncoding::convertSmartFromByteStringToRepresentableQString(m_currentObject.getString()))); break; case pdf::PDFObject::Type::Name: ui->descriptionEdit->setText(QString("/%1").arg(QString::fromLatin1(m_currentObject.getString().toPercentEncoding(m_printableCharacters)))); break; case pdf::PDFObject::Type::Array: ui->descriptionEdit->setText(tr("Array [%1 items]").arg(locale.toString(m_currentObject.getArray()->getCount()))); break; case pdf::PDFObject::Type::Dictionary: ui->descriptionEdit->setText(tr("Dictionary [%1 items]").arg(locale.toString(m_currentObject.getDictionary()->getCount()))); break; case pdf::PDFObject::Type::Stream: ui->descriptionEdit->setText(tr("Stream [%1 items, %2 data bytes]").arg(locale.toString(m_currentObject.getStream()->getDictionary()->getCount()), locale.toString(m_currentObject.getStream()->getContent()->size()))); break; case pdf::PDFObject::Type::Reference: ui->descriptionEdit->setText(QString("%1 %2 R").arg(m_currentObject.getReference().objectNumber).arg(m_currentObject.getReference().generation)); break; default: Q_ASSERT(false); break; } if (m_currentObject.isStream()) { try { pdf::PDFDocumentDataLoaderDecorator loader(m_document); const pdf::PDFStream* stream = m_currentObject.getStream(); const pdf::PDFDictionary* dictionary = stream->getDictionary(); if (loader.readNameFromDictionary(dictionary, "Type") == "XObject" && loader.readNameFromDictionary(dictionary, "Subtype") == "Image") { pdf::PDFColorSpacePointer colorSpace; if (dictionary->hasKey("ColorSpace")) { const pdf::PDFObject& colorSpaceObject = m_document->getObject(dictionary->get("ColorSpace")); if (colorSpaceObject.isName() || colorSpaceObject.isArray()) { pdf::PDFDictionary dummyColorSpaceDictionary; colorSpace = pdf::PDFAbstractColorSpace::createColorSpace(&dummyColorSpaceDictionary, m_document, colorSpaceObject); } else if (!colorSpaceObject.isNull()) { throw pdf::PDFException(tr("Invalid color space of the image.")); } } pdf::PDFRenderErrorReporterDummy dummyErrorReporter; pdf::PDFImage pdfImage = pdf::PDFImage::createImage(m_document, stream, qMove(colorSpace), false, pdf::RenderingIntent::Perceptual, &dummyErrorReporter); QImage image = pdfImage.getImage(m_cms, &dummyErrorReporter, nullptr); ui->stackedWidget->setCurrentWidget(ui->imageBrowserPage); ui->imageBrowser->setPixmap(QPixmap::fromImage(image)); const int width = image.width(); const int height = image.height(); const int depth = loader.readIntegerFromDictionary(dictionary, "BitsPerComponent", 8); QString textDescription = tr("Image Stream [%1 items, %2 data bytes, %3 x %4 pixels, %5 bits per component]"); ui->descriptionEdit->setText(textDescription.arg(locale.toString(m_currentObject.getStream()->getDictionary()->getCount()), locale.toString(m_currentObject.getStream()->getContent()->size()), locale.toString(width), locale.toString(height), locale.toString(depth))); } else { QByteArray dataToBeAdjusted = m_document->getDecodedStream(stream); dataToBeAdjusted.replace('\r', ' '); QByteArray percentEncodedData = dataToBeAdjusted.toPercentEncoding(m_printableCharacters); ui->contentTextBrowser->setText(QString::fromLatin1(percentEncodedData)); ui->stackedWidget->setCurrentWidget(ui->contentTextBrowserPage); } } catch (const pdf::PDFException &exception) { ui->contentTextBrowser->setText(exception.getMessage()); ui->stackedWidget->setCurrentWidget(ui->contentTextBrowserPage); } } else { QByteArray serializedObject = pdf::PDFDocumentWriter::getSerializedObject(m_currentObject); QByteArray percentEncodedData = serializedObject.toPercentEncoding(m_printableCharacters); ui->contentTextBrowser->setText(QString::fromLatin1(percentEncodedData)); ui->stackedWidget->setCurrentWidget(ui->contentTextBrowserPage); } } void ObjectViewerWidget::updatePinnedUi() { ui->pinButton->setEnabled(!m_isPinned); ui->unpinButton->setEnabled(m_isPinned); } const pdf::PDFCMS* ObjectViewerWidget::getCms() const { return m_cms; } void ObjectViewerWidget::setCms(const pdf::PDFCMS* cms) { m_cms = cms; } QString ObjectViewerWidget::getTitleText() const { if (!m_currentReference.isValid()) { return tr("[Unknown]"); } QString referenceString = tr("%1 %2 R").arg(m_currentReference.objectNumber).arg(m_currentReference.generation); if (m_isRootObject) { return referenceString; } else { return tr("%1 (part)").arg(referenceString); } } const pdf::PDFDocument* ObjectViewerWidget::getDocument() const { return m_document; } void ObjectViewerWidget::setDocument(const pdf::PDFDocument* document) { m_document = document; } } // namespace pdfplugin