diff --git a/PdfForQtLib/PdfForQtLib.pro b/PdfForQtLib/PdfForQtLib.pro
index 3ec0d34..80e8095 100644
--- a/PdfForQtLib/PdfForQtLib.pro
+++ b/PdfForQtLib/PdfForQtLib.pro
@@ -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
diff --git a/PdfForQtLib/sources/pdfcatalog.h b/PdfForQtLib/sources/pdfcatalog.h
index a799616..d559a5b 100644
--- a/PdfForQtLib/sources/pdfcatalog.h
+++ b/PdfForQtLib/sources/pdfcatalog.h
@@ -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);
diff --git a/PdfForQtLib/sources/pdfdocument.h b/PdfForQtLib/sources/pdfdocument.h
index a82922e..8b5c820 100644
--- a/PdfForQtLib/sources/pdfdocument.h
+++ b/PdfForQtLib/sources/pdfdocument.h
@@ -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;
diff --git a/PdfForQtLib/sources/pdfdrawspacecontroller.cpp b/PdfForQtLib/sources/pdfdrawspacecontroller.cpp
new file mode 100644
index 0000000..c74b931
--- /dev/null
+++ b/PdfForQtLib/sources/pdfdrawspacecontroller.cpp
@@ -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 .
+
+
+#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(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::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& 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 pageIndices(pageCount, INVALID_PAGE_INDEX);
+ std::iota(pageIndices.begin(), pageIndices.end(), static_cast(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 pageIndices(pageCount + 1, INVALID_PAGE_INDEX);
+ std::iota(std::next(pageIndices.begin()), pageIndices.end(), static_cast(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 pageIndices(pageCount, INVALID_PAGE_INDEX);
+ std::iota(pageIndices.begin(), pageIndices.end(), static_cast(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 pageIndices(pageCount + 1, INVALID_PAGE_INDEX);
+ std::iota(std::next(pageIndices.begin()), pageIndices.end(), static_cast(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
diff --git a/PdfForQtLib/sources/pdfdrawspacecontroller.h b/PdfForQtLib/sources/pdfdrawspacecontroller.h
new file mode 100644
index 0000000..998d82d
--- /dev/null
+++ b/PdfForQtLib/sources/pdfdrawspacecontroller.h
@@ -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 .
+
+#ifndef PDFDRAWSPACECONTROLLER_H
+#define PDFDRAWSPACECONTROLLER_H
+
+#include "pdfdocument.h"
+
+#include
+#include
+#include
+
+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;
+
+ /// 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;
+
+ const PDFDocument* m_document;
+
+ PageLayout m_pageLayoutMode;
+ LayoutItems m_layoutItems;
+ BlockItems m_blockItems;
+ PDFReal m_verticalSpacingMM;
+ PDFReal m_horizontalSpacingMM;
+};
+
+} // namespace pdf
+
+#endif // PDFDRAWSPACECONTROLLER_H
diff --git a/PdfForQtLib/sources/pdfglobal.h b/PdfForQtLib/sources/pdfglobal.h
index 272a688..0b6667d 100644
--- a/PdfForQtLib/sources/pdfglobal.h
+++ b/PdfForQtLib/sources/pdfglobal.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
diff --git a/PdfForQtLib/sources/pdfpage.cpp b/PdfForQtLib/sources/pdfpage.cpp
index 7330dd1..113d21e 100644
--- a/PdfForQtLib/sources/pdfpage.cpp
+++ b/PdfForQtLib/sources/pdfpage.cpp
@@ -108,6 +108,31 @@ std::vector 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& pages,
std::set& visitedReferences,
const PDFPageInheritableAttributes& templateAttributes,
@@ -165,7 +190,7 @@ void PDFPage::parseImpl(std::vector& 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())
diff --git a/PdfForQtLib/sources/pdfpage.h b/PdfForQtLib/sources/pdfpage.h
index a919270..59c64e2 100644
--- a/PdfForQtLib/sources/pdfpage.h
+++ b/PdfForQtLib/sources/pdfpage.h
@@ -76,14 +76,24 @@ public:
/// \param root Root object of page tree
static std::vector 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.
diff --git a/PdfForQtLib/sources/pdfstreamfilters.h b/PdfForQtLib/sources/pdfstreamfilters.h
index 9438b32..f5747bb 100644
--- a/PdfForQtLib/sources/pdfstreamfilters.h
+++ b/PdfForQtLib/sources/pdfstreamfilters.h
@@ -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;
diff --git a/PdfForQtViewer/pdfviewermainwindow.cpp b/PdfForQtViewer/pdfviewermainwindow.cpp
index 15850a8..509d35e 100644
--- a/PdfForQtViewer/pdfviewermainwindow.cpp
+++ b/PdfForQtViewer/pdfviewermainwindow.cpp
@@ -3,6 +3,7 @@
#include "pdfdocumentreader.h"
#include "pdfvisitor.h"
+#include "pdfstreamfilters.h"
#include
#include
@@ -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());
+ }
}
}
diff --git a/UnitTests/tst_lexicalanalyzertest.cpp b/UnitTests/tst_lexicalanalyzertest.cpp
index db65659..6ebb693 100644
--- a/UnitTests/tst_lexicalanalyzertest.cpp
+++ b/UnitTests/tst_lexicalanalyzertest.cpp
@@ -22,6 +22,7 @@
#include "pdfparser.h"
#include "pdfconstants.h"
#include "pdfflatmap.h"
+#include "pdfstreamfilters.h"
#include
@@ -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));