summaryrefslogtreecommitdiffstats
path: root/sdext/source/pdfimport/xpdfwrapper
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sdext/source/pdfimport/xpdfwrapper
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.cxx1168
-rw-r--r--sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.hxx302
-rw-r--r--sdext/source/pdfimport/xpdfwrapper/pnghelper.cxx404
-rw-r--r--sdext/source/pdfimport/xpdfwrapper/pnghelper.hxx84
-rw-r--r--sdext/source/pdfimport/xpdfwrapper/wrapper_gpl.cxx188
5 files changed, 2146 insertions, 0 deletions
diff --git a/sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.cxx b/sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.cxx
new file mode 100644
index 000000000..3ad139b65
--- /dev/null
+++ b/sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.cxx
@@ -0,0 +1,1168 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "pdfioutdev_gpl.hxx"
+#include "pnghelper.hxx"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <math.h>
+
+#include <memory>
+#include <vector>
+
+// sigh, UTF8.h was removed in poppler-0.21.0 and put back in 0.21.1, then renamed to UnicodeMapFuncs.h in 0.62.0
+// FIXME: we can't use #if POPPLER_CHECK_VERSION(0, 21, 0) && !POPPLER_CHECK_VERSION(0, 21, 1)
+// because the internal poppler does not provide poppler-version.h and the macro always returns 0
+#if POPPLER_CHECK_VERSION(0, 62, 0)
+#include <UnicodeMapFuncs.h>
+#elif POPPLER_CHECK_VERSION(0, 21, 1)
+#include <UTF8.h>
+#elif POPPLER_CHECK_VERSION(0, 21, 0)
+#include "UTF.h"
+#else
+#include "UTF8.h"
+#endif
+
+#ifdef _WIN32
+# define snprintf _snprintf
+
+#if defined __GNUC__
+#pragma GCC diagnostic warning "-Wformat"
+#pragma GCC diagnostic warning "-Wformat-extra-args"
+#endif
+#endif
+
+/* SYNC STREAMS
+ ============
+
+ We stream human-readable tokens to stdout, and binary data (fonts,
+ bitmaps) to g_binary_out. Another process reads from those pipes, and
+ there lies the rub: things can deadlock, if the two involved
+ processes access the pipes in different order. At any point in
+ time, both processes must access the same pipe. To ensure this,
+ data must be flushed to the OS before writing to a different pipe,
+ otherwise not-yet-written data will leave the reading process
+ waiting on the wrong pipe.
+ */
+
+namespace pdfi
+{
+
+/// cut off very small numbers & clamp value to zero
+static double normalize( double val )
+{
+ return fabs(val) < 0.0000001 ? 0.0 : val;
+}
+
+namespace
+{
+
+/** Escapes line-ending characters (\n and \r) in input string.
+ */
+std::vector<char> lcl_escapeLineFeeds(const char* const i_pStr)
+{
+ size_t nLength(strlen(i_pStr));
+ std::vector<char> aBuffer;
+ aBuffer.reserve(2*nLength+1);
+
+ const char* pRead = i_pStr;
+ while( nLength-- )
+ {
+ if( *pRead == '\r' )
+ {
+ aBuffer.push_back('\\');
+ aBuffer.push_back('r');
+ }
+ else if( *pRead == '\n' )
+ {
+ aBuffer.push_back('\\');
+ aBuffer.push_back('n');
+ }
+ else if( *pRead == '\\' )
+ {
+ aBuffer.push_back('\\');
+ aBuffer.push_back('\\');
+ }
+ else
+ aBuffer.push_back(*pRead);
+ pRead++;
+ }
+ aBuffer.push_back(0);
+
+ return aBuffer;
+}
+
+}
+
+/// for the temp char buffer the header gets snprintfed in
+#define WRITE_BUFFER_SIZE 1024
+
+/// for the initial std::vector capacity when copying stream from xpdf
+#define WRITE_BUFFER_INITIAL_CAPACITY (1024*100)
+
+static void initBuf(OutputBuffer& io_rBuffer)
+{
+ io_rBuffer.reserve(WRITE_BUFFER_INITIAL_CAPACITY);
+}
+
+static void writeBinaryBuffer( const OutputBuffer& rBuffer )
+{
+ // ---sync point--- see SYNC STREAMS above
+ fflush(stdout);
+
+ // put buffer to stderr
+ if( !rBuffer.empty() )
+ if( fwrite(rBuffer.data(), sizeof(char),
+ rBuffer.size(), g_binary_out) != static_cast<size_t>(rBuffer.size()) )
+ exit(1); // error
+
+ // ---sync point--- see SYNC STREAMS above
+ fflush(g_binary_out);
+}
+
+static bool ExtractJpegData(Stream* str, OutputBuffer& outBuf)
+{
+ int bytesToMarker = 0;
+ int bytesToLen = -1;
+ bool collectBytes = false;
+ int startOfScan = 0;
+ int b1 = -1;
+ for (; ; )
+ {
+ const int b2 = b1;
+ b1 = str->getChar();
+
+ if (b1 == -1)
+ return false;
+
+ if (collectBytes)
+ {
+ outBuf.push_back(static_cast<Output_t>(b1));
+
+ bytesToMarker--;
+ bytesToLen--;
+ }
+
+ if (bytesToMarker == 0)
+ {
+ if (startOfScan == 1)
+ {
+ bytesToMarker = -1;
+ startOfScan = 2;
+ }
+ else if (b2 == 0xFF)
+ {
+ if (b1 == 0xD8)
+ {
+ collectBytes = true;
+ bytesToMarker = 2;
+
+ outBuf.push_back(Output_t(0xFF));
+ outBuf.push_back(Output_t(0xD8));
+ }
+ else
+ {
+ bytesToLen = 2;
+ }
+ if (b1 == 0xDA)
+ {
+ startOfScan = 1;
+ }
+ }
+ else if (collectBytes)
+ {
+ return false;
+ }
+ }
+
+ if (bytesToLen == 0)
+ {
+ bytesToMarker = b2 * 256 + b1;
+ }
+
+ if (startOfScan == 2)
+ if ((b2 == 0xFF) && (b1 == 0xD9))
+ return true;
+ }
+}
+
+static void writeJpeg_( OutputBuffer& o_rOutputBuf, Stream* str )
+{
+ // dump JPEG file as-is
+#if POPPLER_CHECK_VERSION(0, 17, 3)
+ str = str->getNextStream();
+#else
+ str = ((DCTStream *)str)->getRawStream();
+#endif
+ str->reset();
+
+ o_rOutputBuf.clear();
+ ExtractJpegData(str, o_rOutputBuf);
+
+ printf( " JPEG %d", static_cast<int>(o_rOutputBuf.size()) );
+ printf("\n");
+
+ str->close();
+}
+
+static void writePbm_(OutputBuffer& o_rOutputBuf, Stream* str, int width, int height, bool bInvert )
+{
+ // write as PBM (char by char, to avoid stdlib lineend messing)
+ o_rOutputBuf.clear();
+ o_rOutputBuf.resize(WRITE_BUFFER_SIZE);
+ o_rOutputBuf[0] = 'P';
+ o_rOutputBuf[1] = '4';
+ o_rOutputBuf[2] = 0x0A;
+ char *pAsCharPtr = reinterpret_cast<char *>(&o_rOutputBuf[3]);
+ int nOutLen = snprintf(pAsCharPtr, WRITE_BUFFER_SIZE-10, "%d %d", width, height);
+ if( nOutLen < 0 )
+ nOutLen = WRITE_BUFFER_SIZE-10;
+ o_rOutputBuf[3+nOutLen] =0x0A;
+ o_rOutputBuf[3+nOutLen+1]=0;
+
+ const int header_size = 3+nOutLen+1;
+ const int size = height * ((width + 7) / 8);
+
+ printf( " PBM %d", size + header_size );
+ printf("\n");
+
+ // trim buffer to exact header length
+ o_rOutputBuf.resize(header_size);
+
+ // initialize stream
+ str->reset();
+
+ // copy the raw stream
+ if( bInvert )
+ {
+ for( int i=0; i<size; ++i)
+ o_rOutputBuf.push_back(static_cast<char>(str->getChar() ^ 0xff));
+ }
+ else
+ {
+ for( int i=0; i<size; ++i)
+ o_rOutputBuf.push_back(static_cast<char>(str->getChar()));
+ }
+
+ str->close();
+}
+
+static void writePpm_( OutputBuffer& o_rOutputBuf,
+ Stream* str,
+ int width,
+ int height,
+ GfxImageColorMap* colorMap )
+{
+ // write as PPM (char by char, to avoid stdlib lineend messing)
+ o_rOutputBuf.clear();
+ o_rOutputBuf.resize(WRITE_BUFFER_SIZE);
+ o_rOutputBuf[0] = 'P';
+ o_rOutputBuf[1] = '6';
+ o_rOutputBuf[2] = '\n';
+ char *pAsCharPtr = reinterpret_cast<char *>(&o_rOutputBuf[3]);
+ int nOutLen = snprintf(pAsCharPtr, WRITE_BUFFER_SIZE-10, "%d %d", width, height);
+ if( nOutLen < 0 )
+ nOutLen = WRITE_BUFFER_SIZE-10;
+ o_rOutputBuf[3+nOutLen] ='\n';
+ o_rOutputBuf[3+nOutLen+1]='2';
+ o_rOutputBuf[3+nOutLen+2]='5';
+ o_rOutputBuf[3+nOutLen+3]='5';
+ o_rOutputBuf[3+nOutLen+4]='\n';
+ o_rOutputBuf[3+nOutLen+5]=0;
+
+ const int header_size = 3+nOutLen+5;
+ const int size = width*height*3 + header_size;
+
+ printf( " PPM %d", size );
+ printf("\n");
+
+ // trim buffer to exact header size
+ o_rOutputBuf.resize(header_size);
+
+ // initialize stream
+ unsigned char *p;
+ GfxRGB rgb;
+ std::unique_ptr<ImageStream> imgStr(
+ new ImageStream(str,
+ width,
+ colorMap->getNumPixelComps(),
+ colorMap->getBits()));
+ imgStr->reset();
+
+ for( int y=0; y<height; ++y)
+ {
+ p = imgStr->getLine();
+ for( int x=0; x<width; ++x)
+ {
+ colorMap->getRGB(p, &rgb);
+ o_rOutputBuf.push_back(colToByte(rgb.r));
+ o_rOutputBuf.push_back(colToByte(rgb.g));
+ o_rOutputBuf.push_back(colToByte(rgb.b));
+
+ p +=colorMap->getNumPixelComps();
+ }
+ }
+}
+
+// call this only for 1 bit image streams !
+static void writePng_( OutputBuffer& o_rOutputBuf,
+ Stream* str,
+ int width,
+ int height,
+ GfxRGB const & zeroColor,
+ GfxRGB const & oneColor,
+ bool bIsMask )
+{
+ o_rOutputBuf.clear();
+
+ // get png image
+ PngHelper::createPng( o_rOutputBuf, str, width, height, zeroColor, oneColor, bIsMask );
+
+ printf( " PNG %d", static_cast<int>(o_rOutputBuf.size()) );
+ printf("\n");
+}
+
+static void writePng_( OutputBuffer& o_rOutputBuf,
+ Stream* str,
+ int width, int height, GfxImageColorMap* colorMap,
+ Stream* maskStr,
+ int maskWidth, int maskHeight, GfxImageColorMap* maskColorMap )
+{
+ o_rOutputBuf.clear();
+
+ // get png image
+ PngHelper::createPng( o_rOutputBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap );
+
+ printf( " PNG %d", static_cast<int>(o_rOutputBuf.size()) );
+ printf("\n");
+}
+
+static void writePng_( OutputBuffer& o_rOutputBuf,
+ Stream* str,
+ int width, int height, GfxImageColorMap* colorMap,
+ Stream* maskStr,
+ int maskWidth, int maskHeight, bool maskInvert )
+{
+ o_rOutputBuf.clear();
+
+ // get png image
+ PngHelper::createPng( o_rOutputBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert );
+
+ printf( " PNG %d", static_cast<int>(o_rOutputBuf.size()) );
+ printf("\n");
+}
+
+// stolen from ImageOutputDev.cc
+static void writeMask_( OutputBuffer& o_rOutputBuf, Stream* str, int width, int height, bool bInvert )
+{
+ if( str->getKind() == strDCT )
+ writeJpeg_(o_rOutputBuf, str);
+ else
+ writePbm_(o_rOutputBuf, str, width, height, bInvert );
+}
+
+static void writeImage_( OutputBuffer& o_rOutputBuf,
+ Stream* str,
+ int width,
+ int height,
+ GfxImageColorMap* colorMap )
+{
+ // dump JPEG file
+ if( str->getKind() == strDCT &&
+ (colorMap->getNumPixelComps() == 1 ||
+ colorMap->getNumPixelComps() == 3) )
+ {
+ writeJpeg_(o_rOutputBuf, str);
+ }
+ else if (colorMap->getNumPixelComps() == 1 &&
+ colorMap->getBits() == 1)
+ {
+ // this is a two color bitmap, write a png
+ // provide default colors
+ GfxRGB zeroColor = { 0, 0, 0 },
+ oneColor = { byteToCol( 0xff ), byteToCol( 0xff ), byteToCol( 0xff ) };
+ if( colorMap->getColorSpace()->getMode() == csIndexed || colorMap->getColorSpace()->getMode() == csDeviceGray )
+ {
+ unsigned char nIndex = 0;
+ colorMap->getRGB( &nIndex, &zeroColor );
+ nIndex = 1;
+ colorMap->getRGB( &nIndex, &oneColor );
+ }
+ writePng_( o_rOutputBuf, str, width, height, zeroColor, oneColor, false);
+ }
+ else
+ writePpm_( o_rOutputBuf, str, width, height, colorMap );
+}
+
+// forwarders
+
+
+static void writeImageLF( OutputBuffer& o_rOutputBuf,
+ Stream* str,
+ int width,
+ int height,
+ GfxImageColorMap* colorMap ) { writeImage_(o_rOutputBuf,str,width,height,colorMap); }
+static void writeMaskLF( OutputBuffer& o_rOutputBuf,
+ Stream* str,
+ int width,
+ int height,
+ bool bInvert ) { writeMask_(o_rOutputBuf,str,width,height,bInvert); }
+
+
+int PDFOutDev::parseFont( long long nNewId, GfxFont* gfxFont, const GfxState* state ) const
+{
+ FontAttributes aNewFont;
+ int nSize = 0;
+
+#if POPPLER_CHECK_VERSION(20, 12, 0)
+ std::string familyName = gfxFont->getNameWithoutSubsetTag();
+#else
+#if POPPLER_CHECK_VERSION(0, 71, 0) // GooString::toStr()
+ std::string familyName = gfxFont->getName()->toStr();
+#else
+ const GooString* gooString = gfxFont->getName();
+ std::string familyName = std::string(gooString->getCString(), gooString->getLength());
+#endif
+ if (familyName.length() > 7 && familyName.at(6) == '+')
+ {
+ familyName = familyName.substr(7);
+ }
+#endif
+ if( familyName != "" )
+ {
+ aNewFont.familyName.clear();
+#if POPPLER_CHECK_VERSION(0, 83, 0) // GooString::append(const std::string&)
+ aNewFont.familyName.append( familyName );
+#else
+ aNewFont.familyName.append( familyName.c_str() );
+#endif
+ }
+ else
+ {
+ aNewFont.familyName.clear();
+ aNewFont.familyName.append( "Arial" );
+ }
+
+ aNewFont.maFontWeight = gfxFont->getWeight();
+ aNewFont.isItalic = gfxFont->isItalic();
+#if POPPLER_CHECK_VERSION(0, 83, 0) // const added to getTransformedFontSize
+ aNewFont.size = state->getTransformedFontSize();
+#else
+ aNewFont.size = const_cast<GfxState*>(state)->getTransformedFontSize();
+#endif
+ aNewFont.isUnderline = false;
+
+ if( gfxFont->getType() == fontTrueType || gfxFont->getType() == fontType1 )
+ {
+ // TODO(P3): Unfortunately, need to read stream twice, since
+ // we must write byte count to stdout before
+#if POPPLER_CHECK_VERSION(22, 6, 0)
+ std::optional<std::vector<unsigned char>> pBuf = gfxFont->readEmbFontFile( m_pDoc->getXRef() );
+ if ( pBuf )
+ {
+ aNewFont.isEmbedded = true;
+ nSize = pBuf->size();
+ }
+#else
+ char* pBuf = gfxFont->readEmbFontFile( m_pDoc->getXRef(), &nSize );
+ if( pBuf )
+ {
+ aNewFont.isEmbedded = true;
+ gfree(pBuf);
+ }
+#endif
+ }
+
+ m_aFontMap[ nNewId ] = aNewFont;
+ return nSize;
+}
+
+void PDFOutDev::writeFontFile( GfxFont* gfxFont ) const
+{
+ if( gfxFont->getType() != fontTrueType && gfxFont->getType() != fontType1 )
+ return;
+
+ int nSize = 0;
+#if POPPLER_CHECK_VERSION(22, 6, 0)
+ std::optional<std::vector<unsigned char>> pBuf = gfxFont->readEmbFontFile( m_pDoc->getXRef() );
+ if ( pBuf )
+ nSize = pBuf->size();
+ if ( nSize == 0 )
+ return;
+#else
+ char* pBuf = gfxFont->readEmbFontFile( m_pDoc->getXRef(), &nSize );
+ if( !pBuf )
+ return;
+#endif
+
+ // ---sync point--- see SYNC STREAMS above
+ fflush(stdout);
+
+#if POPPLER_CHECK_VERSION(22, 6, 0)
+ if( fwrite(pBuf->data(), sizeof(*pBuf->data()), nSize, g_binary_out) != static_cast<size_t>(nSize) )
+ {
+ exit(1); // error
+ }
+ // ---sync point--- see SYNC STREAMS above
+ fflush(g_binary_out);
+#else
+ if( fwrite(pBuf, sizeof(char), nSize, g_binary_out) != static_cast<size_t>(nSize) )
+ {
+ gfree(pBuf);
+ exit(1); // error
+ }
+ // ---sync point--- see SYNC STREAMS above
+ fflush(g_binary_out);
+ gfree(pBuf);
+#endif
+}
+
+#if POPPLER_CHECK_VERSION(0, 83, 0)
+void PDFOutDev::printPath( const GfxPath* pPath )
+#else
+void PDFOutDev::printPath( GfxPath* pPath )
+#endif
+{
+ int nSubPaths = pPath ? pPath->getNumSubpaths() : 0;
+ for( int i=0; i<nSubPaths; i++ )
+ {
+#if POPPLER_CHECK_VERSION(0, 83, 0)
+ const
+#endif
+ GfxSubpath* pSub = pPath->getSubpath( i );
+ const int nPoints = pSub->getNumPoints();
+
+ printf( " subpath %d", pSub->isClosed() );
+
+ for( int n=0; n<nPoints; ++n )
+ {
+ printf( " %f %f %d",
+ normalize(pSub->getX(n)),
+ normalize(pSub->getY(n)),
+ pSub->getCurve(n) );
+ }
+ }
+}
+
+PDFOutDev::PDFOutDev( PDFDoc* pDoc ) :
+ m_pDoc( pDoc ),
+ m_pUtf8Map( new UnicodeMap("UTF-8", true, &mapUTF8) ),
+ m_bSkipImages(false)
+{
+}
+PDFOutDev::~PDFOutDev()
+{
+}
+
+void PDFOutDev::startPage(int /*pageNum*/, GfxState* state
+#if POPPLER_CHECK_VERSION(0, 23, 0) || POPPLER_CHECK_VERSION(0, 24, 0)
+ , XRef* /*xref*/
+#endif
+)
+{
+ assert(state);
+ printf("startPage %f %f\n",
+ normalize(state->getPageWidth()),
+ normalize(state->getPageHeight()));
+}
+
+void PDFOutDev::endPage()
+{
+ printf("endPage\n");
+}
+
+#if POPPLER_CHECK_VERSION(0, 19, 0)
+void PDFOutDev::processLink(AnnotLink *link)
+#elif POPPLER_CHECK_VERSION(0, 17, 0)
+void PDFOutDev::processLink(AnnotLink *link, Catalog *)
+#else
+void PDFOutDev::processLink(Link* link, Catalog*)
+#endif
+{
+ assert(link);
+
+ double x1,x2,y1,y2;
+ link->getRect( &x1, &y1, &x2, &y2 );
+
+ LinkAction* pAction = link->getAction();
+ if (!(pAction && pAction->getKind() == actionURI))
+ return;
+
+#if POPPLER_CHECK_VERSION(0, 86, 0)
+ const char* pURI = static_cast<LinkURI*>(pAction)->getURI().c_str();
+#elif POPPLER_CHECK_VERSION(0, 72, 0)
+ const char* pURI = static_cast<LinkURI*>(pAction)->getURI()->c_str();
+#else
+ const char* pURI = static_cast<LinkURI*>(pAction)->getURI()->getCString();
+#endif
+
+ std::vector<char> aEsc( lcl_escapeLineFeeds(pURI) );
+
+ printf( "drawLink %f %f %f %f %s\n",
+ normalize(x1),
+ normalize(y1),
+ normalize(x2),
+ normalize(y2),
+ aEsc.data() );
+}
+
+void PDFOutDev::saveState(GfxState*)
+{
+ printf( "saveState\n" );
+}
+
+void PDFOutDev::restoreState(GfxState*)
+{
+ printf( "restoreState\n" );
+}
+
+#if POPPLER_CHECK_VERSION(0, 71, 0)
+void PDFOutDev::setDefaultCTM(const double *pMat)
+#else
+void PDFOutDev::setDefaultCTM(double *pMat)
+#endif
+{
+ assert(pMat);
+
+ OutputDev::setDefaultCTM(pMat);
+
+ printf( "updateCtm %f %f %f %f %f %f\n",
+ normalize(pMat[0]),
+ normalize(pMat[1]),
+ normalize(pMat[2]),
+ normalize(pMat[3]),
+ normalize(pMat[4]),
+ normalize(pMat[5]) );
+}
+
+void PDFOutDev::updateCTM(GfxState* state,
+ double, double,
+ double, double,
+ double, double)
+{
+ assert(state);
+
+ const double* const pMat = state->getCTM();
+ assert(pMat);
+
+ printf( "updateCtm %f %f %f %f %f %f\n",
+ normalize(pMat[0]),
+ normalize(pMat[1]),
+ normalize(pMat[2]),
+ normalize(pMat[3]),
+ normalize(pMat[4]),
+ normalize(pMat[5]) );
+}
+
+void PDFOutDev::updateLineDash(GfxState *state)
+{
+ if (m_bSkipImages)
+ return;
+ assert(state);
+
+ int arrayLen; double startOffset;
+#if POPPLER_CHECK_VERSION(22, 9, 0)
+ const std::vector<double> &dash = state->getLineDash(&startOffset);
+ const double* dashArray = dash.data();
+ arrayLen = dash.size();
+#else
+ double* dashArray;
+ state->getLineDash(&dashArray, &arrayLen, &startOffset);
+#endif
+
+ printf( "updateLineDash" );
+ if( arrayLen && dashArray )
+ {
+ printf( " %f %d", normalize(startOffset), arrayLen );
+ for( int i=0; i<arrayLen; ++i )
+ printf( " %f", normalize(*dashArray++) );
+ }
+ printf( "\n" );
+}
+
+void PDFOutDev::updateFlatness(GfxState *state)
+{
+ if (m_bSkipImages)
+ return;
+ assert(state);
+ printf( "updateFlatness %d\n", state->getFlatness() );
+}
+
+void PDFOutDev::updateLineJoin(GfxState *state)
+{
+ if (m_bSkipImages)
+ return;
+ assert(state);
+ printf( "updateLineJoin %d\n", state->getLineJoin() );
+}
+
+void PDFOutDev::updateLineCap(GfxState *state)
+{
+ if (m_bSkipImages)
+ return;
+ assert(state);
+ printf( "updateLineCap %d\n", state->getLineCap() );
+}
+
+void PDFOutDev::updateMiterLimit(GfxState *state)
+{
+ if (m_bSkipImages)
+ return;
+ assert(state);
+ printf( "updateMiterLimit %f\n", normalize(state->getMiterLimit()) );
+}
+
+void PDFOutDev::updateLineWidth(GfxState *state)
+{
+ if (m_bSkipImages)
+ return;
+ assert(state);
+ printf( "updateLineWidth %f\n", normalize(state->getLineWidth()) );
+}
+
+void PDFOutDev::updateFillColor(GfxState *state)
+{
+ if (m_bSkipImages)
+ return;
+ assert(state);
+
+ GfxRGB aRGB;
+ state->getFillRGB( &aRGB );
+
+ printf( "updateFillColor %f %f %f %f\n",
+ normalize(colToDbl(aRGB.r)),
+ normalize(colToDbl(aRGB.g)),
+ normalize(colToDbl(aRGB.b)),
+ normalize(state->getFillOpacity()) );
+}
+
+void PDFOutDev::updateStrokeColor(GfxState *state)
+{
+ if (m_bSkipImages)
+ return;
+ assert(state);
+
+ GfxRGB aRGB;
+ state->getStrokeRGB( &aRGB );
+
+ printf( "updateStrokeColor %f %f %f %f\n",
+ normalize(colToDbl(aRGB.r)),
+ normalize(colToDbl(aRGB.g)),
+ normalize(colToDbl(aRGB.b)),
+ normalize(state->getFillOpacity()) );
+}
+
+void PDFOutDev::updateFillOpacity(GfxState *state)
+{
+ if (m_bSkipImages)
+ return;
+ updateFillColor(state);
+}
+
+void PDFOutDev::updateStrokeOpacity(GfxState *state)
+{
+ if (m_bSkipImages)
+ return;
+ updateStrokeColor(state);
+}
+
+void PDFOutDev::updateBlendMode(GfxState*)
+{
+}
+
+void PDFOutDev::updateFont(GfxState *state)
+{
+ assert(state);
+
+#if POPPLER_CHECK_VERSION(22, 6, 0)
+ GfxFont *gfxFont = state->getFont().get();
+#else
+ GfxFont *gfxFont = state->getFont();
+#endif
+ if( !gfxFont )
+ return;
+
+ FontAttributes aFont;
+ int nEmbedSize=0;
+
+#if POPPLER_CHECK_VERSION(0, 64, 0)
+ const
+#endif
+ Ref* pID = gfxFont->getID();
+ // TODO(Q3): Portability problem
+ long long fontID = static_cast<long long>(pID->gen) << 32 | static_cast<long long>(pID->num);
+ std::unordered_map< long long, FontAttributes >::const_iterator it =
+ m_aFontMap.find( fontID );
+ if( it == m_aFontMap.end() )
+ {
+ nEmbedSize = parseFont( fontID, gfxFont, state );
+ it = m_aFontMap.find( fontID );
+ }
+
+ printf( "updateFont" );
+ if( it != m_aFontMap.end() )
+ {
+ // conflating this with printf below crashes under Windoze
+ printf( " %lld", fontID );
+
+ aFont = it->second;
+
+#if POPPLER_CHECK_VERSION(0, 72, 0)
+ std::vector<char> aEsc( lcl_escapeLineFeeds(aFont.familyName.c_str()) );
+#else
+ std::vector<char> aEsc( lcl_escapeLineFeeds(aFont.familyName.getCString()) );
+#endif
+ printf( " %d %d %d %d %f %d %s",
+ aFont.isEmbedded,
+ aFont.maFontWeight,
+ aFont.isItalic,
+ aFont.isUnderline,
+ normalize(state->getTransformedFontSize()),
+ nEmbedSize,
+ aEsc.data() );
+ }
+ printf( "\n" );
+
+ if (nEmbedSize)
+ {
+ writeFontFile(gfxFont);
+ }
+}
+
+void PDFOutDev::updateRender(GfxState *state)
+{
+ assert(state);
+
+ printf( "setTextRenderMode %d\n", state->getRender() );
+}
+
+void PDFOutDev::stroke(GfxState *state)
+{
+ if (m_bSkipImages)
+ return;
+ assert(state);
+
+ printf( "strokePath" );
+ printPath( state->getPath() );
+ printf( "\n" );
+}
+
+void PDFOutDev::fill(GfxState *state)
+{
+ if (m_bSkipImages)
+ return;
+ assert(state);
+
+ printf( "fillPath" );
+ printPath( state->getPath() );
+ printf( "\n" );
+}
+
+void PDFOutDev::eoFill(GfxState *state)
+{
+ if (m_bSkipImages)
+ return;
+ assert(state);
+
+ printf( "eoFillPath" );
+ printPath( state->getPath() );
+ printf( "\n" );
+}
+
+void PDFOutDev::clip(GfxState *state)
+{
+ if (m_bSkipImages)
+ return;
+ assert(state);
+
+ printf( "clipPath" );
+ printPath( state->getPath() );
+ printf( "\n" );
+}
+
+void PDFOutDev::eoClip(GfxState *state)
+{
+ if (m_bSkipImages)
+ return;
+ assert(state);
+
+ printf( "eoClipPath" );
+ printPath( state->getPath() );
+ printf( "\n" );
+}
+
+/** Output one glyph
+
+
+ @param dx
+ horizontal skip for character (already scaled with font size) +
+ inter-char space: cursor is shifted by this amount for next char
+
+ @param dy
+ vertical skip for character (zero for horizontal writing mode):
+ cursor is shifted by this amount for next char
+
+ @param originX
+ local offset of character (zero for horizontal writing mode). not
+ taken into account for output pos updates. Used for vertical writing.
+
+ @param originY
+ local offset of character (zero for horizontal writing mode). not
+ taken into account for output pos updates. Used for vertical writing.
+ */
+
+#if POPPLER_CHECK_VERSION(0, 82, 0)
+void PDFOutDev::drawChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ double originX, double originY,
+ CharCode, int /*nBytes*/, const Unicode *u, int uLen)
+{
+#else
+void PDFOutDev::drawChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ double originX, double originY,
+ CharCode, int /*nBytes*/, Unicode *u, int uLen)
+{
+#endif
+ assert(state);
+
+ if( u == nullptr )
+ return;
+
+ // Fix for tdf#96080
+ if (uLen == 4 && u[0] == '\t' && u[1] == '\r' && u[2] == ' ' && u[3] == 0xA0)
+ {
+ u += 2;
+ uLen = 1;
+ }
+
+ double csdx = 0.0;
+ double csdy = 0.0;
+ if (state->getFont()->getWMode())
+ {
+ csdy = state->getCharSpace();
+ if (*u == ' ')
+ csdy += state->getWordSpace();
+ }
+ else
+ {
+ csdx = state->getCharSpace();
+ if (*u == ' ')
+ csdx += state->getWordSpace();
+ csdx *= state->getHorizScaling();
+ }
+
+ double cstdx = 0.0;
+ double cstdy = 0.0;
+ state->textTransformDelta(csdx, csdy, &cstdx, &cstdy);
+
+ const double fontSize = state->getFontSize();
+
+ const double aPositionX(x-originX);
+ const double aPositionY(y-originY);
+
+ const double* pTextMat=state->getTextMat();
+ printf( "drawChar %f %f %f %f %f %f %f %f %f ",
+ normalize(aPositionX),
+ normalize(aPositionY),
+ normalize(aPositionX + dx - cstdx),
+ normalize(aPositionY + dy - cstdy),
+ normalize(pTextMat[0]),
+ normalize(pTextMat[2]),
+ normalize(pTextMat[1]),
+ normalize(pTextMat[3]),
+ normalize(fontSize)
+ );
+
+ // silence spurious warning
+#if POPPLER_CHECK_VERSION(0, 62, 0)
+ (void)&mapUTF16;
+#else
+ (void)&mapUCS2;
+#endif
+
+ char buf[9];
+ for( int i=0; i<uLen; ++i )
+ {
+ buf[ m_pUtf8Map->mapUnicode(u[i], buf, sizeof(buf)-1) ] = 0;
+ std::vector<char> aEsc( lcl_escapeLineFeeds(buf) );
+ printf( "%s", aEsc.data() );
+ }
+
+ printf( "\n" );
+}
+
+#if POPPLER_CHECK_VERSION(0, 64, 0)
+void PDFOutDev::drawString(GfxState*, const GooString* /*s*/)
+#else
+void PDFOutDev::drawString(GfxState*, GooString* /*s*/)
+#endif
+{
+ // TODO(F3): NYI
+}
+
+void PDFOutDev::endTextObject(GfxState*)
+{
+ printf( "endTextObject\n" );
+}
+
+void PDFOutDev::drawImageMask(GfxState* pState, Object*, Stream* str,
+ int width, int height, poppler_bool invert,
+ poppler_bool /*interpolate*/,
+ poppler_bool /*inlineImg*/ )
+{
+ if (m_bSkipImages)
+ return;
+ OutputBuffer aBuf; initBuf(aBuf);
+
+ printf( "drawMask %d %d %d", width, height, invert );
+
+ int bitsPerComponent = 1;
+ StreamColorSpaceMode csMode = streamCSNone;
+ str->getImageParams( &bitsPerComponent, &csMode );
+ if( bitsPerComponent == 1 && (csMode == streamCSNone || csMode == streamCSDeviceGray) )
+ {
+ GfxRGB oneColor = { dblToCol( 1.0 ), dblToCol( 1.0 ), dblToCol( 1.0 ) };
+ GfxRGB zeroColor = { dblToCol( 0.0 ), dblToCol( 0.0 ), dblToCol( 0.0 ) };
+ pState->getFillColorSpace()->getRGB( pState->getFillColor(), &zeroColor );
+ if( invert )
+ writePng_( aBuf, str, width, height, oneColor, zeroColor, true );
+ else
+ writePng_( aBuf, str, width, height, zeroColor, oneColor, true );
+ }
+ else
+ writeMaskLF(aBuf, str, width, height, invert);
+ writeBinaryBuffer(aBuf);
+}
+
+#if POPPLER_CHECK_VERSION(0, 82, 0)
+void PDFOutDev::drawImage(GfxState*, Object*, Stream* str,
+ int width, int height, GfxImageColorMap* colorMap,
+ poppler_bool /*interpolate*/,
+ const int* maskColors, poppler_bool /*inlineImg*/ )
+{
+#else
+void PDFOutDev::drawImage(GfxState*, Object*, Stream* str,
+ int width, int height, GfxImageColorMap* colorMap,
+ poppler_bool /*interpolate*/,
+ int* maskColors, poppler_bool /*inlineImg*/ )
+{
+#endif
+ if (m_bSkipImages)
+ return;
+ OutputBuffer aBuf; initBuf(aBuf);
+ OutputBuffer aMaskBuf;
+
+ printf( "drawImage %d %d", width, height );
+
+ if( maskColors )
+ {
+ // write mask colors. nBytes must be even - first half is
+ // lower bound values, second half upper bound values
+ if( colorMap->getColorSpace()->getMode() == csIndexed )
+ {
+ aMaskBuf.push_back( static_cast<char>(maskColors[0]) );
+ aMaskBuf.push_back( static_cast<char>(maskColors[gfxColorMaxComps]) );
+ }
+ else
+ {
+ GfxRGB aMinRGB;
+ colorMap->getColorSpace()->getRGB(
+#if POPPLER_CHECK_VERSION(0, 82, 0)
+ reinterpret_cast<const GfxColor*>(maskColors),
+#else
+ reinterpret_cast<GfxColor*>(maskColors),
+#endif
+ &aMinRGB );
+
+ GfxRGB aMaxRGB;
+ colorMap->getColorSpace()->getRGB(
+#if POPPLER_CHECK_VERSION(0, 82, 0)
+ reinterpret_cast<const GfxColor*>(maskColors)+gfxColorMaxComps,
+#else
+ reinterpret_cast<GfxColor*>(maskColors)+gfxColorMaxComps,
+#endif
+ &aMaxRGB );
+
+ aMaskBuf.push_back( colToByte(aMinRGB.r) );
+ aMaskBuf.push_back( colToByte(aMinRGB.g) );
+ aMaskBuf.push_back( colToByte(aMinRGB.b) );
+ aMaskBuf.push_back( colToByte(aMaxRGB.r) );
+ aMaskBuf.push_back( colToByte(aMaxRGB.g) );
+ aMaskBuf.push_back( colToByte(aMaxRGB.b) );
+ }
+ }
+
+ printf( " %d", static_cast<int>(aMaskBuf.size()) );
+ writeImageLF( aBuf, str, width, height, colorMap );
+ writeBinaryBuffer(aBuf);
+ writeBinaryBuffer(aMaskBuf);
+}
+
+void PDFOutDev::drawMaskedImage(GfxState*, Object*, Stream* str,
+ int width, int height,
+ GfxImageColorMap* colorMap,
+ poppler_bool /*interpolate*/,
+ Stream* maskStr,
+ int maskWidth, int maskHeight,
+ poppler_bool maskInvert, poppler_bool /*maskInterpolate*/
+ )
+{
+ if (m_bSkipImages)
+ return;
+ OutputBuffer aBuf; initBuf(aBuf);
+ printf( "drawImage %d %d 0", width, height );
+ writePng_( aBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert );
+ writeBinaryBuffer( aBuf );
+}
+
+void PDFOutDev::drawSoftMaskedImage(GfxState*, Object*, Stream* str,
+ int width, int height,
+ GfxImageColorMap* colorMap,
+ poppler_bool /*interpolate*/,
+ Stream* maskStr,
+ int maskWidth, int maskHeight,
+ GfxImageColorMap* maskColorMap
+ , poppler_bool /*maskInterpolate*/
+ )
+{
+ if (m_bSkipImages)
+ return;
+ OutputBuffer aBuf; initBuf(aBuf);
+ printf( "drawImage %d %d 0", width, height );
+ writePng_( aBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap );
+ writeBinaryBuffer( aBuf );
+}
+
+void PDFOutDev::setPageNum( int nNumPages )
+{
+ // TODO(F3): printf might format int locale-dependent!
+ printf("setPageNum %d\n", nNumPages);
+}
+
+void PDFOutDev::setSkipImages( bool bSkipImages )
+{
+ m_bSkipImages = bSkipImages;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.hxx b/sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.hxx
new file mode 100644
index 000000000..b34fad1ba
--- /dev/null
+++ b/sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.hxx
@@ -0,0 +1,302 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SDEXT_SOURCE_PDFIMPORT_XPDFWRAPPER_PDFIOUTDEV_GPL_HXX
+#define INCLUDED_SDEXT_SOURCE_PDFIMPORT_XPDFWRAPPER_PDFIOUTDEV_GPL_HXX
+
+#include <sal/types.h>
+#include <config_poppler.h>
+
+#if defined __GNUC__ || defined __clang__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wundef"
+# pragma GCC diagnostic ignored "-Wunused-parameter"
+#elif defined _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4100) // unreferenced formal parameter
+#pragma warning(disable : 4310) // cast truncates constant value
+#endif
+
+#include <GfxState.h>
+#include <GfxFont.h>
+#include <UnicodeMap.h>
+#include <Link.h>
+#include <Object.h>
+#include <OutputDev.h>
+#include <GlobalParams.h>
+#include <PDFDoc.h>
+
+#if defined __GNUC__ || defined __clang__
+# pragma GCC diagnostic pop
+#elif defined _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include <unordered_map>
+#include <vector>
+#include <memory>
+
+class GfxPath;
+class GfxFont;
+class PDFDoc;
+#include <cpp/poppler-version.h>
+#define POPPLER_CHECK_VERSION(major,minor,micro) \
+ (POPPLER_VERSION_MAJOR > (major) || \
+ (POPPLER_VERSION_MAJOR == (major) && POPPLER_VERSION_MINOR > (minor)) || \
+ (POPPLER_VERSION_MAJOR == (major) && POPPLER_VERSION_MINOR == (minor) && POPPLER_VERSION_MICRO >= (micro)))
+
+namespace pdfi
+{
+ struct FontAttributes
+ {
+ FontAttributes() :
+ familyName(),
+ isEmbedded(false),
+ maFontWeight(GfxFont::W400),
+ isItalic(false),
+ isUnderline(false),
+ size(0.0)
+ {}
+
+ // xpdf goo stuff is so totally borked...
+ // ...need to hand-code assignment
+ FontAttributes( const FontAttributes& rSrc ) :
+ familyName(),
+ isEmbedded(rSrc.isEmbedded),
+ maFontWeight(rSrc.maFontWeight),
+ isItalic(rSrc.isItalic),
+ isUnderline(rSrc.isUnderline),
+ size(rSrc.size)
+ {
+ familyName.append(&rSrc.getFamilyName());
+ }
+
+ FontAttributes& operator=( const FontAttributes& rSrc )
+ {
+ familyName.clear();
+ familyName.append(&rSrc.getFamilyName());
+
+ isEmbedded = rSrc.isEmbedded;
+ maFontWeight= rSrc.maFontWeight;
+ isItalic = rSrc.isItalic;
+ isUnderline = rSrc.isUnderline;
+ size = rSrc.size;
+
+ return *this;
+ }
+
+ bool operator==(const FontAttributes& rFont) const
+ {
+ return getFamilyName().cmp(&rFont.getFamilyName())==0 &&
+ isEmbedded == rFont.isEmbedded &&
+ maFontWeight == rFont.maFontWeight &&
+ isItalic == rFont.isItalic &&
+ isUnderline == rFont.isUnderline &&
+ size == rFont.size;
+ }
+
+ GooString familyName;
+ bool isEmbedded;
+ GfxFont::Weight maFontWeight;
+ bool isItalic;
+ bool isUnderline;
+ double size;
+
+ private:
+ // Work around const-ness issues in the GooString API:
+ GooString & getFamilyName() const
+ { return const_cast<GooString &>(familyName); }
+ };
+
+ // Versions before 0.15 defined GBool as int; 0.15 redefined it as bool; 0.71 dropped GBool
+#if POPPLER_VERSION_MAJOR == 0 && POPPLER_VERSION_MINOR < 71
+ typedef GBool poppler_bool;
+#else
+ typedef bool poppler_bool;
+#endif
+
+ class PDFOutDev : public OutputDev
+ {
+ // not owned by this class
+ PDFDoc* m_pDoc;
+ mutable std::unordered_map< long long,
+ FontAttributes > m_aFontMap;
+ std::unique_ptr<UnicodeMap> m_pUtf8Map;
+ bool m_bSkipImages;
+
+ int parseFont( long long nNewId, GfxFont* pFont, const GfxState* state ) const;
+ void writeFontFile( GfxFont* gfxFont ) const;
+#if POPPLER_CHECK_VERSION(0, 83, 0)
+ static void printPath( const GfxPath* pPath );
+#else
+ static void printPath( GfxPath* pPath );
+#endif
+
+ public:
+ explicit PDFOutDev( PDFDoc* pDoc );
+ virtual ~PDFOutDev() override;
+
+ //----- get info about output device
+
+ // Does this device use upside-down coordinates?
+ // (Upside-down means (0,0) is the top left corner of the page.)
+ virtual poppler_bool upsideDown() override { return true; }
+
+ // Does this device use drawChar() or drawString()?
+ virtual poppler_bool useDrawChar() override { return true; }
+
+ // Does this device use beginType3Char/endType3Char? Otherwise,
+ // text in Type 3 fonts will be drawn with drawChar/drawString.
+ virtual poppler_bool interpretType3Chars() override { return false; }
+
+ // Does this device need non-text content?
+ virtual poppler_bool needNonText() override { return true; }
+
+ //----- initialization and control
+
+ // Set default transform matrix.
+#if POPPLER_CHECK_VERSION(0, 71, 0)
+ virtual void setDefaultCTM(const double *ctm) override;
+#else
+ virtual void setDefaultCTM(double *ctm) override;
+#endif
+
+ // Start a page.
+ virtual void startPage(int pageNum, GfxState *state
+#if POPPLER_CHECK_VERSION(0, 23, 0) || POPPLER_CHECK_VERSION(0, 24, 0)
+ , XRef *xref
+#endif
+ ) override;
+
+ // End a page.
+ virtual void endPage() override;
+
+ //----- link borders
+ #if POPPLER_CHECK_VERSION(0, 19, 0)
+ virtual void processLink(AnnotLink *link) override;
+ #elif POPPLER_CHECK_VERSION(0, 17, 0)
+ virtual void processLink(AnnotLink *link, Catalog *catalog) override;
+ #else
+ virtual void processLink(Link *link, Catalog *catalog) override;
+ #endif
+
+ //----- save/restore graphics state
+ virtual void saveState(GfxState *state) override;
+ virtual void restoreState(GfxState *state) override;
+
+ //----- update graphics state
+ virtual void updateCTM(GfxState *state, double m11, double m12,
+ double m21, double m22, double m31, double m32) override;
+ virtual void updateLineDash(GfxState *state) override;
+ virtual void updateFlatness(GfxState *state) override;
+ virtual void updateLineJoin(GfxState *state) override;
+ virtual void updateLineCap(GfxState *state) override;
+ virtual void updateMiterLimit(GfxState *state) override;
+ virtual void updateLineWidth(GfxState *state) override;
+ virtual void updateFillColor(GfxState *state) override;
+ virtual void updateStrokeColor(GfxState *state) override;
+ virtual void updateFillOpacity(GfxState *state) override;
+ virtual void updateStrokeOpacity(GfxState *state) override;
+ virtual void updateBlendMode(GfxState *state) override;
+
+ //----- update text state
+ virtual void updateFont(GfxState *state) override;
+ virtual void updateRender(GfxState *state) override;
+
+ //----- path painting
+ virtual void stroke(GfxState *state) override;
+ virtual void fill(GfxState *state) override;
+ virtual void eoFill(GfxState *state) override;
+
+ //----- path clipping
+ virtual void clip(GfxState *state) override;
+ virtual void eoClip(GfxState *state) override;
+
+ //----- text drawing
+#if POPPLER_CHECK_VERSION(0, 82, 0)
+ virtual void drawChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ double originX, double originY,
+ CharCode code, int nBytes, const Unicode *u, int uLen) override;
+#else
+ virtual void drawChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ double originX, double originY,
+ CharCode code, int nBytes, Unicode *u, int uLen) override;
+#endif
+#if POPPLER_CHECK_VERSION(0, 64, 0)
+ virtual void drawString(GfxState *state, const GooString *s) override;
+#else
+ virtual void drawString(GfxState *state, GooString *s) override;
+#endif
+ virtual void endTextObject(GfxState *state) override;
+
+ //----- image drawing
+ virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, poppler_bool invert,
+ poppler_bool interpolate,
+ poppler_bool inlineImg) override;
+#if POPPLER_CHECK_VERSION(0, 82, 0)
+ virtual void drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ poppler_bool interpolate,
+ const int* maskColors, poppler_bool inlineImg) override;
+#else
+ virtual void drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ poppler_bool interpolate,
+ int* maskColors, poppler_bool inlineImg) override;
+#endif
+ virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ poppler_bool interpolate,
+ Stream *maskStr, int maskWidth, int maskHeight,
+ poppler_bool maskInvert,
+ poppler_bool maskInterpolate
+ ) override;
+ virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ poppler_bool interpolate,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GfxImageColorMap *maskColorMap
+ , poppler_bool maskInterpolate
+ ) override;
+
+ static void setPageNum( int nNumPages );
+ void setSkipImages ( bool bSkipImages );
+ };
+}
+
+extern FILE* g_binary_out;
+
+// note: if you ever change Output_t, please keep in mind that the current code
+// relies on it being of 8 bit size
+typedef unsigned char Output_t;
+typedef std::vector< Output_t > OutputBuffer;
+
+#if !POPPLER_CHECK_VERSION(0, 73, 0)
+static_assert(std::is_same_v<Guchar, unsigned char>, "unexpected typedef");
+#endif
+
+#endif // INCLUDED_SDEXT_SOURCE_PDFIMPORT_XPDFWRAPPER_PDFIOUTDEV_GPL_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sdext/source/pdfimport/xpdfwrapper/pnghelper.cxx b/sdext/source/pdfimport/xpdfwrapper/pnghelper.cxx
new file mode 100644
index 000000000..798555fe2
--- /dev/null
+++ b/sdext/source/pdfimport/xpdfwrapper/pnghelper.cxx
@@ -0,0 +1,404 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "pnghelper.hxx"
+#include <sal/macros.h>
+
+#include <zlib.h>
+
+using namespace pdfi;
+
+// checksum helpers, courtesy of libpng.org
+
+/* Table of CRCs of all 8-bit messages. */
+sal_uInt32 PngHelper::crc_table[256];
+
+/* Flag: has the table been computed? Initially false. */
+bool PngHelper::bCRCTableInit = true;
+
+/* Make the table for a fast CRC. */
+void PngHelper::initCRCTable()
+{
+ for (sal_uInt32 n = 0; n < 256; n++)
+ {
+ sal_uInt32 c = n;
+ for (int k = 0; k < 8; k++)
+ {
+ if (c & 1)
+ c = 0xedb88320L ^ (c >> 1);
+ else
+ c = c >> 1;
+ }
+ crc_table[n] = c;
+ }
+ bCRCTableInit = false;
+}
+
+/* Update a running CRC with the bytes buf[0..len-1]--the CRC
+ should be initialized to all 1's, and the transmitted value
+ is the 1's complement of the final running CRC (see the
+ crc() routine below)). */
+
+void PngHelper::updateCRC( sal_uInt32& io_rCRC, const sal_uInt8* i_pBuf, size_t i_nLen )
+{
+ if( bCRCTableInit )
+ initCRCTable();
+
+ sal_uInt32 nCRC = io_rCRC;
+ for( size_t n = 0; n < i_nLen; n++ )
+ nCRC = crc_table[(nCRC ^ i_pBuf[n]) & 0xff] ^ (nCRC >> 8);
+ io_rCRC = nCRC;
+}
+
+sal_uInt32 PngHelper::getCRC( const sal_uInt8* i_pBuf, size_t i_nLen )
+{
+ sal_uInt32 nCRC = 0xffffffff;
+ updateCRC( nCRC, i_pBuf, i_nLen );
+ return nCRC ^ 0xffffffff;
+}
+
+sal_uInt32 PngHelper::deflateBuffer( const Output_t* i_pBuf, size_t i_nLen, OutputBuffer& o_rOut )
+{
+ size_t nOrigSize = o_rOut.size();
+
+ // prepare z stream
+ z_stream aStream;
+ aStream.zalloc = Z_NULL;
+ aStream.zfree = Z_NULL;
+ aStream.opaque = Z_NULL;
+ aStream.total_out = aStream.total_in = 0;
+ if (Z_OK != deflateInit(&aStream, Z_BEST_COMPRESSION))
+ return 0;
+ aStream.avail_in = uInt(i_nLen);
+ aStream.next_in = i_pBuf;
+
+ sal_uInt8 aOutBuf[ 32768 ];
+ do
+ {
+ aStream.avail_out = sizeof( aOutBuf );
+ aStream.next_out = aOutBuf;
+
+ if( deflate( &aStream, Z_FINISH ) == Z_STREAM_ERROR )
+ {
+ deflateEnd( &aStream );
+ // scrap the data of this broken stream
+ o_rOut.resize( nOrigSize );
+ return 0;
+ }
+
+ // append compressed bytes
+ sal_uInt32 nCompressedBytes = sizeof( aOutBuf ) - aStream.avail_out;
+ if( nCompressedBytes )
+ o_rOut.insert( o_rOut.end(), aOutBuf, aOutBuf+nCompressedBytes );
+
+ } while( aStream.avail_out == 0 );
+
+ // cleanup
+ deflateEnd( &aStream );
+
+ return sal_uInt32( o_rOut.size() - nOrigSize );
+}
+
+void PngHelper::appendFileHeader( OutputBuffer& o_rOutputBuf )
+{
+ static const unsigned char aHeader[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
+
+ o_rOutputBuf.insert( o_rOutputBuf.end(), aHeader, aHeader + SAL_N_ELEMENTS(aHeader) );
+}
+
+size_t PngHelper::startChunk( const char* pChunkName, OutputBuffer& o_rOutputBuf )
+{
+ size_t nIndex = sal_uInt32( o_rOutputBuf.size() );
+ o_rOutputBuf.insert( o_rOutputBuf.end(), 4, Output_t(0) );
+ o_rOutputBuf.push_back( pChunkName[0] );
+ o_rOutputBuf.push_back( pChunkName[1] );
+ o_rOutputBuf.push_back( pChunkName[2] );
+ o_rOutputBuf.push_back( pChunkName[3] );
+ return nIndex;
+}
+
+void PngHelper::set( sal_uInt32 i_nValue, OutputBuffer& o_rOutputBuf, size_t i_nIndex )
+{
+ o_rOutputBuf[ i_nIndex ] = (i_nValue & 0xff000000) >> 24;
+ o_rOutputBuf[ i_nIndex+1 ] = (i_nValue & 0x00ff0000) >> 16;
+ o_rOutputBuf[ i_nIndex+2 ] = (i_nValue & 0x0000ff00) >> 8;
+ o_rOutputBuf[ i_nIndex+3 ] = (i_nValue & 0x000000ff);
+}
+
+void PngHelper::endChunk( size_t nStart, OutputBuffer& o_rOutputBuf )
+{
+ if( nStart+8 > o_rOutputBuf.size() )
+ return; // something broken is going on
+
+ // update chunk length
+ size_t nLen = o_rOutputBuf.size() - nStart;
+ sal_uInt32 nDataLen = sal_uInt32(nLen)-8;
+ set( nDataLen, o_rOutputBuf, nStart );
+
+ // append chunk crc
+ sal_uInt32 nChunkCRC = getCRC( reinterpret_cast<sal_uInt8*>(&o_rOutputBuf[nStart+4]), nLen-4 );
+ append( nChunkCRC, o_rOutputBuf );
+}
+
+void PngHelper::appendIHDR( OutputBuffer& o_rOutputBuf, int width, int height, int depth, int colortype )
+{
+ size_t nStart = startChunk( "IHDR", o_rOutputBuf );
+ append( width, o_rOutputBuf );
+ append( height, o_rOutputBuf );
+ o_rOutputBuf.push_back( Output_t(depth) );
+ o_rOutputBuf.push_back( Output_t(colortype) );
+ o_rOutputBuf.push_back( 0 ); // compression method deflate
+ o_rOutputBuf.push_back( 0 ); // filtering method 0 (default)
+ o_rOutputBuf.push_back( 0 ); // no interlacing
+ endChunk( nStart, o_rOutputBuf );
+}
+
+void PngHelper::appendIEND( OutputBuffer& o_rOutputBuf )
+{
+ size_t nStart = startChunk( "IEND", o_rOutputBuf );
+ endChunk( nStart, o_rOutputBuf );
+}
+
+void PngHelper::createPng( OutputBuffer& o_rOutputBuf,
+ Stream* str,
+ int width,
+ int height,
+ GfxRGB const & zeroColor,
+ GfxRGB const & oneColor,
+ bool bIsMask
+ )
+{
+ appendFileHeader( o_rOutputBuf );
+ appendIHDR( o_rOutputBuf, width, height, 1, 3 );
+
+ // write palette
+ size_t nIdx = startChunk( "PLTE", o_rOutputBuf );
+ // write colors 0 and 1
+ o_rOutputBuf.push_back(colToByte(zeroColor.r));
+ o_rOutputBuf.push_back(colToByte(zeroColor.g));
+ o_rOutputBuf.push_back(colToByte(zeroColor.b));
+ o_rOutputBuf.push_back(colToByte(oneColor.r));
+ o_rOutputBuf.push_back(colToByte(oneColor.g));
+ o_rOutputBuf.push_back(colToByte(oneColor.b));
+ // end PLTE chunk
+ endChunk( nIdx, o_rOutputBuf );
+
+ if( bIsMask )
+ {
+ // write tRNS chunk
+ nIdx = startChunk( "tRNS", o_rOutputBuf );
+ o_rOutputBuf.push_back( 0xff );
+ o_rOutputBuf.push_back( 0 );
+ // end tRNS chunk
+ endChunk( nIdx, o_rOutputBuf );
+ }
+
+ // create scan line data buffer
+ OutputBuffer aScanlines;
+ int nLineSize = (width + 7)/8;
+ aScanlines.reserve( nLineSize * height + height );
+
+ str->reset();
+ for( int y = 0; y < height; y++ )
+ {
+ // determine filter type (none) for this scanline
+ aScanlines.push_back( 0 );
+ for( int x = 0; x < nLineSize; x++ )
+ aScanlines.push_back( str->getChar() );
+ }
+
+ // begin IDAT chunk for scanline data
+ nIdx = startChunk( "IDAT", o_rOutputBuf );
+ // compress scanlines
+ deflateBuffer( aScanlines.data(), aScanlines.size(), o_rOutputBuf );
+ // end IDAT chunk
+ endChunk( nIdx, o_rOutputBuf );
+
+ // output IEND
+ appendIEND( o_rOutputBuf );
+}
+
+void PngHelper::createPng( OutputBuffer& o_rOutputBuf,
+ Stream* str,
+ int width, int height, GfxImageColorMap* colorMap,
+ Stream* maskStr,
+ int maskWidth, int maskHeight, GfxImageColorMap* maskColorMap )
+{
+ appendFileHeader( o_rOutputBuf );
+ appendIHDR( o_rOutputBuf, width, height, 8, 6 ); // RGBA image
+
+ // initialize stream
+ unsigned char *p, *pm;
+ GfxRGB rgb;
+ GfxGray alpha;
+ std::unique_ptr<ImageStream> imgStr(
+ new ImageStream(str,
+ width,
+ colorMap->getNumPixelComps(),
+ colorMap->getBits()));
+ imgStr->reset();
+
+ // create scan line data buffer
+ OutputBuffer aScanlines;
+ aScanlines.reserve( width*height*4 + height );
+
+ for( int y=0; y<height; ++y)
+ {
+ aScanlines.push_back( 0 );
+ p = imgStr->getLine();
+ for( int x=0; x<width; ++x)
+ {
+ colorMap->getRGB(p, &rgb);
+ aScanlines.push_back(colToByte(rgb.r));
+ aScanlines.push_back(colToByte(rgb.g));
+ aScanlines.push_back(colToByte(rgb.b));
+ aScanlines.push_back( 0xff );
+
+ p +=colorMap->getNumPixelComps();
+ }
+ }
+
+
+ // now fill in the mask data
+
+ // CAUTION: originally this was done in one single loop
+ // it caused merry chaos; the reason is that maskStr and str are
+ // not independent streams, it happens that reading one advances
+ // the other, too. Hence the two passes are imperative !
+
+ // initialize mask stream
+ std::unique_ptr<ImageStream> imgStrMask(
+ new ImageStream(maskStr,
+ maskWidth,
+ maskColorMap->getNumPixelComps(),
+ maskColorMap->getBits()));
+
+ imgStrMask->reset();
+ for( int y = 0; y < maskHeight; ++y )
+ {
+ pm = imgStrMask->getLine();
+ for( int x = 0; x < maskWidth; ++x )
+ {
+ maskColorMap->getGray(pm,&alpha);
+ pm += maskColorMap->getNumPixelComps();
+ int nIndex = (y*height/maskHeight) * (width*4+1) + // mapped line
+ (x*width/maskWidth)*4 + 1 + 3 // mapped column
+ ;
+ aScanlines[ nIndex ] = colToByte(alpha);
+ }
+ }
+
+ imgStr.reset();
+ imgStrMask.reset();
+
+ // begind IDAT chunk for scanline data
+ size_t nIdx = startChunk( "IDAT", o_rOutputBuf );
+ // compress scanlines
+ deflateBuffer( aScanlines.data(), aScanlines.size(), o_rOutputBuf );
+ // end IDAT chunk
+ endChunk( nIdx, o_rOutputBuf );
+ // output IEND
+ appendIEND( o_rOutputBuf );
+}
+
+// one bit mask; 0 bits opaque
+void PngHelper::createPng( OutputBuffer& o_rOutputBuf,
+ Stream* str,
+ int width, int height, GfxImageColorMap* colorMap,
+ Stream* maskStr,
+ int maskWidth, int maskHeight,
+ bool maskInvert
+ )
+{
+ appendFileHeader( o_rOutputBuf );
+ appendIHDR( o_rOutputBuf, width, height, 8, 6 ); // RGBA image
+
+ // initialize stream
+ unsigned char *p;
+ GfxRGB rgb;
+ std::unique_ptr<ImageStream> imgStr(
+ new ImageStream(str,
+ width,
+ colorMap->getNumPixelComps(),
+ colorMap->getBits()));
+ imgStr->reset();
+
+ // create scan line data buffer
+ OutputBuffer aScanlines;
+ aScanlines.reserve( width*height*4 + height );
+
+ for( int y=0; y<height; ++y)
+ {
+ aScanlines.push_back( 0 );
+ p = imgStr->getLine();
+ for( int x=0; x<width; ++x)
+ {
+ colorMap->getRGB(p, &rgb);
+ aScanlines.push_back(colToByte(rgb.r));
+ aScanlines.push_back(colToByte(rgb.g));
+ aScanlines.push_back(colToByte(rgb.b));
+ aScanlines.push_back( 0xff );
+
+ p +=colorMap->getNumPixelComps();
+ }
+ }
+
+
+ // now fill in the mask data
+
+ // CAUTION: originally this was done in one single loop
+ // it caused merry chaos; the reason is that maskStr and str are
+ // not independent streams, it happens that reading one advances
+ // the other, too. Hence the two passes are imperative !
+
+ // initialize mask stream
+ std::unique_ptr<ImageStream> imgStrMask(
+ new ImageStream(maskStr, maskWidth, 1, 1));
+
+ imgStrMask->reset();
+ for( int y = 0; y < maskHeight; ++y )
+ {
+ for( int x = 0; x < maskWidth; ++x )
+ {
+ unsigned char aPixel = 0;
+ imgStrMask->getPixel( &aPixel );
+ int nIndex = (y*height/maskHeight) * (width*4+1) + // mapped line
+ (x*width/maskWidth)*4 + 1 + 3 // mapped column
+ ;
+ if( maskInvert )
+ aScanlines[ nIndex ] = aPixel ? 0xff : 0x00;
+ else
+ aScanlines[ nIndex ] = aPixel ? 0x00 : 0xff;
+ }
+ }
+
+ imgStr.reset();
+ imgStrMask.reset();
+
+ // begind IDAT chunk for scanline data
+ size_t nIdx = startChunk( "IDAT", o_rOutputBuf );
+ // compress scanlines
+ deflateBuffer( aScanlines.data(), aScanlines.size(), o_rOutputBuf );
+ // end IDAT chunk
+ endChunk( nIdx, o_rOutputBuf );
+ // output IEND
+ appendIEND( o_rOutputBuf );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sdext/source/pdfimport/xpdfwrapper/pnghelper.hxx b/sdext/source/pdfimport/xpdfwrapper/pnghelper.hxx
new file mode 100644
index 000000000..e0f2ea98b
--- /dev/null
+++ b/sdext/source/pdfimport/xpdfwrapper/pnghelper.hxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SDEXT_SOURCE_PDFIMPORT_XPDFWRAPPER_PNGHELPER_HXX
+#define INCLUDED_SDEXT_SOURCE_PDFIMPORT_XPDFWRAPPER_PNGHELPER_HXX
+
+#include <sal/types.h>
+#include "pdfioutdev_gpl.hxx"
+
+
+namespace pdfi
+{
+ class PngHelper
+ {
+ static sal_uInt32 crc_table[ 256 ];
+ static bool bCRCTableInit;
+
+ static void initCRCTable();
+ static void appendFileHeader( OutputBuffer& o_rOutputBuf );
+ static size_t startChunk( const char* pChunkName, OutputBuffer& o_rOut );
+ static void endChunk( size_t nStart, OutputBuffer& o_rOut );
+
+ static void set( sal_uInt32 i_nValue, OutputBuffer& o_rOutputBuf, size_t i_nIndex );
+ static void append( sal_uInt32 i_nValue, OutputBuffer& o_rOutputBuf )
+ {
+ size_t nCur = o_rOutputBuf.size();
+ o_rOutputBuf.insert( o_rOutputBuf.end(), 4, Output_t(0) );
+ set( i_nValue, o_rOutputBuf, nCur );
+ }
+
+ static void appendIHDR( OutputBuffer& o_rOutputBuf, int width, int height, int depth, int colortype );
+ static void appendIEND( OutputBuffer& o_rOutputBuf );
+
+ public:
+ static void updateCRC( sal_uInt32& io_rCRC, const sal_uInt8* i_pBuf, size_t i_nLen );
+ static sal_uInt32 getCRC( const sal_uInt8* i_pBuf, size_t i_nLen );
+
+ // deflates the passed buff i_pBuf and appends it to the output vector
+ // returns the number of bytes added to the output
+ static sal_uInt32 deflateBuffer( const Output_t* i_pBuf, size_t i_nLen, OutputBuffer& o_rOut );
+
+ static void createPng( OutputBuffer& o_rOutputBuf,
+ Stream* str,
+ int width,
+ int height,
+ GfxRGB const & zeroColor,
+ GfxRGB const & oneColor,
+ bool bIsMask
+ );
+ static void createPng( OutputBuffer& o_rOutputBuf,
+ Stream* str,
+ int width, int height, GfxImageColorMap* colorMap,
+ Stream* maskStr,
+ int maskWidth, int maskHeight, GfxImageColorMap* maskColorMap );
+
+ // for one bit masks
+ static void createPng( OutputBuffer& o_rOutputBuf,
+ Stream* str,
+ int width, int height, GfxImageColorMap* colorMap,
+ Stream* maskStr,
+ int maskWidth, int maskHeight, bool maskInvert );
+
+ };
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sdext/source/pdfimport/xpdfwrapper/wrapper_gpl.cxx b/sdext/source/pdfimport/xpdfwrapper/wrapper_gpl.cxx
new file mode 100644
index 000000000..e924547e9
--- /dev/null
+++ b/sdext/source/pdfimport/xpdfwrapper/wrapper_gpl.cxx
@@ -0,0 +1,188 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "pdfioutdev_gpl.hxx"
+#ifdef _WIN32
+# include <io.h>
+# include <fcntl.h> /*_O_BINARY*/
+#endif
+#ifndef SYSTEM_POPPLER
+#include <string> // std::string
+#include <cstddef> // std::size_t
+#include <config_folders.h> //LIBO_SHARE_FOLDER
+#endif
+
+FILE* g_binary_out=stderr;
+
+static const char *ownerPassword = "\001";
+static const char *userPassword = "\001";
+static const char *outputFile = "\001";
+static const char *options = "\001";
+
+int main(int argc, char **argv)
+{
+ int k = 0;
+ while (k < argc)
+ {
+ if (!strcmp(argv[k], "-f"))
+ {
+ outputFile = argv[k+1];
+ argc -= 2;
+ for (int j = k; j < argc; ++j)
+ argv[j] = argv[j+2];
+ }
+ else if (!strcmp(argv[k], "-o"))
+ {
+ options = argv[k+1];
+ argc -= 2;
+ for (int j = k; j < argc; ++j)
+ argv[j] = argv[j+2];
+ }
+
+ else if (!strcmp(argv[k], "-opw"))
+ {
+ ownerPassword = argv[k+1];
+ argc -= 2;
+ for (int j = k; j < argc; ++j)
+ argv[j] = argv[j+2];
+ }
+ else if (!strcmp(argv[k], "-upw"))
+ {
+ userPassword = argv[k+1];
+ argc -= 2;
+ for (int j = k; j < argc; ++j)
+ argv[j] = argv[j+2];
+ }
+ ++k;
+ }
+
+ /* Get data directory location */
+#ifdef SYSTEM_POPPLER
+ const char* datadir = nullptr;
+#else
+ /* Creates an absolute path to the poppler_data directory, by taking the path
+ * to the xpdfimport executable (provided in argv[0], and concatenating a
+ * relative path to the poppler_data directory from the program directory. */
+ const std::string execPath = argv[0];
+ const std::size_t filenameStartPos = execPath.find_last_of("/\\")+1;
+ const std::string programPath = execPath.substr(0,filenameStartPos);
+ const std::string popplerDataPath = programPath + "../" LIBO_SHARE_FOLDER "/xpdfimport/poppler_data";
+ const char* datadir = popplerDataPath.c_str();
+#endif
+
+ // read config file
+#if POPPLER_CHECK_VERSION(0, 83, 0)
+ globalParams = std::make_unique<GlobalParams>(datadir);
+#else
+ globalParams = new GlobalParams(datadir);
+#endif
+ globalParams->setErrQuiet(true);
+#if defined(_MSC_VER)
+ globalParams->setupBaseFonts(nullptr);
+#endif
+
+ // try to read a possible open password from stdin
+ char aPwBuf[129];
+ aPwBuf[128] = 0;
+ if( ! fgets( aPwBuf, sizeof(aPwBuf)-1, stdin ) )
+ aPwBuf[0] = 0; // mark as empty
+ else
+ {
+ for( size_t i = 0; i < sizeof(aPwBuf); i++ )
+ {
+ if( aPwBuf[i] == '\n' )
+ {
+ aPwBuf[i] = 0;
+ break;
+ }
+ }
+ }
+
+ // PDFDoc takes over ownership for all strings below
+ GooString* pFileName = new GooString(argv[1]);
+ GooString* pErrFileName = new GooString(argv[2]);
+
+ // check for password string(s)
+ GooString* pOwnerPasswordStr( aPwBuf[0] != 0
+ ? new GooString( aPwBuf )
+ : (ownerPassword[0] != '\001'
+ ? new GooString(ownerPassword)
+ : nullptr ) );
+ GooString* pUserPasswordStr( aPwBuf[0] != 0
+ ? new GooString( aPwBuf )
+ : (userPassword[0] != '\001'
+ ? new GooString(userPassword)
+ : nullptr ) );
+ if( outputFile[0] != '\001' )
+ g_binary_out = fopen(outputFile,"wb");
+
+#ifdef _WIN32
+ // Win actually modifies output for O_TEXT file mode, so need to
+ // revert to binary here
+ _setmode( _fileno( g_binary_out ), _O_BINARY );
+#endif
+
+#if POPPLER_CHECK_VERSION(22, 6, 0)
+ PDFDoc aDoc( std::make_unique<GooString>(pFileName),
+ std::optional<GooString>(pOwnerPasswordStr),
+ std::optional<GooString>(pUserPasswordStr) );
+
+ PDFDoc aErrDoc( std::make_unique<GooString>(pErrFileName),
+ std::optional<GooString>(pOwnerPasswordStr),
+ std::optional<GooString>(pUserPasswordStr) );
+#else
+ PDFDoc aDoc( pFileName,
+ pOwnerPasswordStr,
+ pUserPasswordStr );
+
+ PDFDoc aErrDoc( pErrFileName,
+ pOwnerPasswordStr,
+ pUserPasswordStr );
+#endif
+
+ // Check various permissions for aDoc.
+ PDFDoc &rDoc = aDoc.isOk()? aDoc: aErrDoc;
+
+ pdfi::PDFOutDev aOutDev(&rDoc);
+ if (!strcmp(options, "SkipImages")) {
+ aOutDev.setSkipImages(true);
+ }
+
+ // tell the receiver early - needed for proper progress calculation
+ const int nPages = rDoc.isOk()? rDoc.getNumPages(): 0;
+ pdfi::PDFOutDev::setPageNum(nPages);
+
+ // virtual resolution of the PDF OutputDev in dpi
+ static const int PDFI_OUTDEV_RESOLUTION = 7200;
+
+ // do the conversion
+ for (int i = 1; i <= nPages; ++i)
+ {
+ rDoc.displayPage(&aOutDev,
+ i,
+ PDFI_OUTDEV_RESOLUTION,
+ PDFI_OUTDEV_RESOLUTION,
+ 0, true, true, true);
+ rDoc.processLinks(&aOutDev, i);
+ }
+
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */