From 8562baa3f86d74b39f5aa9f4cdd66f4a43e63886 Mon Sep 17 00:00:00 2001 From: Oliver Sander Date: Fri, 23 Mar 2018 22:24:42 +0100 Subject: [PATCH 7/7] Implement Type3 font support for ArthurOutputDev --- qt5/src/ArthurOutputDev.cc | 161 +++++++++++++++++++++++++++++++++++++++++---- qt5/src/ArthurOutputDev.h | 18 +++-- qt5/src/poppler-page.cc | 2 +- 3 files changed, 159 insertions(+), 22 deletions(-) diff --git a/qt5/src/ArthurOutputDev.cc b/qt5/src/ArthurOutputDev.cc index dcac59dd..a79c7245 100644 --- a/qt5/src/ArthurOutputDev.cc +++ b/qt5/src/ArthurOutputDev.cc @@ -50,6 +50,9 @@ #include "FontEncodingTables.h" #include #include "ArthurOutputDev.h" +#include "Page.h" +#include "Gfx.h" +#include "PDFDoc.h" #include #include @@ -86,6 +89,86 @@ private: #endif +class ArthurType3Font +{ +public: + + ArthurType3Font(PDFDoc* doc, Gfx8BitFont* font); + + const QPicture& getGlyph(int gid) const; + +private: + PDFDoc* m_doc; + Gfx8BitFont* m_font; + + mutable std::vector > glyphs; + +public: + std::vector codeToGID; +}; + +ArthurType3Font::ArthurType3Font(PDFDoc* doc, Gfx8BitFont* font) +: m_doc(doc), m_font(font) +{ + char *name; + const Dict* charProcs = font->getCharProcs(); + + // Storage for the rendered glyphs + glyphs.resize(charProcs->getLength()); + + // Compute the code-to-GID map + char **enc = font->getEncoding(); + + codeToGID.resize(256); + + for (int i = 0; i < 256; ++i) { + codeToGID[i] = 0; + if (charProcs && (name = enc[i])) { + for (int j = 0; j < charProcs->getLength(); j++) { + if (strcmp(name, charProcs->getKey(j)) == 0) { + codeToGID[i] = j; + } + } + } + } +} + +const QPicture& ArthurType3Font::getGlyph(int gid) const +{ + if (!glyphs[gid]) { + + // Glyph has not been rendered before: render it now + + // Smallest box that contains all the glyphs from this font + const double* fontBBox = m_font->getFontBBox(); + PDFRectangle box(fontBBox[0], fontBBox[1], fontBBox[2], fontBBox[3]); + + Dict* resDict = m_font->getResources(); + + QPainter glyphPainter; + glyphs[gid] = std::unique_ptr(new QPicture); + glyphPainter.begin(glyphs[gid].get()); + std::unique_ptr output_dev(new ArthurOutputDev(&glyphPainter)); + + std::unique_ptr gfx(new Gfx(m_doc, output_dev.get(), resDict, + &box, // pagebox + nullptr)); // cropBox + + output_dev->startDoc(m_doc); + + output_dev->startPage (1, gfx->getState(), gfx->getXRef()); + + const Dict* charProcs = m_font->getCharProcs(); + Object charProc = charProcs->getVal(gid); + gfx->display(&charProc); + + glyphPainter.end(); + } + + return *glyphs[gid]; +} + + //------------------------------------------------------------------------ // ArthurOutputDev //------------------------------------------------------------------------ @@ -106,8 +189,9 @@ ArthurOutputDev::~ArthurOutputDev() #endif } -void ArthurOutputDev::startDoc(XRef *xrefA) { - xref = xrefA; +void ArthurOutputDev::startDoc(PDFDoc* doc) { + xref = doc->getXRef(); + m_doc = doc; #ifdef HAVE_SPLASH delete m_fontEngine; @@ -133,6 +217,7 @@ void ArthurOutputDev::saveState(GfxState *state) m_currentPenStack.push(m_currentPen); m_currentBrushStack.push(m_currentBrush); m_rawFontStack.push(m_rawFont); + m_type3FontStack.push(m_currentType3Font); m_codeToGIDStack.push(m_codeToGID); m_painter.top()->save(); @@ -146,6 +231,8 @@ void ArthurOutputDev::restoreState(GfxState *state) m_codeToGIDStack.pop(); m_rawFont = m_rawFontStack.top(); m_rawFontStack.pop(); + m_currentType3Font = m_type3FontStack.top(); + m_type3FontStack.pop(); m_currentBrush = m_currentBrushStack.top(); m_currentBrushStack.pop(); m_currentPen = m_currentPenStack.top(); @@ -361,8 +448,30 @@ void ArthurOutputDev::updateFont(GfxState *state) return; } - // is the font in the cache? + // The key to look in the font caches ArthurFontID fontID = {*gfxFont->getID(), state->getFontSize()}; + + // Current font is a type3 font + if (gfxFont->getType() == fontType3) + { + auto cacheEntry = m_type3FontCache.find(fontID); + + if (cacheEntry!=m_type3FontCache.end()) { + + // Take the font from the cache + m_currentType3Font = cacheEntry->second.get(); + + } else { + + m_currentType3Font = new ArthurType3Font(m_doc, (Gfx8BitFont*)gfxFont); + m_type3FontCache.insert(std::make_pair(fontID,std::unique_ptr(m_currentType3Font))); + + } + + return; + } + + // Non-type3: is the font in the cache? auto cacheEntry = m_rawFontCache.find(fontID); if (cacheEntry!=m_rawFontCache.end()) { @@ -817,6 +926,41 @@ void ArthurOutputDev::drawChar(GfxState *state, double x, double y, double originX, double originY, CharCode code, int nBytes, Unicode *u, int uLen) { + // First handle type3 fonts + GfxFont *gfxFont = state->getFont(); + + GfxFontType fontType = gfxFont->getType(); + if (fontType == fontType3) { + + ///////////////////////////////////////////////////////////////////// + // Draw the QPicture that contains the glyph onto the page + ///////////////////////////////////////////////////////////////////// + + // Store the QPainter state; we need to modify it temporarily + m_painter.top()->save(); + + // Make the glyph position the coordinate origin -- that's our center of scaling + m_painter.top()->translate(QPointF(x-originX, y-originY)); + + const double* mat = gfxFont->getFontMatrix(); + QTransform fontMatrix(mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); + + // Scale with the font size + fontMatrix.scale(state->getFontSize(), state->getFontSize()); + + m_painter.top()->setTransform(fontMatrix,true); + + // Actually draw the glyph + int gid = m_currentType3Font->codeToGID[code]; + m_painter.top()->drawPicture(QPointF(0,0), m_currentType3Font->getGlyph(gid)); + + // Restore transformation + m_painter.top()->restore(); + + return; + } + + // check for invisible text -- this is used by Acrobat Capture int render = state->getRender(); if (render == 3 || !m_rawFont) { @@ -883,17 +1027,6 @@ void ArthurOutputDev::drawChar(GfxState *state, double x, double y, } } -GBool ArthurOutputDev::beginType3Char(GfxState *state, double x, double y, - double dx, double dy, - CharCode code, Unicode *u, int uLen) -{ - return gFalse; -} - -void ArthurOutputDev::endType3Char(GfxState *state) -{ -} - void ArthurOutputDev::type3D0(GfxState *state, double wx, double wy) { } diff --git a/qt5/src/ArthurOutputDev.h b/qt5/src/ArthurOutputDev.h index 43933199..65835427 100644 --- a/qt5/src/ArthurOutputDev.h +++ b/qt5/src/ArthurOutputDev.h @@ -45,11 +45,14 @@ #include class GfxState; +class PDFDoc; class SplashFontEngine; class QRawFont; +class ArthurType3Font; + //------------------------------------------------------------------------ // ArthurOutputDev - Qt 5 QPainter renderer //------------------------------------------------------------------------ @@ -91,7 +94,7 @@ public: // Does this device use beginType3Char/endType3Char? Otherwise, // text in Type 3 fonts will be drawn with drawChar/drawString. - GBool interpretType3Chars() override { return gTrue; } + GBool interpretType3Chars() override { return gFalse; } //----- initialization and control @@ -143,10 +146,6 @@ public: double dx, double dy, double originX, double originY, CharCode code, int nBytes, Unicode *u, int uLen) override; - GBool beginType3Char(GfxState *state, double x, double y, - double dx, double dy, - CharCode code, Unicode *u, int uLen) override; - void endType3Char(GfxState *state) override; void endTextObject(GfxState *state) override; //----- image drawing @@ -182,8 +181,8 @@ public: //----- special access // Called to indicate that a new PDF document has been loaded. - void startDoc(XRef *xrefA); - + void startDoc(PDFDoc* doc); + GBool isReverseVideo() { return gFalse; } private: @@ -211,12 +210,16 @@ private: GBool m_needFontUpdate; // set when the font needs to be updated SplashFontEngine *m_fontEngine; + PDFDoc* m_doc; XRef *xref; // xref table for current document // The current font in use QRawFont* m_rawFont; std::stack m_rawFontStack; + ArthurType3Font* m_currentType3Font; + std::stack m_type3FontStack; + // Identify a font by its 'Ref' and its font size struct ArthurFontID { @@ -232,6 +235,7 @@ private: // Cache all fonts std::map > m_rawFontCache; + std::map > m_type3FontCache; // The table that maps character codes to glyph indexes int* m_codeToGID; diff --git a/qt5/src/poppler-page.cc b/qt5/src/poppler-page.cc index 381a608b..b9289666 100644 --- a/qt5/src/poppler-page.cc +++ b/qt5/src/poppler-page.cc @@ -456,7 +456,7 @@ static bool renderToArthur(QImageDumpingArthurOutputDev *arthur_output, QPainter painter->setRenderHint(QPainter::TextAntialiasing); painter->translate(x == -1 ? 0 : -x, y == -1 ? 0 : -y); - arthur_output->startDoc(page->parentDoc->doc->getXRef()); + arthur_output->startDoc(page->parentDoc->doc); const GBool hideAnnotations = page->parentDoc->m_hints & Document::HideAnnotations; -- 2.16.2