diff options
Diffstat (limited to 'sdext/source/pdfimport/xpdfwrapper')
-rw-r--r-- | sdext/source/pdfimport/xpdfwrapper/makefile.mk | 82 | ||||
-rw-r--r-- | sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.cxx | 935 | ||||
-rw-r--r-- | sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.hxx | 299 | ||||
-rw-r--r-- | sdext/source/pdfimport/xpdfwrapper/pnghelper.cxx | 419 | ||||
-rw-r--r-- | sdext/source/pdfimport/xpdfwrapper/pnghelper.hxx | 95 | ||||
-rw-r--r-- | sdext/source/pdfimport/xpdfwrapper/wrapper_gpl.cxx | 210 |
6 files changed, 2040 insertions, 0 deletions
diff --git a/sdext/source/pdfimport/xpdfwrapper/makefile.mk b/sdext/source/pdfimport/xpdfwrapper/makefile.mk new file mode 100644 index 000000000000..0d74baf215fa --- /dev/null +++ b/sdext/source/pdfimport/xpdfwrapper/makefile.mk @@ -0,0 +1,82 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=sdext +TARGET=xpdfimport +TARGETTYPE=CUI +ENABLE_EXCEPTIONS=TRUE +EXTERNAL_WARNINGS_NOT_ERRORS := TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE: settings.mk + +.IF "$(SYSTEM_ZLIB)" == "YES" +CFLAGS+=-DSYSTEM_ZLIB +.ENDIF + +.IF "$(ENABLE_PDFIMPORT)" == "NO" +@all: + @echo "PDF Import extension disabled." +.ENDIF + +.IF "$(SYSTEM_POPPLER)" == "YES" +CFLAGS += $(POPPLER_CFLAGS) -DSYSTEM_POPPLER +.ELSE +CFLAGS += -I$(SOLARINCDIR)$/xpdf +.ENDIF + +# --- Files -------------------------------------------------------- +UWINAPILIB:= +APP1TARGET=$(TARGET) +APP1LIBSALCPPRT= +APP1OBJS= \ + $(OBJ)$/wrapper_gpl.obj $(OBJ)/pdfioutdev_gpl.obj $(OBJ)/pnghelper.obj + +APP1STDLIBS+=$(ZLIB3RDLIB) + +.IF "$(SYSTEM_POPPLER)" == "YES" +APP1STDLIBS+=$(POPPLER_LIBS) +.ELSE +.IF "$(GUI)" == "WNT" +.IF "$(COM)"=="GCC" +APP1STDLIBS+=-lxpdf -lfofi -lGoo -lgdi32 -ladvapi32 +.ELSE +APP1STDLIBS+=xpdf.lib fofi.lib Goo.lib gdi32.lib advapi32.lib +.ENDIF +.ELSE +.IF "$(OS)" == "MACOSX" && "$(GUIBASE)"=="unx" +APP1STDLIBS+=-lobjc +.ENDIF +APP1STDLIBS+=-lxpdf -lfofi -lGoo +.ENDIF +.ENDIF +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.cxx b/sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.cxx new file mode 100644 index 000000000000..cf28922d2e7d --- /dev/null +++ b/sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.cxx @@ -0,0 +1,935 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * The Contents of this file are made available subject to + * the terms of GNU General Public License Version 2. + * + * + * GNU General Public License, version 2 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + ************************************************************************/ + +#include "pdfioutdev_gpl.hxx" +#include "pnghelper.hxx" + +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <math.h> +#include <vector> + +#include <boost/shared_array.hpp> + +#if defined __SUNPRO_CC +#pragma disable_warn +#elif defined _MSC_VER +#pragma warning(push, 1) +#endif + +#include "UTF8.h" + +#if defined __SUNPRO_CC +#pragma enable_warn +#elif defined _MSC_VER +#pragma warning(pop) +#endif + +#ifdef WNT +# define snprintf _snprintf +#endif + + +/* SYNC STREAMS + ============ + + We stream human-readble 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 +inline double normalize( double val ) +{ + return fabs(val) < 0.0000001 ? 0.0 : val; +} + +namespace +{ + +/** Escapes line-ending characters (\n and \r) in input string. + */ +boost::shared_array<char> lcl_escapeLineFeeds(const char* const i_pStr) +{ + size_t nLength(strlen(i_pStr)); + char* pBuffer = new char[2*nLength+1]; + + const char* pRead = i_pStr; + char* pWrite = pBuffer; + while( nLength-- ) + { + if( *pRead == '\r' ) + { + *pWrite++ = '\\'; + *pWrite++ = 'r'; + } + else if( *pRead == '\n' ) + { + *pWrite++ = '\\'; + *pWrite++ = 'n'; + } + else if( *pRead == '\\' ) + { + *pWrite++ = '\\'; + *pWrite++ = '\\'; + } + else + *pWrite++ = *pRead; + pRead++; + } + *pWrite++ = 0; + + return boost::shared_array<char>(pBuffer); +} + +} + +/// 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) + +void initBuf(OutputBuffer& io_rBuffer) +{ + io_rBuffer.reserve(WRITE_BUFFER_INITIAL_CAPACITY); +} + +void writeBinaryBuffer( const OutputBuffer& rBuffer ) +{ + // ---sync point--- see SYNC STREAMS above + fflush(stdout); + + // put buffer to stderr + if( !rBuffer.empty() ) + if( fwrite(&rBuffer[0], sizeof(char), + rBuffer.size(), g_binary_out) != (size_t)rBuffer.size() ) + exit(1); // error + + // ---sync point--- see SYNC STREAMS above + fflush(g_binary_out); +} + +void writeJpeg_( OutputBuffer& o_rOutputBuf, Stream* str, bool bWithLinefeed ) +{ + // dump JPEG file as-is + str = ((DCTStream *)str)->getRawStream(); + str->reset(); + + int c; + o_rOutputBuf.clear(); + while((c=str->getChar()) != EOF) + o_rOutputBuf.push_back(static_cast<char>(c)); + + printf( " JPEG %d", (int)o_rOutputBuf.size() ); + if( bWithLinefeed ) + printf("\n"); + + str->close(); +} + +void writePbm_(OutputBuffer& o_rOutputBuf, Stream* str, int width, int height, bool bWithLinefeed, 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; + int nOutLen = snprintf(&o_rOutputBuf[3], 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 ); + if( bWithLinefeed ) + 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(); +} + +void writePpm_( OutputBuffer& o_rOutputBuf, + Stream* str, + int width, + int height, + GfxImageColorMap* colorMap, + bool bWithLinefeed ) +{ + // 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'; + int nOutLen = snprintf(&o_rOutputBuf[3], 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 ); + if( bWithLinefeed ) + printf("\n"); + + // trim buffer to exact header size + o_rOutputBuf.resize(header_size); + + // initialize stream + Guchar *p; + GfxRGB rgb; + 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(); + } + } + + delete imgStr; + +} + +// call this only for 1 bit image streams ! +void writePng_( OutputBuffer& o_rOutputBuf, + Stream* str, + int width, + int height, + GfxRGB& zeroColor, + GfxRGB& oneColor, + bool bIsMask, + bool bWithLinefeed ) +{ + o_rOutputBuf.clear(); + + // get png image + PngHelper::createPng( o_rOutputBuf, str, width, height, zeroColor, oneColor, bIsMask ); + + printf( " PNG %d", (int)o_rOutputBuf.size() ); + if( bWithLinefeed ) + printf("\n"); +} + +void writePng_( OutputBuffer& o_rOutputBuf, + Stream* str, + int width, int height, GfxImageColorMap* colorMap, + Stream* maskStr, + int maskWidth, int maskHeight, GfxImageColorMap* maskColorMap, + bool bWithLinefeed ) +{ + o_rOutputBuf.clear(); + + // get png image + PngHelper::createPng( o_rOutputBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap ); + + printf( " PNG %d", (int)o_rOutputBuf.size() ); + if( bWithLinefeed ) + printf("\n"); +} + +void writePng_( OutputBuffer& o_rOutputBuf, + Stream* str, + int width, int height, GfxImageColorMap* colorMap, + Stream* maskStr, + int maskWidth, int maskHeight, bool maskInvert, + bool bWithLinefeed ) +{ + o_rOutputBuf.clear(); + + // get png image + PngHelper::createPng( o_rOutputBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert ); + + printf( " PNG %d", (int)o_rOutputBuf.size() ); + if( bWithLinefeed ) + printf("\n"); +} + +// stolen from ImageOutputDev.cc +void writeMask_( OutputBuffer& o_rOutputBuf, Stream* str, int width, int height, bool bWithLinefeed, bool bInvert ) +{ + if( str->getKind() == strDCT ) + writeJpeg_(o_rOutputBuf, str, bWithLinefeed); + else + writePbm_(o_rOutputBuf, str, width, height, bWithLinefeed, bInvert ); +} + +void writeImage_( OutputBuffer& o_rOutputBuf, + Stream* str, + int width, + int height, + GfxImageColorMap* colorMap, + bool bWithLinefeed ) +{ + // dump JPEG file + if( str->getKind() == strDCT && + (colorMap->getNumPixelComps() == 1 || + colorMap->getNumPixelComps() == 3) ) + { + writeJpeg_(o_rOutputBuf, str, bWithLinefeed); + } + 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 ) + { + Guchar nIndex = 0; + colorMap->getRGB( &nIndex, &zeroColor ); + nIndex = 1; + colorMap->getRGB( &nIndex, &oneColor ); + } + writePng_( o_rOutputBuf, str, width, height, zeroColor, oneColor, false, bWithLinefeed ); + } + else + writePpm_( o_rOutputBuf, str, width, height, colorMap, bWithLinefeed ); +} + +// forwarders +// ------------------------------------------------------------------ + +inline void writeImage( OutputBuffer& o_rOutputBuf, + Stream* str, + int width, + int height, + GfxImageColorMap* colorMap ) { writeImage_(o_rOutputBuf,str,width,height,colorMap,false); } +inline void writeImageLF( OutputBuffer& o_rOutputBuf, + Stream* str, + int width, + int height, + GfxImageColorMap* colorMap ) { writeImage_(o_rOutputBuf,str,width,height,colorMap,true); } +inline void writeMask( OutputBuffer& o_rOutputBuf, + Stream* str, + int width, + int height, + bool bInvert ) { writeMask_(o_rOutputBuf,str,width,height,false,bInvert); } +inline void writeMaskLF( OutputBuffer& o_rOutputBuf, + Stream* str, + int width, + int height, + bool bInvert ) { writeMask_(o_rOutputBuf,str,width,height,true,bInvert); } + +// ------------------------------------------------------------------ + + +int PDFOutDev::parseFont( long long nNewId, GfxFont* gfxFont, GfxState* state ) const +{ + FontAttributes aNewFont; + int nSize = 0; + + GooString* pFamily = gfxFont->getName(); + if( ! pFamily ) + pFamily = gfxFont->getOrigName(); + if( pFamily ) + { + aNewFont.familyName.clear(); + aNewFont.familyName.append( gfxFont->getName() ); + } + else + { + aNewFont.familyName.clear(); + aNewFont.familyName.append( "Arial" ); + } + + aNewFont.isBold = gfxFont->isBold(); + aNewFont.isItalic = gfxFont->isItalic(); + aNewFont.size = state->getTransformedFontSize(); + 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 + char* pBuf = gfxFont->readEmbFontFile( m_pDoc->getXRef(), &nSize ); + if( pBuf ) + aNewFont.isEmbedded = true; + } + + m_aFontMap[ nNewId ] = aNewFont; + return nSize; +} + +void PDFOutDev::writeFontFile( GfxFont* gfxFont ) const +{ + if( gfxFont->getType() != fontTrueType && gfxFont->getType() != fontType1 ) + return; + + int nSize = 0; + char* pBuf = gfxFont->readEmbFontFile( m_pDoc->getXRef(), &nSize ); + if( !pBuf ) + return; + + // ---sync point--- see SYNC STREAMS above + fflush(stdout); + + if( fwrite(pBuf, sizeof(char), nSize, g_binary_out) != (size_t)nSize ) + exit(1); // error + + // ---sync point--- see SYNC STREAMS above + fflush(g_binary_out); +} + +void PDFOutDev::printPath( GfxPath* pPath ) const +{ + int nSubPaths = pPath ? pPath->getNumSubpaths() : 0; + for( int i=0; i<nSubPaths; i++ ) + { + 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_aFontMap(), + m_pUtf8Map( new UnicodeMap((char*)"UTF-8", gTrue, &mapUTF8) ) +{ +} + +void PDFOutDev::startPage(int /*pageNum*/, GfxState* state) +{ + assert(state); + printf("startPage %f %f\n", + normalize(state->getPageWidth()), + normalize(state->getPageHeight())); +} + +void PDFOutDev::endPage() +{ + printf("endPage\n"); +} + +#if POPPLER_CHECK_VERSION(0, 17, 0) +void PDFOutDev::processLink(AnnotLink *link, Catalog *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->getKind() == actionURI ) + { + const char* pURI = static_cast<LinkURI*>(pAction)->getURI()->getCString(); + + boost::shared_array<char> pEsc( lcl_escapeLineFeeds(pURI) ); + + printf( "drawLink %f %f %f %f %s\n", + normalize(x1), + normalize(y1), + normalize(x2), + normalize(y2), + pEsc.get() ); + } +} + +void PDFOutDev::saveState(GfxState*) +{ + printf( "saveState\n" ); +} + +void PDFOutDev::restoreState(GfxState*) +{ + printf( "restoreState\n" ); +} + +void PDFOutDev::setDefaultCTM(double *pMat) +{ + assert(pMat); + + OutputDev::setDefaultCTM(pMat); + + printf( "updateCtm %f %f %f %f %f %f\n", + normalize(pMat[0]), + normalize(pMat[2]), + normalize(pMat[1]), + 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[2]), + normalize(pMat[1]), + normalize(pMat[3]), + normalize(pMat[4]), + normalize(pMat[5]) ); +} + +void PDFOutDev::updateLineDash(GfxState *state) +{ + assert(state); + + double* dashArray; int arrayLen; double startOffset; + state->getLineDash(&dashArray, &arrayLen, &startOffset); + + 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) +{ + assert(state); + printf( "updateFlatness %d\n", state->getFlatness() ); +} + +void PDFOutDev::updateLineJoin(GfxState *state) +{ + assert(state); + printf( "updateLineJoin %d\n", state->getLineJoin() ); +} + +void PDFOutDev::updateLineCap(GfxState *state) +{ + assert(state); + printf( "updateLineCap %d\n", state->getLineCap() ); +} + +void PDFOutDev::updateMiterLimit(GfxState *state) +{ + assert(state); + printf( "updateMiterLimit %f\n", normalize(state->getMiterLimit()) ); +} + +void PDFOutDev::updateLineWidth(GfxState *state) +{ + assert(state); + printf( "updateLineWidth %f\n", normalize(state->getLineWidth()) ); +} + +void PDFOutDev::updateFillColor(GfxState *state) +{ + 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) +{ + 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) +{ + updateFillColor(state); +} + +void PDFOutDev::updateStrokeOpacity(GfxState *state) +{ + updateStrokeColor(state); +} + +void PDFOutDev::updateBlendMode(GfxState*) +{ +} + +void PDFOutDev::updateFont(GfxState *state) +{ + assert(state); + + GfxFont *gfxFont = state->getFont(); + if( gfxFont ) + { + FontAttributes aFont; + int nEmbedSize=0; + + Ref* pID = gfxFont->getID(); + // TODO(Q3): Portability problem + long long fontID = (long long)pID->gen << 32 | (long long)pID->num; + boost::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; + + boost::shared_array<char> pEsc( lcl_escapeLineFeeds(aFont.familyName.getCString()) ); + printf( " %d %d %d %d %f %d %s", + aFont.isEmbedded, + aFont.isBold, + aFont.isItalic, + aFont.isUnderline, + normalize(state->getTransformedFontSize()), + nEmbedSize, + pEsc.get() ); + } + printf( "\n" ); + + if( nEmbedSize ) + writeFontFile(gfxFont); + } +} + +void PDFOutDev::updateRender(GfxState *state) +{ + assert(state); + + printf( "setTextRenderMode %d\n", state->getRender() ); +} + +void PDFOutDev::stroke(GfxState *state) +{ + assert(state); + + printf( "strokePath" ); + printPath( state->getPath() ); + printf( "\n" ); +} + +void PDFOutDev::fill(GfxState *state) +{ + assert(state); + + printf( "fillPath" ); + printPath( state->getPath() ); + printf( "\n" ); +} + +void PDFOutDev::eoFill(GfxState *state) +{ + assert(state); + + printf( "eoFillPath" ); + printPath( state->getPath() ); + printf( "\n" ); +} + +void PDFOutDev::clip(GfxState *state) +{ + assert(state); + + printf( "clipPath" ); + printPath( state->getPath() ); + printf( "\n" ); +} + +void PDFOutDev::eoClip(GfxState *state) +{ + 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. + */ +void PDFOutDev::drawChar(GfxState *state, double x, double y, + double dx, double dy, + double originX, double originY, + CharCode, int /*nBytes*/, Unicode *u, int uLen) +{ + assert(state); + + if( u == NULL ) + return; + + // normalize coordinates: correct from baseline-relative to upper + // left corner of glyphs + double x2(0.0), y2(0.0); + state->textTransformDelta( 0.0, + state->getFont()->getAscent(), + &x2, &y2 ); + const double fFontSize(state->getFontSize()); + x += x2*fFontSize; + y += y2*fFontSize; + + const double aPositionX(x-originX); + const double aPositionY(y-originY); + // TODO(F2): use leading here, when set + const double nWidth(dx != 0.0 ? dx : fFontSize); + const double nHeight(dy != 0.0 ? dy : fFontSize); + + const double* pTextMat=state->getTextMat(); + printf( "drawChar %f %f %f %f %f %f %f %f ", + normalize(aPositionX), + normalize(aPositionY), + normalize(aPositionX+nWidth), + normalize(aPositionY-nHeight), + normalize(pTextMat[0]), + normalize(pTextMat[2]), + normalize(pTextMat[1]), + normalize(pTextMat[3]) ); + + // silence spurious warning + (void)&mapUCS2; + + char buf[9]; + for( int i=0; i<uLen; ++i ) + { + buf[ m_pUtf8Map->mapUnicode(u[i], buf, sizeof(buf)-1) ] = 0; + boost::shared_array<char> pEsc( lcl_escapeLineFeeds(buf) ); + printf( "%s", pEsc.get() ); + } + + printf( "\n" ); +} + +void PDFOutDev::drawString(GfxState*, GooString* /*s*/) +{ + // TODO(F3): NYI +} + +void PDFOutDev::endTextObject(GfxState*) +{ + printf( "endTextObject\n" ); +} + +void PDFOutDev::drawImageMask(GfxState* pState, Object*, Stream* str, + int width, int height, GBool invert, + GBool /*inlineImg*/ ) +{ + 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, true ); + else + writePng_( aBuf, str, width, height, zeroColor, oneColor, true, true ); + } + else + writeMaskLF(aBuf, str, width, height, invert != 0); + writeBinaryBuffer(aBuf); +} + +void PDFOutDev::drawImage(GfxState*, Object*, Stream* str, + int width, int height, GfxImageColorMap* colorMap, + int* maskColors, GBool /*inlineImg*/ ) +{ + 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( (char)maskColors[0] ); + aMaskBuf.push_back( (char)maskColors[gfxColorMaxComps] ); + } + else + { + GfxRGB aMinRGB; + colorMap->getColorSpace()->getRGB( + (GfxColor*)maskColors, + &aMinRGB ); + + GfxRGB aMaxRGB; + colorMap->getColorSpace()->getRGB( + (GfxColor*)maskColors+gfxColorMaxComps, + &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", (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, + Stream* maskStr, + int maskWidth, int maskHeight, + GBool maskInvert) +{ + OutputBuffer aBuf; initBuf(aBuf); + printf( "drawImage %d %d 0", width, height ); + writePng_( aBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert, true ); + writeBinaryBuffer( aBuf ); +} + +void PDFOutDev::drawSoftMaskedImage(GfxState*, Object*, Stream* str, + int width, int height, + GfxImageColorMap* colorMap, + Stream* maskStr, + int maskWidth, int maskHeight, + GfxImageColorMap* maskColorMap ) +{ + OutputBuffer aBuf; initBuf(aBuf); + printf( "drawImage %d %d 0", width, height ); + writePng_( aBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap, true ); + writeBinaryBuffer( aBuf ); +} + +void PDFOutDev::setPageNum( int nNumPages ) +{ + // TODO(F3): printf might format int locale-dependent! + printf("setPageNum %d\n", nNumPages); +} + +} + +/* 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 000000000000..2a35fb7faaae --- /dev/null +++ b/sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.hxx @@ -0,0 +1,299 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * The Contents of this file are made available subject to + * the terms of GNU General Public License Version 2. + * + * + * GNU General Public License, version 2 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + ************************************************************************/ + +#ifndef INCLUDED_PDFI_OUTDEV_HXX +#define INCLUDED_PDFI_OUTDEV_HXX + +#if defined __GNUC__ +#pragma GCC system_header +#elif defined __SUNPRO_CC +#pragma disable_warn +#elif defined _MSC_VER +#pragma warning(push, 1) +#endif + +#include "GfxState.h" +#include "GfxFont.h" +#include "UnicodeMap.h" +#include "Link.h" +#include "Object.h" +#include "OutputDev.h" +#ifndef SYSTEM_POPPLER +# include "parseargs.h" +#endif +#include "GlobalParams.h" +#include "PDFDoc.h" + +#if defined __SUNPRO_CC +#pragma enable_warn +#elif defined _MSC_VER +#pragma warning(pop) +#endif + +#include <boost/unordered_map.hpp> +#include <vector> + +class GfxPath; +class GfxFont; +class PDFDoc; +#ifndef SYSTEM_POPPLER +#define POPPLER_CHECK_VERSION(major,minor,micro) (0) +typedef GString GooString; +#else +#include <glib/poppler-features.h> +#endif + +namespace pdfi +{ + struct FontAttributes + { + FontAttributes( const GooString& familyName_, + bool isEmbedded_, + bool isBold_, + bool isItalic_, + bool isUnderline_, + double size_ ) : + familyName(), + isEmbedded(isEmbedded_), + isBold(isBold_), + isItalic(isItalic_), + isUnderline(isUnderline_), + size(size_) + { + familyName.append(const_cast<GooString*>(&familyName_)); + } + + FontAttributes() : + familyName(), + isEmbedded(false), + isBold(false), + isItalic(false), + isUnderline(false), + size(0.0) + {} + + // xdpf goo stuff is so totally borked... + // ...need to hand-code assignment + FontAttributes( const FontAttributes& rSrc ) : + familyName(), + isEmbedded(rSrc.isEmbedded), + isBold(rSrc.isBold), + isItalic(rSrc.isItalic), + isUnderline(rSrc.isUnderline), + size(rSrc.size) + { + familyName.append(const_cast<GooString*>(&rSrc.familyName)); + } + + FontAttributes& operator=( const FontAttributes& rSrc ) + { + familyName.clear(); + familyName.append(const_cast<GooString*>(&rSrc.familyName)); + + isEmbedded = rSrc.isEmbedded; + isBold = rSrc.isBold; + isItalic = rSrc.isItalic; + isUnderline = rSrc.isUnderline; + size = rSrc.size; + + return *this; + } + + bool operator==(const FontAttributes& rFont) const + { + return const_cast<GooString*>(&familyName)->cmp( + const_cast<GooString*>(&rFont.familyName))==0 && + isEmbedded == rFont.isEmbedded && + isBold == rFont.isBold && + isItalic == rFont.isItalic && + isUnderline == rFont.isUnderline && + size == rFont.size; + } + + GooString familyName; + bool isEmbedded; + bool isBold; + bool isItalic; + bool isUnderline; + double size; + }; + + class PDFOutDev : public OutputDev + { + // not owned by this class + PDFDoc* m_pDoc; + mutable boost::unordered_map< long long, + FontAttributes > m_aFontMap; + UnicodeMap* m_pUtf8Map; + + int parseFont( long long nNewId, GfxFont* pFont, GfxState* state ) const; + void writeFontFile( GfxFont* gfxFont ) const; + void printPath( GfxPath* pPath ) const; + + public: + explicit PDFOutDev( PDFDoc* pDoc ); + + //----- 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 GBool upsideDown() { return gTrue; } + + // Does this device use drawChar() or drawString()? + virtual GBool useDrawChar() { return gTrue; } + + // Does this device use beginType3Char/endType3Char? Otherwise, + // text in Type 3 fonts will be drawn with drawChar/drawString. + virtual GBool interpretType3Chars() { return gFalse; } + + // Does this device need non-text content? + virtual GBool needNonText() { return gTrue; } + + //----- initialization and control + + // Set default transform matrix. + virtual void setDefaultCTM(double *ctm); + + // Start a page. + virtual void startPage(int pageNum, GfxState *state); + + // End a page. + virtual void endPage(); + + // Dump page contents to display. + // virtual void dump() {} + + //----- coordinate conversion + + // Convert between device and user coordinates. + // virtual void cvtDevToUser(double dx, double dy, double *ux, double *uy); + // virtual void cvtUserToDev(double ux, double uy, int *dx, int *dy); + + #if POPPLER_CHECK_VERSION(0, 17, 0) + virtual void processLink(AnnotLink *link, Catalog *catalog); + #else + //----- link borders + virtual void processLink(Link *link, Catalog *catalog); + #endif + + //----- save/restore graphics state + virtual void saveState(GfxState *state); + virtual void restoreState(GfxState *state); + + //----- update graphics state + // virtual void updateAll(GfxState *state); + virtual void updateCTM(GfxState *state, double m11, double m12, + double m21, double m22, double m31, double m32); + virtual void updateLineDash(GfxState *state); + virtual void updateFlatness(GfxState *state); + virtual void updateLineJoin(GfxState *state); + virtual void updateLineCap(GfxState *state); + virtual void updateMiterLimit(GfxState *state); + virtual void updateLineWidth(GfxState *state); + virtual void updateFillColor(GfxState *state); + virtual void updateStrokeColor(GfxState *state); + virtual void updateFillOpacity(GfxState *state); + virtual void updateStrokeOpacity(GfxState *state); + virtual void updateBlendMode(GfxState *state); + + //----- update text state + virtual void updateFont(GfxState *state); + // virtual void updateTextMat(GfxState *state); + // virtual void updateCharSpace(GfxState *state) {} + virtual void updateRender(GfxState *state); + // virtual void updateRise(GfxState *state) {} + // virtual void updateWordSpace(GfxState *state) {} + // virtual void updateHorizScaling(GfxState *state) {} + // virtual void updateTextPos(GfxState *state) {} + // virtual void updateTextShift(GfxState *state, double shift) {} + + //----- path painting + virtual void stroke(GfxState *state); + virtual void fill(GfxState *state); + virtual void eoFill(GfxState *state); + + //----- path clipping + virtual void clip(GfxState *state); + virtual void eoClip(GfxState *state); + + //----- text drawing + 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); + virtual void drawString(GfxState *state, GooString *s); + virtual void endTextObject(GfxState *state); + + //----- image drawing + virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, + int width, int height, GBool invert, + GBool inlineImg); + virtual void drawImage(GfxState *state, Object *ref, Stream *str, + int width, int height, GfxImageColorMap *colorMap, + int *maskColors, GBool inlineImg); + virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, int maskWidth, int maskHeight, + GBool maskInvert); + virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GfxImageColorMap *maskColorMap); + + //----- OPI functions + // virtual void opiBegin(GfxState *state, Dict *opiDict); + // virtual void opiEnd(GfxState *state, Dict *opiDict); + + //----- Type 3 font operators + // virtual void type3D0(GfxState *state, double wx, double wy) {} + // virtual void type3D1(GfxState *state, double wx, double wy, + // double llx, double lly, double urx, double ury) {} + + //----- PostScript XObjects + // virtual void psXObject(Stream *psStream, Stream *level1Stream) {} + + void setPageNum( int nNumPages ); + }; +} + +extern FILE* g_binary_out; + +// note: if you ever hcange Output_t, please keep in mind that the current code +// relies on it being of 8 bit size +typedef char Output_t; +typedef std::vector< Output_t > OutputBuffer; + +#endif /* INCLUDED_PDFI_OUTDEV_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 000000000000..71b0c8989228 --- /dev/null +++ b/sdext/source/pdfimport/xpdfwrapper/pnghelper.cxx @@ -0,0 +1,419 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * The Contents of this file are made available subject to + * the terms of GNU General Public License Version 2. + * + * + * GNU General Public License, version 2 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + ************************************************************************/ + +#include "pnghelper.hxx" +#include <sal/macros.h> + +#ifdef SYSTEM_ZLIB +#include "zlib.h" +#else +#define ZLIB_INTERNAL 1 +#include <zlib/zlib.h> +#endif + +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; + deflateInit( &aStream, Z_BEST_COMPRESSION ); + aStream.avail_in = uInt(i_nLen); + aStream.next_in = (Bytef*)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 ); + // scrao 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( (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& zeroColor, + GfxRGB& 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[0], 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 + Guchar *p, *pm; + GfxRGB rgb; + GfxGray alpha; + 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 + 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); + } + } + + delete imgStr; + delete imgStrMask; + + // begind IDAT chunk for scanline data + size_t nIdx = startChunk( "IDAT", o_rOutputBuf ); + // compress scanlines + deflateBuffer( &aScanlines[0], 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 + Guchar *p; + GfxRGB rgb; + 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 + ImageStream* imgStrMask = + new ImageStream(maskStr, maskWidth, 1, 1); + + imgStrMask->reset(); + for( int y = 0; y < maskHeight; ++y ) + { + for( int x = 0; x < maskWidth; ++x ) + { + Guchar 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; + } + } + + delete imgStr; + delete imgStrMask; + + // begind IDAT chunk for scanline data + size_t nIdx = startChunk( "IDAT", o_rOutputBuf ); + // compress scanlines + deflateBuffer( &aScanlines[0], 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 000000000000..c7b050869554 --- /dev/null +++ b/sdext/source/pdfimport/xpdfwrapper/pnghelper.hxx @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * The Contents of this file are made available subject to + * the terms of GNU General Public License Version 2. + * + * + * GNU General Public License, version 2 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + ************************************************************************/ +#ifndef _IPDF_PNGHELPER_HXX +#define _IPDF_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& zeroColor, + GfxRGB& 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 000000000000..f10ed9278b6b --- /dev/null +++ b/sdext/source/pdfimport/xpdfwrapper/wrapper_gpl.cxx @@ -0,0 +1,210 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * The Contents of this file are made available subject to + * the terms of GNU General Public License Version 2. + * + * + * GNU General Public License, version 2 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + ************************************************************************/ + +#include "pdfioutdev_gpl.hxx" +#ifdef WNT +# include <io.h> +# include <fcntl.h> /*_O_BINARY*/ +#endif + +FILE* g_binary_out=stderr; + +#ifndef SYSTEM_POPPLER +static char ownerPassword[33] = "\001"; +static char userPassword[33] = "\001"; +static char outputFile[256] = "\001"; + +static ArgDesc argDesc[] = { + {(char*)"-f", argString, outputFile, sizeof(outputFile), + (char*)"output file for binary streams"}, + {(char*)"-opw", argString, ownerPassword, sizeof(ownerPassword), + (char*)"owner password (for encrypted files)"}, + {(char*)"-upw", argString, userPassword, sizeof(userPassword), + (char*)"user password (for encrypted files)"}, + {NULL, argString, NULL, 0, NULL } +}; +#else +static const char *ownerPassword = "\001"; +static const char *userPassword = "\001"; +static const char *outputFile = "\001"; +#endif + +int main(int argc, char **argv) +{ +#ifndef SYSTEM_POPPLER + // parse args; initialize to defaults + if( !parseArgs(argDesc, &argc, argv) ) + return 1; +#else + int k = 0; + while (k < argc) + { + if (!strcmp(argv[k], "-f")) + { + outputFile = argv[k+1]; + --argc; + for (int j = k; j < argc; ++j) + argv[j] = argv[j+1]; + } + else if (!strcmp(argv[k], "-opw")) + { + ownerPassword = argv[k+1]; + --argc; + for (int j = k; j < argc; ++j) + argv[j] = argv[j+1]; + } + else if (!strcmp(argv[k], "-upw")) + { + userPassword = argv[k+1]; + --argc; + for (int j = k; j < argc; ++j) + argv[j] = argv[j+1]; + } + ++k; + } +#endif + + if( argc < 2 ) + return 1; + + // read config file + globalParams = new GlobalParams( +#ifndef SYSTEM_POPPLER + (char*)"" +#endif + ); + globalParams->setErrQuiet(gTrue); +#if !defined(SYSTEM_POPPLER) || defined(_MSC_VER) + globalParams->setupBaseFonts(NULL); +#endif + + // try to read a possible open password form stdin + char aPwBuf[129]; + aPwBuf[128] = 0; + if( ! fgets( aPwBuf, sizeof(aPwBuf)-1, stdin ) ) + aPwBuf[0] = 0; // mark as empty + else + { + for( unsigned int 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* pTempErrFileName = new GooString("_err.pdf"); + GooString* pTempErrFileNamePath = new GooString(argv[0]); + + GooString* pErrFileName = new GooString(pTempErrFileNamePath,pTempErrFileName); + + + // check for password string(s) + GooString* pOwnerPasswordStr( aPwBuf[0] != 0 + ? new GooString( aPwBuf ) + : (ownerPassword[0] != '\001' + ? new GooString(ownerPassword) + : (GooString *)NULL ) ); + GooString* pUserPasswordStr( userPassword[0] != '\001' + ? new GooString(userPassword) + : (GooString *)NULL ); + if( outputFile[0] != '\001' ) + g_binary_out = fopen(outputFile,"wb"); + +#ifdef WNT + // Win actually modifies output for O_TEXT file mode, so need to + // revert to binary here + _setmode( _fileno( g_binary_out ), _O_BINARY ); +#endif + + PDFDoc aDoc( pFileName, + pOwnerPasswordStr, + pUserPasswordStr ); + + PDFDoc aErrDoc( pErrFileName, + pOwnerPasswordStr, + pUserPasswordStr ); + + + // Check various permissions. + if ( !aDoc.isOk() ) + { + pdfi::PDFOutDev* pOutDev( new pdfi::PDFOutDev(&aErrDoc) ); + + const int nPages = aErrDoc.isOk() ? aErrDoc.getNumPages() : 0; + + // tell receiver early - needed for proper progress calculation + pOutDev->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 ) + { + aErrDoc.displayPage( pOutDev, + i, + PDFI_OUTDEV_RESOLUTION, + PDFI_OUTDEV_RESOLUTION, + 0, gTrue, gTrue, gTrue ); + aErrDoc.processLinks( pOutDev, i ); + } + } + else + { + pdfi::PDFOutDev* pOutDev( new pdfi::PDFOutDev(&aDoc) ); + + // tell receiver early - needed for proper progress calculation + pOutDev->setPageNum( aDoc.getNumPages() ); + + // virtual resolution of the PDF OutputDev in dpi + static const int PDFI_OUTDEV_RESOLUTION=7200; + + // do the conversion + const int nPages = aDoc.getNumPages(); + for( int i=1; i<=nPages; ++i ) + { + aDoc.displayPage( pOutDev, + i, + PDFI_OUTDEV_RESOLUTION, + PDFI_OUTDEV_RESOLUTION, + 0, gTrue, gTrue, gTrue ); + aDoc.processLinks( pOutDev, i ); + } + } + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |