mirror of https://github.com/JakubMelka/PDF4QT.git
Draw space controller
This commit is contained in:
parent
a9292a4c02
commit
7631265ba4
|
@ -45,7 +45,8 @@ SOURCES += \
|
|||
sources/pdfencoding.cpp \
|
||||
sources/pdfcatalog.cpp \
|
||||
sources/pdfpage.cpp \
|
||||
sources/pdfstreamfilters.cpp
|
||||
sources/pdfstreamfilters.cpp \
|
||||
sources/pdfdrawspacecontroller.cpp
|
||||
|
||||
HEADERS += \
|
||||
sources/pdfobject.h \
|
||||
|
@ -61,7 +62,8 @@ HEADERS += \
|
|||
sources/pdfcatalog.h \
|
||||
sources/pdfnumbertreeloader.h \
|
||||
sources/pdfpage.h \
|
||||
sources/pdfstreamfilters.h
|
||||
sources/pdfstreamfilters.h \
|
||||
sources/pdfdrawspacecontroller.h
|
||||
|
||||
unix {
|
||||
target.path = /usr/lib
|
||||
|
|
|
@ -196,6 +196,12 @@ public:
|
|||
/// Returns viewer preferences of the application
|
||||
const PDFViewerPreferences* getViewerPreferences() const { return &m_viewerPreferences; }
|
||||
|
||||
/// Returns the page count
|
||||
size_t getPageCount() const { return m_pages.size(); }
|
||||
|
||||
/// Returns the page
|
||||
const PDFPage* getPage(size_t index) const { return &m_pages.at(index); }
|
||||
|
||||
/// Parses catalog from catalog dictionary. If object cannot be parsed, or error occurs,
|
||||
/// then exception is thrown.
|
||||
static PDFCatalog parse(const PDFObject& catalog, const PDFDocument* document);
|
||||
|
|
|
@ -173,6 +173,9 @@ public:
|
|||
/// is returned (no exception is thrown).
|
||||
const PDFObject& getObject(const PDFObject& object) const;
|
||||
|
||||
/// Returns the document catalog
|
||||
const PDFCatalog* getCatalog() const { return &m_catalog; }
|
||||
|
||||
private:
|
||||
friend class PDFDocumentReader;
|
||||
|
||||
|
|
|
@ -0,0 +1,272 @@
|
|||
// Copyright (C) 2019 Jakub Melka
|
||||
//
|
||||
// This file is part of PdfForQt.
|
||||
//
|
||||
// PdfForQt 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
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// PdfForQt 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 PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#include "pdfdrawspacecontroller.h"
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
PDFDrawSpaceController::PDFDrawSpaceController(QObject* parent) :
|
||||
QObject(parent),
|
||||
m_document(nullptr),
|
||||
m_pageLayoutMode(PageLayout::SinglePage),
|
||||
m_verticalSpacingMM(5.0),
|
||||
m_horizontalSpacingMM(1.0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PDFDrawSpaceController::recalculate()
|
||||
{
|
||||
if (!m_document)
|
||||
{
|
||||
clear(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const PDFCatalog* catalog = m_document->getCatalog();
|
||||
size_t pageCount = catalog->getPageCount();
|
||||
|
||||
// First, preserve page rotations. We assume the count of pages is the same as the document.
|
||||
// Document should not be changed while viewing. If a new document is setted, then the draw
|
||||
// space is cleared first.
|
||||
std::vector<PageRotation> pageRotation(pageCount, PageRotation::None);
|
||||
for (size_t i = 0; i < pageCount; ++i)
|
||||
{
|
||||
pageRotation[i] = catalog->getPage(i)->getPageRotation();
|
||||
}
|
||||
for (const LayoutItem& layoutItem : m_layoutItems)
|
||||
{
|
||||
pageRotation[layoutItem.pageIndex] = layoutItem.pageRotation;
|
||||
}
|
||||
|
||||
static constexpr size_t INVALID_PAGE_INDEX = std::numeric_limits<size_t>::max();
|
||||
|
||||
// Places the pages on the left/right sides. Pages can be nullptr, but not both of them.
|
||||
// Updates bounding rectangle.
|
||||
auto placePagesLeftRight = [this, catalog, &pageRotation](PDFInteger blockIndex, size_t leftIndex, size_t rightIndex, PDFReal& yPos, QRectF& boundingRect)
|
||||
{
|
||||
PDFReal yPosAdvance = 0.0;
|
||||
|
||||
if (leftIndex != INVALID_PAGE_INDEX)
|
||||
{
|
||||
QSizeF pageSize = PDFPage::getRotatedBox(catalog->getPage(leftIndex)->getMediaBoxMM(), pageRotation[leftIndex]).size();
|
||||
PDFReal xPos = -pageSize.width() - m_horizontalSpacingMM * 0.5;
|
||||
QRectF rect(xPos, yPos, pageSize.width(), pageSize.height());
|
||||
m_layoutItems.emplace_back(blockIndex, leftIndex, pageRotation[leftIndex], rect);
|
||||
yPosAdvance = qMax(yPosAdvance, pageSize.height());
|
||||
boundingRect = boundingRect.united(rect);
|
||||
}
|
||||
|
||||
if (rightIndex != INVALID_PAGE_INDEX)
|
||||
{
|
||||
QSizeF pageSize = PDFPage::getRotatedBox(catalog->getPage(rightIndex)->getMediaBoxMM(), pageRotation[rightIndex]).size();
|
||||
PDFReal xPos = m_horizontalSpacingMM * 0.5;
|
||||
QRectF rect(xPos, yPos, pageSize.width(), pageSize.height());
|
||||
m_layoutItems.emplace_back(blockIndex, rightIndex, pageRotation[rightIndex], rect);
|
||||
yPosAdvance = qMax(yPosAdvance, pageSize.height());
|
||||
boundingRect = boundingRect.united(rect);
|
||||
}
|
||||
|
||||
if (yPosAdvance > 0.0)
|
||||
{
|
||||
yPos += yPosAdvance + m_verticalSpacingMM;
|
||||
}
|
||||
};
|
||||
|
||||
// Generates block with pages using page indices. If generateBlocks is true, then
|
||||
// for each pair of pages, single block is generated, otherwise block containing all
|
||||
// pages is generated.
|
||||
auto placePagesLeftRightByIndices = [this, &placePagesLeftRight](const std::vector<size_t>& indices, bool generateBlocks)
|
||||
{
|
||||
Q_ASSERT(indices.size() % 2 == 0);
|
||||
|
||||
PDFReal yPos = 0.0;
|
||||
PDFInteger blockIndex = 0;
|
||||
QRectF boundingRectangle;
|
||||
|
||||
size_t count = indices.size() / 2;
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
const size_t leftPageIndex = indices[2 * i];
|
||||
const size_t rightPageIndex = indices[2 * i + 1];
|
||||
placePagesLeftRight(blockIndex, leftPageIndex, rightPageIndex, yPos, boundingRectangle);
|
||||
|
||||
if (generateBlocks)
|
||||
{
|
||||
m_blockItems.emplace_back(boundingRectangle);
|
||||
|
||||
// Clear the old data
|
||||
yPos = 0.0;
|
||||
++blockIndex;
|
||||
boundingRectangle = QRectF();
|
||||
}
|
||||
}
|
||||
|
||||
if (!generateBlocks)
|
||||
{
|
||||
// Generate single block for all layed out pages
|
||||
m_blockItems.emplace_back(boundingRectangle);
|
||||
}
|
||||
};
|
||||
|
||||
switch (m_pageLayoutMode)
|
||||
{
|
||||
case PageLayout::SinglePage:
|
||||
{
|
||||
// Each block contains single page
|
||||
m_layoutItems.reserve(pageCount);
|
||||
m_blockItems.reserve(pageCount);
|
||||
|
||||
// Pages can have different size, so we center them around the center.
|
||||
// Block size will equal to the page size.
|
||||
|
||||
for (size_t i = 0; i < pageCount; ++i)
|
||||
{
|
||||
QSizeF pageSize = PDFPage::getRotatedBox(catalog->getPage(i)->getMediaBoxMM(), pageRotation[i]).size();
|
||||
QRectF rect(-pageSize.width() * 0.5, -pageSize.height() * 0.5, pageSize.width(), pageSize.height());
|
||||
m_layoutItems.emplace_back(i, i, pageRotation[i], rect);
|
||||
m_blockItems.emplace_back(rect);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PageLayout::OneColumn:
|
||||
{
|
||||
// Single block, one column
|
||||
m_layoutItems.reserve(pageCount);
|
||||
m_blockItems.reserve(1);
|
||||
|
||||
PDFReal yPos = 0.0;
|
||||
QRectF boundingRectangle;
|
||||
|
||||
for (size_t i = 0; i < pageCount; ++i)
|
||||
{
|
||||
// Top of current page is at yPos.
|
||||
QSizeF pageSize = PDFPage::getRotatedBox(catalog->getPage(i)->getMediaBoxMM(), pageRotation[i]).size();
|
||||
QRectF rect(-pageSize.width() * 0.5, yPos, pageSize.width(), pageSize.height());
|
||||
m_layoutItems.emplace_back(0, i, pageRotation[i], rect);
|
||||
yPos += pageSize.height() + m_verticalSpacingMM;
|
||||
boundingRectangle = boundingRectangle.united(rect);
|
||||
}
|
||||
|
||||
// Insert the single block with union of bounding rectangles
|
||||
m_blockItems.emplace_back(boundingRectangle);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PageLayout::TwoColumnLeft:
|
||||
{
|
||||
// Pages with number 1, 3, 5, ... are on the left, 2, 4, 6 are on the right.
|
||||
// Page indices are numbered from 0, so pages 0, 2, 4 will be on the left,
|
||||
// 1, 3, 5 will be on the right.
|
||||
// For purposes or paging, "left" pages will be on the left side of y axis (negative x axis),
|
||||
// the "right" pages will be on the right side of y axis (positive x axis).
|
||||
|
||||
m_layoutItems.reserve(pageCount);
|
||||
m_blockItems.reserve(1);
|
||||
|
||||
std::vector<size_t> pageIndices(pageCount, INVALID_PAGE_INDEX);
|
||||
std::iota(pageIndices.begin(), pageIndices.end(), static_cast<size_t>(0));
|
||||
|
||||
if (pageIndices.size() % 2 == 1)
|
||||
{
|
||||
pageIndices.push_back(INVALID_PAGE_INDEX);
|
||||
}
|
||||
|
||||
placePagesLeftRightByIndices(pageIndices, false);
|
||||
break;
|
||||
}
|
||||
|
||||
case PageLayout::TwoColumnRight:
|
||||
{
|
||||
// Similar to previous case, but page sequence start on the right.
|
||||
|
||||
m_layoutItems.reserve(pageCount);
|
||||
m_blockItems.reserve(1);
|
||||
|
||||
std::vector<size_t> pageIndices(pageCount + 1, INVALID_PAGE_INDEX);
|
||||
std::iota(std::next(pageIndices.begin()), pageIndices.end(), static_cast<size_t>(0));
|
||||
|
||||
if (pageIndices.size() % 2 == 1)
|
||||
{
|
||||
pageIndices.push_back(INVALID_PAGE_INDEX);
|
||||
}
|
||||
|
||||
placePagesLeftRightByIndices(pageIndices, false);
|
||||
break;
|
||||
}
|
||||
|
||||
case PageLayout::TwoPagesLeft:
|
||||
{
|
||||
m_layoutItems.reserve(pageCount);
|
||||
m_blockItems.reserve((pageCount / 2) + (pageCount % 2));
|
||||
|
||||
std::vector<size_t> pageIndices(pageCount, INVALID_PAGE_INDEX);
|
||||
std::iota(pageIndices.begin(), pageIndices.end(), static_cast<size_t>(0));
|
||||
|
||||
if (pageIndices.size() % 2 == 1)
|
||||
{
|
||||
pageIndices.push_back(INVALID_PAGE_INDEX);
|
||||
}
|
||||
|
||||
placePagesLeftRightByIndices(pageIndices, true);
|
||||
break;
|
||||
}
|
||||
|
||||
case PageLayout::TwoPagesRight:
|
||||
{
|
||||
m_layoutItems.reserve(pageCount);
|
||||
m_blockItems.reserve((pageCount / 2) + (pageCount % 2));
|
||||
|
||||
std::vector<size_t> pageIndices(pageCount + 1, INVALID_PAGE_INDEX);
|
||||
std::iota(std::next(pageIndices.begin()), pageIndices.end(), static_cast<size_t>(0));
|
||||
|
||||
if (pageIndices.size() % 2 == 1)
|
||||
{
|
||||
pageIndices.push_back(INVALID_PAGE_INDEX);
|
||||
}
|
||||
|
||||
placePagesLeftRightByIndices(pageIndices, true);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
emit drawSpaceChanged();
|
||||
}
|
||||
|
||||
void PDFDrawSpaceController::clear(bool emitSignal)
|
||||
{
|
||||
m_layoutItems.clear();
|
||||
m_blockItems.clear();
|
||||
|
||||
if (emitSignal)
|
||||
{
|
||||
emit drawSpaceChanged();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace pdf
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright (C) 2019 Jakub Melka
|
||||
//
|
||||
// This file is part of PdfForQt.
|
||||
//
|
||||
// PdfForQt 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
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// PdfForQt 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 PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef PDFDRAWSPACECONTROLLER_H
|
||||
#define PDFDRAWSPACECONTROLLER_H
|
||||
|
||||
#include "pdfdocument.h"
|
||||
|
||||
#include <QRectF>
|
||||
#include <QObject>
|
||||
#include <QMarginsF>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
/// This class controls draw space - page layout. Pages are divided into blocks
|
||||
/// each block can contain one or multiple pages. Units are in milimeters.
|
||||
/// Pages are layouted in zoom-independent mode.
|
||||
class PDFDrawSpaceController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PDFDrawSpaceController(QObject* parent);
|
||||
|
||||
signals:
|
||||
void drawSpaceChanged();
|
||||
|
||||
private:
|
||||
/// Recalculates the draw space. Preserves setted page rotation.
|
||||
void recalculate();
|
||||
|
||||
/// Clears the draw space. Emits signal if desired.
|
||||
void clear(bool emitSignal);
|
||||
|
||||
/// Represents layouted page. This structure contains index of the block, index of the
|
||||
/// page and page rectangle, in which the page is contained.
|
||||
struct LayoutItem
|
||||
{
|
||||
constexpr inline explicit LayoutItem() : blockIndex(-1), pageIndex(-1), pageRotation(PageRotation::None) { }
|
||||
constexpr inline explicit LayoutItem(PDFInteger blockIndex, PDFInteger pageIndex, PageRotation rotation, const QRectF& pageRectMM) :
|
||||
blockIndex(blockIndex), pageIndex(pageIndex), pageRotation(rotation), pageRectMM(pageRectMM) { }
|
||||
|
||||
PDFInteger blockIndex;
|
||||
PDFInteger pageIndex;
|
||||
PageRotation pageRotation;
|
||||
QRectF pageRectMM;
|
||||
};
|
||||
|
||||
using LayoutItems = std::vector<LayoutItem>;
|
||||
|
||||
/// Represents data for the single block. Contains block size in milimeters.
|
||||
struct LayoutBlock
|
||||
{
|
||||
constexpr inline explicit LayoutBlock() = default;
|
||||
constexpr inline explicit LayoutBlock(const QRectF& blockRectMM) : blockRectMM(blockRectMM) { }
|
||||
|
||||
QRectF blockRectMM;
|
||||
};
|
||||
|
||||
using BlockItems = std::vector<LayoutBlock>;
|
||||
|
||||
const PDFDocument* m_document;
|
||||
|
||||
PageLayout m_pageLayoutMode;
|
||||
LayoutItems m_layoutItems;
|
||||
BlockItems m_blockItems;
|
||||
PDFReal m_verticalSpacingMM;
|
||||
PDFReal m_horizontalSpacingMM;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFDRAWSPACECONTROLLER_H
|
|
@ -104,6 +104,15 @@ struct PDFTranslationContext
|
|||
Q_DECLARE_TR_FUNCTIONS(pdf::PDFTranslationContext)
|
||||
};
|
||||
|
||||
constexpr PDFReal PDF_POINT_TO_INCH = 1.0 / 72.0;
|
||||
constexpr PDFReal PDF_INT_TO_MM = 25.4;
|
||||
constexpr PDFReal PDF_POINT_TO_MM = PDF_POINT_TO_INCH * PDF_INT_TO_MM;
|
||||
|
||||
constexpr PDFReal convertPDFPointToMM(PDFReal point)
|
||||
{
|
||||
return point * PDF_POINT_TO_MM;
|
||||
}
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFGLOBAL_H
|
||||
|
|
|
@ -108,6 +108,31 @@ std::vector<PDFPage> PDFPage::parse(const PDFDocument* document, const PDFObject
|
|||
return result;
|
||||
}
|
||||
|
||||
QRectF PDFPage::getRectMM(const QRectF& rect) const
|
||||
{
|
||||
return QRectF(convertPDFPointToMM(rect.left()),
|
||||
convertPDFPointToMM(rect.top()),
|
||||
convertPDFPointToMM(rect.width()),
|
||||
convertPDFPointToMM(rect.height()));
|
||||
}
|
||||
|
||||
QRectF PDFPage::getRotatedBox(const QRectF& rect, PageRotation rotation)
|
||||
{
|
||||
switch (rotation)
|
||||
{
|
||||
case PageRotation::None:
|
||||
case PageRotation::Rotate180:
|
||||
// Preserve rotation
|
||||
break;
|
||||
|
||||
case PageRotation::Rotate90:
|
||||
case PageRotation::Rotate270:
|
||||
return rect.transposed();
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
void PDFPage::parseImpl(std::vector<PDFPage>& pages,
|
||||
std::set<PDFObjectReference>& visitedReferences,
|
||||
const PDFPageInheritableAttributes& templateAttributes,
|
||||
|
@ -165,7 +190,7 @@ void PDFPage::parseImpl(std::vector<PDFPage>& pages,
|
|||
|
||||
page.m_mediaBox = currentInheritableAttributes.getMediaBox();
|
||||
page.m_cropBox = currentInheritableAttributes.getCropBox();
|
||||
page.m_resources = currentInheritableAttributes.getResources();
|
||||
page.m_resources = document->getObject(currentInheritableAttributes.getResources());
|
||||
page.m_pageRotation = currentInheritableAttributes.getPageRotation();
|
||||
|
||||
if (!page.m_cropBox.isValid())
|
||||
|
|
|
@ -76,14 +76,24 @@ public:
|
|||
/// \param root Root object of page tree
|
||||
static std::vector<PDFPage> parse(const PDFDocument* document, const PDFObject& root);
|
||||
|
||||
const QRectF& getMediaBox() const { return m_mediaBox; }
|
||||
const QRectF& getCropBox() const { return m_cropBox; }
|
||||
const QRectF& getBleedBox() const { return m_bleedBox; }
|
||||
const QRectF& getTrimBox() const { return m_trimBox; }
|
||||
const QRectF& getArtBox() const { return m_artBox; }
|
||||
PageRotation getPageRotation() const { return m_pageRotation; }
|
||||
const PDFObject& getResources() const { return m_resources; }
|
||||
const PDFObject& getContents() const { return m_contents; }
|
||||
inline const QRectF& getMediaBox() const { return m_mediaBox; }
|
||||
inline const QRectF& getCropBox() const { return m_cropBox; }
|
||||
inline const QRectF& getBleedBox() const { return m_bleedBox; }
|
||||
inline const QRectF& getTrimBox() const { return m_trimBox; }
|
||||
inline const QRectF& getArtBox() const { return m_artBox; }
|
||||
inline PageRotation getPageRotation() const { return m_pageRotation; }
|
||||
inline const PDFObject& getResources() const { return m_resources; }
|
||||
inline const PDFObject& getContents() const { return m_contents; }
|
||||
|
||||
QRectF getRectMM(const QRectF& rect) const;
|
||||
|
||||
inline QRectF getMediaBoxMM() const { return getRectMM(m_mediaBox); }
|
||||
inline QRectF getCropBoxMM() const { return getRectMM(m_cropBox); }
|
||||
inline QRectF getBleedBoxMM() const { return getRectMM(m_bleedBox); }
|
||||
inline QRectF getTrimBoxMM() const { return getRectMM(m_trimBox); }
|
||||
inline QRectF getArtBoxMM() const { return getRectMM(m_artBox); }
|
||||
|
||||
static QRectF getRotatedBox(const QRectF& rect, PageRotation rotation);
|
||||
|
||||
private:
|
||||
/// Parses the page tree (implementation). If error occurs, then exception is thrown.
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace pdf
|
|||
{
|
||||
class PDFDocument;
|
||||
|
||||
class PDFStreamFilter
|
||||
class PDFFORQTLIBSHARED_EXPORT PDFStreamFilter
|
||||
{
|
||||
public:
|
||||
explicit PDFStreamFilter() = default;
|
||||
|
@ -35,7 +35,7 @@ public:
|
|||
virtual QByteArray apply(const QByteArray& data, const PDFDocument* document, const PDFObject& parameters) const = 0;
|
||||
};
|
||||
|
||||
class PDFAsciiHexDecodeFilter : public PDFStreamFilter
|
||||
class PDFFORQTLIBSHARED_EXPORT PDFAsciiHexDecodeFilter : public PDFStreamFilter
|
||||
{
|
||||
public:
|
||||
explicit PDFAsciiHexDecodeFilter() = default;
|
||||
|
@ -44,7 +44,7 @@ public:
|
|||
virtual QByteArray apply(const QByteArray& data, const PDFDocument* document, const PDFObject& parameters) const override;
|
||||
};
|
||||
|
||||
class PDFAscii85DecodeFilter : public PDFStreamFilter
|
||||
class PDFFORQTLIBSHARED_EXPORT PDFAscii85DecodeFilter : public PDFStreamFilter
|
||||
{
|
||||
public:
|
||||
explicit PDFAscii85DecodeFilter() = default;
|
||||
|
@ -53,7 +53,7 @@ public:
|
|||
virtual QByteArray apply(const QByteArray& data, const PDFDocument* document, const PDFObject& parameters) const override;
|
||||
};
|
||||
|
||||
class PDFLzwDecodeFilter : public PDFStreamFilter
|
||||
class PDFFORQTLIBSHARED_EXPORT PDFLzwDecodeFilter : public PDFStreamFilter
|
||||
{
|
||||
public:
|
||||
explicit PDFLzwDecodeFilter() = default;
|
||||
|
@ -62,7 +62,7 @@ public:
|
|||
virtual QByteArray apply(const QByteArray& data, const PDFDocument* document, const PDFObject& parameters) const override;
|
||||
};
|
||||
|
||||
class PDFFlateDecodeFilter : public PDFStreamFilter
|
||||
class PDFFORQTLIBSHARED_EXPORT PDFFlateDecodeFilter : public PDFStreamFilter
|
||||
{
|
||||
public:
|
||||
explicit PDFFlateDecodeFilter() = default;
|
||||
|
@ -71,7 +71,7 @@ public:
|
|||
virtual QByteArray apply(const QByteArray& data, const PDFDocument* document, const PDFObject& parameters) const override;
|
||||
};
|
||||
|
||||
class PDFRunLengthDecodeFilter : public PDFStreamFilter
|
||||
class PDFFORQTLIBSHARED_EXPORT PDFRunLengthDecodeFilter : public PDFStreamFilter
|
||||
{
|
||||
public:
|
||||
explicit PDFRunLengthDecodeFilter() = default;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "pdfdocumentreader.h"
|
||||
#include "pdfvisitor.h"
|
||||
#include "pdfstreamfilters.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
@ -42,6 +43,18 @@ void PDFViewerMainWindow::onActionOpenTriggered()
|
|||
{
|
||||
QMessageBox::information(this, tr("PDF Reader"), tr("Document read error: %1").arg(reader.getErrorMessage()));
|
||||
}
|
||||
|
||||
const pdf::PDFCatalog* catalog = document.getCatalog();
|
||||
const pdf::PDFPage* page = catalog->getPage(0);
|
||||
const pdf::PDFObject& contents = page->getContents();
|
||||
|
||||
if (contents.isStream())
|
||||
{
|
||||
const pdf::PDFStream* stream = contents.getStream();
|
||||
const QByteArray* compressed = stream->getContent();
|
||||
pdf::PDFFlateDecodeFilter fd;
|
||||
QByteArray uncompressed = fd.apply(*compressed, &document, pdf::PDFObject());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "pdfparser.h"
|
||||
#include "pdfconstants.h"
|
||||
#include "pdfflatmap.h"
|
||||
#include "pdfstreamfilters.h"
|
||||
|
||||
#include <regex>
|
||||
|
||||
|
@ -44,6 +45,7 @@ private slots:
|
|||
void test_invalid_input();
|
||||
void test_header_regexp();
|
||||
void test_flat_map();
|
||||
void test_lzw_filter();
|
||||
|
||||
private:
|
||||
void scanWholeStream(const char* stream);
|
||||
|
@ -295,6 +297,17 @@ void LexicalAnalyzerTest::test_flat_map()
|
|||
}
|
||||
}
|
||||
|
||||
void LexicalAnalyzerTest::test_lzw_filter()
|
||||
{
|
||||
// This example is from PDF 1.7 Reference
|
||||
QByteArray byteArray = QByteArray::fromHex("800B6050220C0C8501");
|
||||
pdf::PDFLzwDecodeFilter filter;
|
||||
QByteArray decoded = filter.apply(byteArray, nullptr, pdf::PDFObject());
|
||||
QByteArray valid = "-----A---B";
|
||||
|
||||
QCOMPARE(decoded, valid);
|
||||
}
|
||||
|
||||
void LexicalAnalyzerTest::scanWholeStream(const char* stream)
|
||||
{
|
||||
pdf::PDFLexicalAnalyzer analyzer(stream, stream + strlen(stream));
|
||||
|
|
Loading…
Reference in New Issue