Commit cdbb9797 authored by Volker Krause's avatar Volker Krause
Browse files

Add a hashable opaque reference type for addressing PDF images

This replaces the direct use of PDF ref/gen number pairs (or just the
ref number) with something that can eventually also distinguish sub-
elements of an image, such as masks.
parent 60b80d79
......@@ -6,6 +6,8 @@
#pragma once
#include "pdfimage.h"
#include <config-kitinerary.h>
#include <QImage>
......@@ -21,7 +23,6 @@ class PDFDoc;
namespace KItinerary {
class PdfDocumentPrivate;
class PdfImage;
class PdfLink;
class PdfPage;
......@@ -45,7 +46,7 @@ public:
// and is referenced by the object id from PdfImage to avoid
// expensive loading/decoding of multiple occurrences of the same image
// image data in here is stored in its source form, without applied transformations
std::unordered_map<int, QImage> m_imageData;
std::unordered_map<PdfImageRef, QImage> m_imageData;
std::vector<PdfPage> m_pages;
std::unique_ptr<PDFDoc> m_popplerDoc;
};
......
......@@ -46,8 +46,7 @@ void PdfExtractorOutputDevice::drawImage(GfxState* state, Object* ref, Stream* s
}
PdfImage pdfImg;
pdfImg.d->m_refNum = ref->getRef().num;
pdfImg.d->m_refGen = ref->getRef().gen;
pdfImg.d->m_ref = PdfImageRef(ref->getRef().num, ref->getRef().gen);
#if KPOPPLER_VERSION >= QT_VERSION_CHECK(0, 69, 0)
pdfImg.d->m_colorMap.reset(colorMap->copy());
......
......@@ -60,7 +60,7 @@ void ImageLoaderOutputDevice::drawImage(GfxState *state, Object *ref, Stream *st
return;
}
if (ref->isRef() && d->m_refNum != ref->getRef().num) {
if (ref->isRef() && d->refNum() != ref->getRef().num) {
return;
}
......@@ -122,13 +122,13 @@ QImage PdfImagePrivate::load(Stream* str, GfxImageColorMap* colorMap)
}
imgStream->close();
m_page->m_doc->m_imageData[m_refNum] = img;
m_page->m_doc->m_imageData[m_ref] = img;
return img;
}
QImage PdfImagePrivate::load()
{
const auto it = m_page->m_doc->m_imageData.find(m_refNum);
const auto it = m_page->m_doc->m_imageData.find(m_ref);
if (it != m_page->m_doc->m_imageData.end()) {
return (*it).second;
}
......@@ -137,7 +137,7 @@ QImage PdfImagePrivate::load()
#if KPOPPLER_VERSION >= QT_VERSION_CHECK(0, 69, 0)
const auto xref = m_page->m_doc->m_popplerDoc->getXRef();
const auto obj = xref->fetch(m_refNum, m_refGen);
const auto obj = xref->fetch(refNum(), refGen());
return load(obj.getStream(), m_colorMap.get());
#else
std::unique_ptr<ImageLoaderOutputDevice> device(new ImageLoaderOutputDevice(this));
......@@ -207,12 +207,12 @@ QImage PdfImage::image() const
bool PdfImage::hasObjectId() const
{
return d->m_refNum >= 0;
return !d->m_ref.isNull();
}
int PdfImage::objectId() const
PdfImageRef PdfImage::objectId() const
{
return d->m_refNum;
return d->m_ref;
}
bool PdfImage::isVectorImage() const
......
......@@ -11,12 +11,61 @@
#include <QExplicitlySharedDataPointer>
#include <QMetaType>
#include <functional>
class QImage;
class QTransform;
namespace KItinerary {
class PdfImagePrivate;
class PdfImageRef;
}
namespace std {
template<>
struct hash<KItinerary::PdfImageRef>
{
inline std::size_t operator()(const KItinerary::PdfImageRef &ref) const noexcept;
};
}
namespace KItinerary {
/** PDF image element type. */
enum class PdfImageType {
Image,
Mask,
SMask
};
/** PDF object reference for an image, with the ability to address attached masks as well. */
class PdfImageRef
{
public:
constexpr PdfImageRef() = default;
constexpr inline PdfImageRef(int num, int gen, PdfImageType type = PdfImageType::Image)
: m_refNum(num)
, m_refGen(gen)
, m_type(type)
{}
constexpr inline bool isNull() const
{
return m_refNum >= 0;
}
constexpr inline bool operator==(const PdfImageRef &other) const
{
return m_refNum == other.m_refNum && m_refGen == other.m_refGen && m_type == other.m_type;
}
private:
int m_refNum = -1;
int m_refGen = -1;
PdfImageType m_type = PdfImageType::Image;
friend class PdfImagePrivate;
friend std::size_t std::hash<PdfImageRef>::operator ()(const PdfImageRef&) const noexcept;
};
/** An image in a PDF document.
*/
......@@ -69,7 +118,7 @@ public:
* Use this to detect multiple occurrences of the same image in different
* places, if that reduces e.g. computation cost.
*/
int objectId() const;
PdfImageRef objectId() const;
/** Returns whether this is a raster or vector image. */
bool isVectorImage() const;
......@@ -92,3 +141,8 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(PdfImage::LoadingHints)
Q_DECLARE_METATYPE(KItinerary::PdfImage)
std::size_t std::hash<KItinerary::PdfImageRef>::operator()(const KItinerary::PdfImageRef &ref) const noexcept
{
// first part is how poppler hashes its Ref type
return std::hash<int>{}(ref.m_refNum) ^ (std::hash<int>{}(ref.m_refGen) << 1) ^ std::hash<int>{}((int)ref.m_type);
}
......@@ -28,12 +28,14 @@ public:
QImage load(Stream *str, GfxImageColorMap *colorMap);
// pixel data
int m_refNum = -1;
int m_refGen = -1;
PdfImageRef m_ref;
QImage::Format m_format = QImage::Format_Invalid;
PdfPagePrivate *m_page = nullptr;
std::unique_ptr<GfxImageColorMap> m_colorMap;
constexpr inline int refNum() const { return m_ref.m_refNum; }
constexpr inline int refGen() const { return m_ref.m_refGen; }
// vector data
PdfVectorPicture m_vectorPicture;
......
......@@ -7,6 +7,7 @@
#pragma once
#include <KItinerary/ExtractorDocumentProcessor>
#include <KItinerary/PdfImage>
#include <unordered_set>
......@@ -27,7 +28,7 @@ public:
void destroyNode(ExtractorDocumentNode &node) const override;
private:
mutable std::unordered_set<int> m_imageIds;
mutable std::unordered_set<PdfImageRef> m_imageIds;
};
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment