diff options
author | Ivo Hinkelmann <ihi@openoffice.org> | 2009-06-15 08:47:44 +0000 |
---|---|---|
committer | Ivo Hinkelmann <ihi@openoffice.org> | 2009-06-15 08:47:44 +0000 |
commit | 0a95901dc53fa6c0cdd89205ad7540f46b357d77 (patch) | |
tree | c00ea96a398b3611572189d9960a99f4dfd0d5c5 /sdext | |
parent | 65c47921dc008eedeb0f3eb3fec67261280f6f1e (diff) |
CWS-TOOLING: integrate CWS pdfextfix02_DEV300
2009-05-10 11:23:59 +0200 pl r271736 : #i94755# adjust extension version, add extension icon
2009-05-08 17:06:50 +0200 pl r271726 : #i92909# handle some cases of mirroring
2009-05-08 14:51:37 +0200 pl r271720 : #i95270# cope with some rotated images
2009-05-08 11:37:46 +0200 pl r271709 : #i101327# recognize non breaking space also (thanks ayaniger)
2009-05-07 13:39:06 +0200 pl r271658 : #i92598# still more masked bitmap support
2009-05-07 10:44:41 +0200 pl r271638 : remove some compiler warnings
2009-05-07 09:59:56 +0200 pl r271633 : make test compile again
2009-05-06 21:12:55 +0200 pl r271612 : #i92903# handle two color images
2009-05-06 19:48:19 +0200 pl r271610 : soft masked images
2009-05-06 16:30:36 +0200 pl r271600 : #i92598# use masked PNG images for drawMask
2009-05-05 18:40:06 +0200 pl r271550 : #i90617# #i92598# some workarounds for mask bitmaps
2009-05-04 18:53:09 +0200 pl r271479 : #i94755# add supported for encrypted PDF files
Diffstat (limited to 'sdext')
18 files changed, 1001 insertions, 152 deletions
diff --git a/sdext/source/pdfimport/config/description.xml b/sdext/source/pdfimport/config/description.xml index eebb9c1..d04364e 100644 --- a/sdext/source/pdfimport/config/description.xml +++ b/sdext/source/pdfimport/config/description.xml @@ -16,7 +16,7 @@ </simple-license> </registration> - <version value="0.3.2" /> + <version value="1.0" /> <platform value="UPDATED_SUPPORTED_PLATFORM" /> @@ -27,5 +27,10 @@ <display-name> <name lang="en-US">PDF Import Extension</name> </display-name> + + <icon> + <default xlink:href="images/pdfiext.png" /> + <high-contrast xlink:href="images/pdfiext_hc.png" /> + </icon> </description> diff --git a/sdext/source/pdfimport/images/pdfiext.png b/sdext/source/pdfimport/images/pdfiext.png Binary files differnew file mode 100644 index 0000000..31f48ea --- /dev/null +++ b/sdext/source/pdfimport/images/pdfiext.png diff --git a/sdext/source/pdfimport/images/pdfiext_hc.png b/sdext/source/pdfimport/images/pdfiext_hc.png Binary files differnew file mode 100644 index 0000000..3870cc4 --- /dev/null +++ b/sdext/source/pdfimport/images/pdfiext_hc.png diff --git a/sdext/source/pdfimport/inc/wrapper.hxx b/sdext/source/pdfimport/inc/wrapper.hxx index 2434f74..abd280d 100755 --- a/sdext/source/pdfimport/inc/wrapper.hxx +++ b/sdext/source/pdfimport/inc/wrapper.hxx @@ -47,13 +47,19 @@ namespace com { namespace sun { namespace star { namespace pdfi { - bool xpdf_ImportFromFile( const ::rtl::OUString& rURL, + bool xpdf_ImportFromFile( const rtl::OUString& rURL, const ContentSinkSharedPtr& rSink, + const com::sun::star::uno::Reference< + com::sun::star::task::XInteractionHandler >& xIHdl, + const rtl::OUString& rPwd, const com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext >& xContext ); bool xpdf_ImportFromStream( const com::sun::star::uno::Reference< com::sun::star::io::XInputStream >& xInput, const ContentSinkSharedPtr& rSink, + const com::sun::star::uno::Reference< + com::sun::star::task::XInteractionHandler >& xIHdl, + const rtl::OUString& rPwd, const com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext >& xContext ); } diff --git a/sdext/source/pdfimport/makefile.mk b/sdext/source/pdfimport/makefile.mk index df11c43..d6cd478 100644 --- a/sdext/source/pdfimport/makefile.mk +++ b/sdext/source/pdfimport/makefile.mk @@ -125,7 +125,11 @@ COMPONENT_HELP= \ COMPONENT_LIBRARIES= \ $(EXTENSIONDIR)$/$(SHL1TARGET)$(DLLPOST) -EXTENSION_PACKDEPS=$(CONVERTER_FILE) $(COMPONENT_DIALOGS) $(COMPONENT_HELP) makefile.mk +COMPONENT_IMAGES=\ + $(EXTENSIONDIR)$/images$/pdfiext.png \ + $(EXTENSIONDIR)$/images$/pdfiext_hc.png + +EXTENSION_PACKDEPS=$(CONVERTER_FILE) $(COMPONENT_DIALOGS) $(COMPONENT_HELP) $(COMPONENT_IMAGES) makefile.mk .INCLUDE : extension_pre.mk .INCLUDE : target.mk @@ -142,3 +146,7 @@ $(COMPONENT_DIALOGS) : dialogs$/$$(@:f) $(COMPONENT_HELP) : help$/$$(@:f) @@-$(MKDIRHIER) $(@:d) $(COPY) $< $@ + +$(COMPONENT_IMAGES) : images$/$$(@:f) + @@-$(MKDIRHIER) $(@:d) + $(COPY) $< $@ diff --git a/sdext/source/pdfimport/pdfiadaptor.cxx b/sdext/source/pdfimport/pdfiadaptor.cxx index 7eeb207..d319c60 100644 --- a/sdext/source/pdfimport/pdfiadaptor.cxx +++ b/sdext/source/pdfimport/pdfiadaptor.cxx @@ -238,6 +238,8 @@ void PDFIRawAdaptor::setTreeVisitorFactory(const TreeVisitorFactorySharedPtr& rV } bool PDFIRawAdaptor::parse( const uno::Reference<io::XInputStream>& xInput, + const uno::Reference<task::XInteractionHandler>& xIHdl, + const rtl::OUString& rPwd, const uno::Reference<task::XStatusIndicator>& xStatus, const XmlEmitterSharedPtr& rEmitter, const rtl::OUString& rURL ) @@ -253,9 +255,9 @@ bool PDFIRawAdaptor::parse( const uno::Reference<io::XInputStream>& xInput bool bSuccess=false; if( xInput.is() && (!rURL.getLength() || rURL.compareToAscii( "file:", 5 ) != 0) ) - bSuccess = xpdf_ImportFromStream( xInput, pSink, m_xContext ); + bSuccess = xpdf_ImportFromStream( xInput, pSink, xIHdl, rPwd, m_xContext ); else - bSuccess = xpdf_ImportFromFile( rURL, pSink, m_xContext ); + bSuccess = xpdf_ImportFromFile( rURL, pSink, xIHdl, rPwd, m_xContext ); if( bSuccess ) pSink->emit(*rEmitter,*m_pVisitorFactory); @@ -268,7 +270,10 @@ bool PDFIRawAdaptor::odfConvert( const rtl::OUString& r const uno::Reference<task::XStatusIndicator>& xStatus ) { XmlEmitterSharedPtr pEmitter = createOdfEmitter(xOutput); - const bool bSuccess = parse(uno::Reference<io::XInputStream>(),xStatus,pEmitter,rURL); + const bool bSuccess = parse(uno::Reference<io::XInputStream>(), + uno::Reference<task::XInteractionHandler>(), + rtl::OUString(), + xStatus,pEmitter,rURL); // tell input stream that it is no longer needed xOutput->closeOutput(); @@ -284,7 +289,9 @@ sal_Bool SAL_CALL PDFIRawAdaptor::importer( const uno::Sequence< beans::Property // get the InputStream carrying the PDF content uno::Reference< io::XInputStream > xInput; uno::Reference< task::XStatusIndicator > xStatus; + uno::Reference< task::XInteractionHandler > xInteractionHandler; rtl::OUString aURL; + rtl::OUString aPwd; const beans::PropertyValue* pAttribs = rSourceData.getConstArray(); sal_Int32 nAttribs = rSourceData.getLength(); for( sal_Int32 i = 0; i < nAttribs; i++, pAttribs++ ) @@ -296,12 +303,16 @@ sal_Bool SAL_CALL PDFIRawAdaptor::importer( const uno::Sequence< beans::Property pAttribs->Value >>= aURL; else if( pAttribs->Name.equalsAscii( "StatusIndicator" ) ) pAttribs->Value >>= xStatus; + else if( pAttribs->Name.equalsAscii( "InteractionHandler" ) ) + pAttribs->Value >>= xInteractionHandler; + else if( pAttribs->Name.equalsAscii( "Password" ) ) + pAttribs->Value >>= aPwd; } if( !xInput.is() ) return sal_False; XmlEmitterSharedPtr pEmitter = createSaxEmitter(rHdl); - const bool bSuccess = parse(xInput,xStatus,pEmitter,aURL); + const bool bSuccess = parse(xInput,xInteractionHandler, aPwd, xStatus,pEmitter,aURL); // tell input stream that it is no longer needed xInput->closeInput(); diff --git a/sdext/source/pdfimport/pdfiadaptor.hxx b/sdext/source/pdfimport/pdfiadaptor.hxx index 43298ac..d7386ec 100644 --- a/sdext/source/pdfimport/pdfiadaptor.hxx +++ b/sdext/source/pdfimport/pdfiadaptor.hxx @@ -96,6 +96,8 @@ namespace pdfi bool m_bEnableToplevelText; bool parse( const com::sun::star::uno::Reference<com::sun::star::io::XInputStream>& xInput, + const com::sun::star::uno::Reference<com::sun::star::task::XInteractionHandler>& xIHdl, + const rtl::OUString& rPwd, const com::sun::star::uno::Reference<com::sun::star::task::XStatusIndicator>& xStatus, const XmlEmitterSharedPtr& rEmitter, const rtl::OUString& rURL ); diff --git a/sdext/source/pdfimport/test/tests.cxx b/sdext/source/pdfimport/test/tests.cxx index 27dd9e7..12d384e 100755 --- a/sdext/source/pdfimport/test/tests.cxx +++ b/sdext/source/pdfimport/test/tests.cxx @@ -442,7 +442,11 @@ namespace xMask[0].Name.compareToAscii( "URL" ) == 0 ); CPPUNIT_ASSERT_MESSAGE( "drawAlphaMaskedImage got InputStream param #2", xMask[1].Name.compareToAscii( "InputStream" ) == 0 ); - } + } + + virtual void setTextRenderMode( sal_Int32 ) + { + } typedef std::hash_map<sal_Int32,FontAttributes> IdToFontMap; typedef std::hash_map<FontAttributes,sal_Int32,FontAttrHash> FontToIdMap; @@ -517,6 +521,8 @@ namespace pdfi::ContentSinkSharedPtr pSink( new TestSink() ); pdfi::xpdf_ImportFromFile( msBaseDir + rtl::OUString::createFromAscii("pdfi_unittest_test.pdf"), pSink, + uno::Reference< task::XInteractionHandler >(), + rtl::OUString(), mxCtx ); // make destruction explicit, a bunch of things are diff --git a/sdext/source/pdfimport/tree/drawtreevisiting.cxx b/sdext/source/pdfimport/tree/drawtreevisiting.cxx index d9905e3..efe98c1 100644 --- a/sdext/source/pdfimport/tree/drawtreevisiting.cxx +++ b/sdext/source/pdfimport/tree/drawtreevisiting.cxx @@ -174,6 +174,11 @@ void DrawXmlEmitter::fillFrameProps( DrawElement& rElem, // TODO(F2): general transformation case missing; if implemented, note // that ODF rotation is oriented the other way + + // vertical mirroring is done by horizontally mirroring and rotaing 180 degree + // quaint ! + if( rElem.MirrorVertical ) + fRotate += M_PI; // build transformation string if( fShearX != 0.0 ) @@ -852,7 +857,14 @@ void DrawXmlFinalizer::visit( FrameElement& elem, const std::list< Element* >::c aGCProps[ USTR("fo:padding-top") ] = USTR("0cm"); aGCProps[ USTR("fo:padding-left") ] = USTR("0cm"); aGCProps[ USTR("fo:padding-right") ] = USTR("0cm"); - aGCProps[ USTR("fo:padding-bottom") ] = USTR("0cm"); + aGCProps[ USTR("fo:padding-bottom") ] = USTR("0cm"); + + // remark: vertical mirroring is done in current OOO by + // mirroring horzontally and rotating 180 degrees + // this is quaint, but unfortunately it seems + // mirror=vertical is defined but not implemented in current code + if( elem.MirrorVertical ) + aGCProps[ USTR("style:mirror") ] = USTR("horizontal"); StyleContainer::Style aStyle( "style:style", aProps ); StyleContainer::Style aSubStyle( "style:graphic-properties", aGCProps ); diff --git a/sdext/source/pdfimport/tree/genericelements.hxx b/sdext/source/pdfimport/tree/genericelements.hxx index 4cecf1b..4ba66aa 100644 --- a/sdext/source/pdfimport/tree/genericelements.hxx +++ b/sdext/source/pdfimport/tree/genericelements.hxx @@ -133,10 +133,11 @@ namespace pdfi { protected: GraphicalElement( Element* pParent, sal_Int32 nGCId ) - : Element( pParent ), GCId(nGCId ) {} + : Element( pParent ), GCId( nGCId ), MirrorVertical( false ) {} public: sal_Int32 GCId; + bool MirrorVertical; }; struct DrawElement : public GraphicalElement diff --git a/sdext/source/pdfimport/tree/pdfiprocessor.cxx b/sdext/source/pdfimport/tree/pdfiprocessor.cxx index 6fd7aaf..48950c1 100644 --- a/sdext/source/pdfimport/tree/pdfiprocessor.cxx +++ b/sdext/source/pdfimport/tree/pdfiprocessor.cxx @@ -369,9 +369,10 @@ void PDFIProcessor::processGlyphLine() else { if ( - ( m_GlyphsList[i].getPrevGlyphsSpace()<= fPreAvarageSpaceValue )&& - ( fPrevDiffCharSpace<=fAvarageDiffCharSpaceValue )&& - ( fPostDiffCharSpace<=fAvarageDiffCharSpaceValue ) || + ( ( m_GlyphsList[i].getPrevGlyphsSpace()<= fPreAvarageSpaceValue )&& + ( fPrevDiffCharSpace<=fAvarageDiffCharSpaceValue )&& + ( fPostDiffCharSpace<=fAvarageDiffCharSpaceValue ) + ) || ( m_GlyphsList[i].getPrevGlyphsSpace() == 0.0 ) ) { @@ -446,7 +447,6 @@ void PDFIProcessor::drawGlyphLine( const rtl::OUString& rGlyphs, const geometry::Matrix2D& rFontMatrix ) { double isFirstLine= fYPrevTextPosition+ fXPrevTextPosition+ fPrevTextHeight+ fPrevTextWidth ; - if( ( ( ( fYPrevTextPosition!= rRect.Y1 ) ) || ( ( fXPrevTextPosition > rRect.X2 ) ) || @@ -456,8 +456,6 @@ void PDFIProcessor::drawGlyphLine( const rtl::OUString& rGlyphs, { processGlyphLine(); - } - CharGlyph aGlyph; aGlyph.setGlyph ( rGlyphs ); @@ -485,6 +483,36 @@ void PDFIProcessor::drawGlyphLine( const rtl::OUString& rGlyphs, m_bIsWhiteSpaceInLine=rGlyphs.equals( tempWhiteSpaceStr ); } +======= + + CharGlyph aGlyph; + + aGlyph.setGlyph ( rGlyphs ); + aGlyph.setRect ( rRect ); + aGlyph.setFontMatrix ( rFontMatrix ); + aGlyph.setGraphicsContext ( getCurrentContext() ); + getGCId(getCurrentContext()); + aGlyph.setCurElement( m_pCurElement ); + + aGlyph.setYPrevGlyphPosition( fYPrevTextPosition ); + aGlyph.setXPrevGlyphPosition( fXPrevTextPosition ); + aGlyph.setPrevGlyphHeight ( fPrevTextHeight ); + aGlyph.setPrevGlyphWidth ( fPrevTextWidth ); + + m_GlyphsList.push_back( aGlyph ); + + fYPrevTextPosition = rRect.Y1; + fXPrevTextPosition = rRect.X2; + fPrevTextHeight = rRect.Y2-rRect.Y1; + fPrevTextWidth = rRect.X2-rRect.X1; + + if( !m_bIsWhiteSpaceInLine ) + { + static rtl::OUString tempWhiteSpaceStr( 0x20 ); + static rtl::OUString tempWhiteSpaceNonBreakingStr( 0xa0 ); + m_bIsWhiteSpaceInLine=(rGlyphs.equals( tempWhiteSpaceStr ) || rGlyphs.equals( tempWhiteSpaceNonBreakingStr )); + } +>>>>>>> .merge-right.r272944 } GraphicsContext& PDFIProcessor::getTransformGlyphContext( CharGlyph& rGlyph ) @@ -571,22 +599,70 @@ void PDFIProcessor::setupImage(ImageId nImage) { const GraphicsContext& rGC( getCurrentContext() ); - // transform unit rect, to determine view box - basegfx::B2DPoint aOrigin(0,0); - aOrigin *= rGC.Transformation; + basegfx::B2DHomMatrix aTrans( rGC.Transformation ); - basegfx::B2DVector aSize(1,1); - aSize *= rGC.Transformation; + // check for rotation, which is the other way around in ODF + basegfx::B2DTuple aScale, aTranslation; + double fRotate, fShearX; + rGC.Transformation.decompose( aScale, aTranslation, fRotate, fShearX ); + // TODDO(F4): correcting rotation when fShearX != 0 ? + if( fRotate != 0.0 ) + { + + // try to create a Transformation that corrects for the wrong rotation + aTrans.identity(); + aTrans.scale( aScale.getX(), aScale.getY() ); + aTrans.rotate( -fRotate ); + + basegfx::B2DRange aRect( 0, 0, 1, 1 ); + aRect.transform( aTrans ); + + // TODO(F3) treat translation correctly + // the corrections below work for multiples of 90 degree + // which is a common case (landscape/portrait/seascape) + // we need a general solution here; however this needs to + // work in sync with DrawXmlEmitter::fillFrameProps and WriterXmlEmitter::fillFrameProps + // admittedly this is a lame workaround and fails for arbitrary rotation + double fQuadrant = fmod( fRotate, 2.0*M_PI ) / M_PI_2; + int nQuadrant = (int)fQuadrant; + if( nQuadrant < 0 ) + nQuadrant += 4; + if( nQuadrant == 1 ) + { + aTranslation.setX( aTranslation.getX() + aRect.getHeight() + aRect.getWidth()); + aTranslation.setY( aTranslation.getY() + aRect.getHeight() ); + } + if( nQuadrant == 3 ) + aTranslation.setX( aTranslation.getX() - aRect.getHeight() ); + + aTrans.translate( aTranslation.getX(), + aTranslation.getY() ); + } + + bool bMirrorVertical = aScale.getY() > 0; + + // transform unit rect to determine view box + basegfx::B2DRange aRect( 0, 0, 1, 1 ); + aRect.transform( aTrans ); // TODO(F3): Handle clip const sal_Int32 nGCId = getGCId(rGC); FrameElement* pFrame = m_pElFactory->createFrameElement( m_pCurElement, nGCId ); ImageElement* pImageElement = m_pElFactory->createImageElement( pFrame, nGCId, nImage ); - pFrame->x = pImageElement->x = aOrigin.getX(); - pFrame->y = pImageElement->y = aOrigin.getY(); - pFrame->w = pImageElement->w = aSize.getX(); - pFrame->h = pImageElement->h = aSize.getY(); + pFrame->x = pImageElement->x = aRect.getMinX(); + pFrame->y = pImageElement->y = aRect.getMinY(); + pFrame->w = pImageElement->w = aRect.getWidth(); + pFrame->h = pImageElement->h = aRect.getHeight(); pFrame->ZOrder = m_nNextZOrder++; + + if( bMirrorVertical ) + { + pFrame->MirrorVertical = pImageElement->MirrorVertical = true; + pFrame->x += aRect.getWidth(); + pImageElement->x += aRect.getWidth(); + pFrame->y += aRect.getHeight(); + pImageElement->y += aRect.getHeight(); + } } void PDFIProcessor::drawMask(const uno::Sequence<beans::PropertyValue>& xBitmap, diff --git a/sdext/source/pdfimport/wrapper/wrapper.cxx b/sdext/source/pdfimport/wrapper/wrapper.cxx index 5e5596b..c4f9062 100755 --- a/sdext/source/pdfimport/wrapper/wrapper.cxx +++ b/sdext/source/pdfimport/wrapper/wrapper.cxx @@ -33,36 +33,39 @@ #include "precompiled_sdext.hxx" #include "contentsink.hxx" - -#include <osl/file.h> -#include <osl/thread.h> -#include <osl/process.h> -#include <osl/diagnose.h> -#include <rtl/ustring.hxx> -#include <rtl/ustrbuf.hxx> -#include <rtl/strbuf.hxx> -#include <rtl/byteseq.hxx> - -#include <cppuhelper/exc_hlp.hxx> -#include <com/sun/star/io/XInputStream.hpp> -#include <com/sun/star/uno/XComponentContext.hpp> -#include <com/sun/star/awt/FontDescriptor.hpp> -#include <com/sun/star/deployment/XPackageInformationProvider.hpp> -#include <com/sun/star/beans/XMaterialHolder.hpp> -#include <com/sun/star/rendering/PathCapType.hpp> -#include <com/sun/star/rendering/PathJoinType.hpp> -#include <com/sun/star/rendering/XColorSpace.hpp> -#include <com/sun/star/rendering/XPolyPolygon2D.hpp> -#include <com/sun/star/rendering/XBitmap.hpp> -#include <com/sun/star/geometry/Matrix2D.hpp> -#include <com/sun/star/geometry/AffineMatrix2D.hpp> -#include <com/sun/star/geometry/RealRectangle2D.hpp> - -#include <basegfx/point/b2dpoint.hxx> -#include <basegfx/polygon/b2dpolypolygon.hxx> -#include <basegfx/polygon/b2dpolygon.hxx> -#include <basegfx/tools/canvastools.hxx> -#include <basegfx/tools/unopolypolygon.hxx> +#include "pdfparse.hxx" +#include "pdfihelper.hxx" + +#include "osl/file.h" +#include "osl/thread.h" +#include "osl/process.h" +#include "osl/diagnose.h" +#include "rtl/ustring.hxx" +#include "rtl/ustrbuf.hxx" +#include "rtl/strbuf.hxx" +#include "rtl/byteseq.hxx" + +#include "cppuhelper/exc_hlp.hxx" +#include "com/sun/star/io/XInputStream.hpp" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/awt/FontDescriptor.hpp" +#include "com/sun/star/deployment/XPackageInformationProvider.hpp" +#include "com/sun/star/beans/XMaterialHolder.hpp" +#include "com/sun/star/rendering/PathCapType.hpp" +#include "com/sun/star/rendering/PathJoinType.hpp" +#include "com/sun/star/rendering/XColorSpace.hpp" +#include "com/sun/star/rendering/XPolyPolygon2D.hpp" +#include "com/sun/star/rendering/XBitmap.hpp" +#include "com/sun/star/geometry/Matrix2D.hpp" +#include "com/sun/star/geometry/AffineMatrix2D.hpp" +#include "com/sun/star/geometry/RealRectangle2D.hpp" +#include "com/sun/star/task/XInteractionHandler.hpp" + +#include "basegfx/point/b2dpoint.hxx" +#include "basegfx/polygon/b2dpolypolygon.hxx" +#include "basegfx/polygon/b2dpolygon.hxx" +#include "basegfx/tools/canvastools.hxx" +#include "basegfx/tools/unopolypolygon.hxx" #include <boost/bind.hpp> #include <boost/preprocessor/stringize.hpp> @@ -561,18 +564,23 @@ uno::Sequence<beans::PropertyValue> Parser::readImageImpl() static const rtl::OString aJpegMarker( "JPEG" ); static const rtl::OString aPbmMarker( "PBM" ); static const rtl::OString aPpmMarker( "PPM" ); - static const rtl::OUString aJpegFile( + static const rtl::OString aPngMarker( "PNG" ); + static const rtl::OUString aJpegFile( RTL_CONSTASCII_USTRINGPARAM( "DUMMY.JPEG" )); static const rtl::OUString aPbmFile( RTL_CONSTASCII_USTRINGPARAM( "DUMMY.PBM" )); static const rtl::OUString aPpmFile( RTL_CONSTASCII_USTRINGPARAM( "DUMMY.PPM" )); + static const rtl::OUString aPngFile( + RTL_CONSTASCII_USTRINGPARAM( "DUMMY.PNG" )); rtl::OString aToken = readNextToken(); const sal_Int32 nImageSize( readInt32() ); rtl::OUString aFileName; - if( aToken.compareTo( aJpegMarker ) == 0 ) + if( aToken.compareTo( aPngMarker ) == 0 ) + aFileName = aPngFile; + else if( aToken.compareTo( aJpegMarker ) == 0 ) aFileName = aJpegFile; else if( aToken.compareTo( aPbmMarker ) == 0 ) aFileName = aPbmFile; @@ -813,15 +821,77 @@ oslFileError readLine( oslFileHandle pFile, ::rtl::OStringBuffer& line ) } // namespace -bool xpdf_ImportFromFile( const ::rtl::OUString& rURL, - const ContentSinkSharedPtr& rSink, - const uno::Reference< uno::XComponentContext >& xContext ) +static bool checkEncryption( const rtl::OUString& i_rPath, + const uno::Reference< task::XInteractionHandler >& i_xIHdl, + rtl::OUString& io_rPwd, + bool& o_rIsEncrypted + ) +{ + bool bSuccess = false; + rtl::OString aPDFFile; + aPDFFile = rtl::OUStringToOString( i_rPath, osl_getThreadTextEncoding() ); + + pdfparse::PDFReader aParser; + boost::scoped_ptr<pdfparse::PDFEntry> pEntry( aParser.read( aPDFFile.getStr() )); + if( pEntry ) + { + pdfparse::PDFFile* pPDFFile = dynamic_cast<pdfparse::PDFFile*>(pEntry.get()); + if( pPDFFile ) + { + o_rIsEncrypted = pPDFFile->isEncrypted(); + if( o_rIsEncrypted ) + { + bool bAuthenticated = false; + if( io_rPwd.getLength() ) + { + rtl::OString aIsoPwd = rtl::OUStringToOString( io_rPwd, + RTL_TEXTENCODING_ISO_8859_1 ); + bAuthenticated = pPDFFile->setupDecryptionData( aIsoPwd.getStr() ); + } + if( bAuthenticated ) + bSuccess = true; + else + { + if( i_xIHdl.is() ) + { + bool bEntered = false; + do + { + bEntered = getPassword( i_xIHdl, io_rPwd, ! bEntered ); + rtl::OString aIsoPwd = rtl::OUStringToOString( io_rPwd, + RTL_TEXTENCODING_ISO_8859_1 ); + bAuthenticated = pPDFFile->setupDecryptionData( aIsoPwd.getStr() ); + } while( bEntered && ! bAuthenticated ); + } + + OSL_TRACE( "password: %s\n", bAuthenticated ? "matches" : "does not match" ); + bSuccess = bAuthenticated; + } + } + else + bSuccess = true; + } + } + return bSuccess; +} + +bool xpdf_ImportFromFile( const ::rtl::OUString& rURL, + const ContentSinkSharedPtr& rSink, + const uno::Reference< task::XInteractionHandler >& xIHdl, + const rtl::OUString& rPwd, + const uno::Reference< uno::XComponentContext >& xContext ) { OSL_ASSERT(rSink); ::rtl::OUString aSysUPath; if( osl_getSystemPathFromFileURL( rURL.pData, &aSysUPath.pData ) != osl_File_E_None ) return false; + + // check for encryption, if necessary get password + rtl::OUString aPwd( rPwd ); + bool bIsEncrypted = false; + if( checkEncryption( aSysUPath, xIHdl, aPwd, bIsEncrypted ) == false ) + return false; rtl::OUStringBuffer converterURL = rtl::OUString::createFromAscii("xpdfimport"); @@ -853,15 +923,17 @@ bool xpdf_ImportFromFile( const ::rtl::OUString& rURL rtl_bootstrap_expandMacros( &aStr.pData ); rtl::OUString aSysPath; osl_getSystemPathFromFileURL( aStr.pData, &aSysPath.pData ); - rtl::OUStringBuffer aBuf( aStr.getLength() + 20 ); - aBuf.appendAscii( "LD_LIBRARY_PATH=" ); - aBuf.append( aSysPath ); - aStr = aBuf.makeStringAndClear(); + rtl::OUStringBuffer aEnvBuf( aStr.getLength() + 20 ); + aEnvBuf.appendAscii( "LD_LIBRARY_PATH=" ); + aEnvBuf.append( aSysPath ); + aStr = aEnvBuf.makeStringAndClear(); ppEnv = &aStr.pData; nEnv = 1; #endif rtl_uString* args[] = { aSysUPath.pData }; + sal_Int32 nArgs = 1; + oslProcess aProcess; oslFileHandle pIn = NULL; oslFileHandle pOut = NULL; @@ -869,7 +941,7 @@ bool xpdf_ImportFromFile( const ::rtl::OUString& rURL const oslProcessError eErr = osl_executeProcess_WithRedirectedIO(converterURL.makeStringAndClear().pData, args, - sizeof(args)/sizeof(*args), + nArgs, osl_Process_SEARCHPATH|osl_Process_HIDDEN, osl_getCurrentSecurity(), 0, ppEnv, nEnv, @@ -880,6 +952,17 @@ bool xpdf_ImportFromFile( const ::rtl::OUString& rURL { if( eErr!=osl_Process_E_None ) return false; + + if( pIn ) + { + rtl::OStringBuffer aBuf(256); + if( bIsEncrypted ) + aBuf.append( rtl::OUStringToOString( aPwd, RTL_TEXTENCODING_ISO_8859_1 ) ); + aBuf.append( '\n' ); + + sal_uInt64 nWritten = 0; + osl_writeFile( pIn, aBuf.getStr(), sal_uInt64(aBuf.getLength()), &nWritten ); + } if( pOut && pErr ) { @@ -908,8 +991,11 @@ bool xpdf_ImportFromFile( const ::rtl::OUString& rURL return bRet; } + bool xpdf_ImportFromStream( const uno::Reference< io::XInputStream >& xInput, const ContentSinkSharedPtr& rSink, + const uno::Reference<task::XInteractionHandler >& xIHdl, + const rtl::OUString& rPwd, const uno::Reference< uno::XComponentContext >& xContext ) { OSL_ASSERT(xInput.is()); @@ -952,7 +1038,7 @@ bool xpdf_ImportFromStream( const uno::Reference< io::XInputStream >& xI osl_closeFile( aFile ); - return bSuccess && xpdf_ImportFromFile( aURL, rSink, xContext ); + return bSuccess && xpdf_ImportFromFile( aURL, rSink, xIHdl, rPwd, xContext ); } } diff --git a/sdext/source/pdfimport/xpdfwrapper/makefile.mk b/sdext/source/pdfimport/xpdfwrapper/makefile.mk index 8ce3fb7..796bef0 100644 --- a/sdext/source/pdfimport/xpdfwrapper/makefile.mk +++ b/sdext/source/pdfimport/xpdfwrapper/makefile.mk @@ -57,8 +57,9 @@ UWINAPILIB:= APP1TARGET=$(TARGET) APP1LIBSALCPPRT= APP1OBJS= \ - $(OBJ)$/wrapper_gpl.obj $(OBJ)/pdfioutdev_gpl.obj + $(OBJ)$/wrapper_gpl.obj $(OBJ)/pdfioutdev_gpl.obj $(OBJ)/pnghelper.obj +APP1STDLIBS+=$(ZLIB3RDLIB) .IF "$(SYSTEM_POPPLER)" == "YES" APP1STDLIBS+=$(POPPLER_LIBS) diff --git a/sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.cxx b/sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.cxx index e3041e9..d29be09 100644 --- a/sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.cxx +++ b/sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.cxx @@ -35,6 +35,7 @@ ************************************************************************/ #include "pdfioutdev_gpl.hxx" +#include "pnghelper.hxx" #include <stdlib.h> #include <stdio.h> @@ -95,8 +96,6 @@ const char* escapeLineFeed( const char* pStr ) /// for the initial std::vector capacity when copying stream from xpdf #define WRITE_BUFFER_INITIAL_CAPACITY (1024*100) -typedef std::vector<char> OutputBuffer; - void initBuf(OutputBuffer& io_rBuffer) { io_rBuffer.reserve(WRITE_BUFFER_INITIAL_CAPACITY); @@ -135,7 +134,7 @@ void writeJpeg_( OutputBuffer& o_rOutputBuf, Stream* str, bool bWithLinefeed ) str->close(); } -void writePbm_(OutputBuffer& o_rOutputBuf, Stream* str, int width, int height, bool bWithLinefeed) +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(); @@ -163,19 +162,142 @@ void writePbm_(OutputBuffer& o_rOutputBuf, Stream* str, int width, int height, b str->reset(); // copy the raw stream - for( int i=0; i<size; ++i) - o_rOutputBuf.push_back(static_cast<char>(str->getChar())); + 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 ) +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); + writePbm_(o_rOutputBuf, str, width, height, bWithLinefeed, bInvert ); } void writeImage_( OutputBuffer& o_rOutputBuf, @@ -195,62 +317,21 @@ void writeImage_( OutputBuffer& o_rOutputBuf, else if (colorMap->getNumPixelComps() == 1 && colorMap->getBits() == 1) { - writePbm_(o_rOutputBuf, str, width, height, bWithLinefeed); - } - else - { - // 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) + // 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 ) { - 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(); - } + Guchar nIndex = 0; + colorMap->getRGB( &nIndex, &zeroColor ); + nIndex = 1; + colorMap->getRGB( &nIndex, &oneColor ); } - - delete imgStr; - } + writePng_( o_rOutputBuf, str, width, height, zeroColor, oneColor, false, bWithLinefeed ); + } + else + writePpm_( o_rOutputBuf, str, width, height, colorMap, bWithLinefeed ); } // forwarders @@ -269,11 +350,13 @@ inline void writeImageLF( OutputBuffer& o_rOutputBuf, inline void writeMask( OutputBuffer& o_rOutputBuf, Stream* str, int width, - int height ) { writeMask_(o_rOutputBuf,str,width,height,false); } + int height, + bool bInvert ) { writeMask_(o_rOutputBuf,str,width,height,false,bInvert); } inline void writeMaskLF( OutputBuffer& o_rOutputBuf, Stream* str, int width, - int height ) { writeMask_(o_rOutputBuf,str,width,height,true); } + int height, + bool bInvert ) { writeMask_(o_rOutputBuf,str,width,height,true,bInvert); } // ------------------------------------------------------------------ @@ -358,7 +441,7 @@ void PDFOutDev::printPath( GfxPath* pPath ) const PDFOutDev::PDFOutDev( PDFDoc* pDoc ) : m_pDoc( pDoc ), m_aFontMap(), - m_pUtf8Map( new UnicodeMap("UTF-8", gTrue, &mapUTF8) ) + m_pUtf8Map( new UnicodeMap((char*)"UTF-8", gTrue, &mapUTF8) ) { } @@ -704,14 +787,29 @@ void PDFOutDev::endTextObject(GfxState*) printf( "endTextObject\n" ); } -void PDFOutDev::drawImageMask(GfxState*, Object*, Stream* str, +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 ); - writeMaskLF(aBuf, str, width, height); + + 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); } @@ -768,13 +866,19 @@ void PDFOutDev::drawMaskedImage(GfxState*, Object*, Stream* str, 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 ); + #if 0 + OutputBuffer aBuf; initBuf(aBuf); OutputBuffer aMaskBuf; initBuf(aMaskBuf); - printf( "drawMaskedImage %d %d %d %d %d", width, height, maskWidth, maskHeight, maskInvert ); + printf( "drawMaskedImage %d %d %d %d %d", width, height, maskWidth, maskHeight, 0 /*maskInvert note: currently we do inversion here*/ ); writeImage( aBuf, str, width, height, colorMap ); - writeMaskLF( aMaskBuf, maskStr, width, height ); + writeMaskLF( aMaskBuf, maskStr, width, height, maskInvert ); writeBinaryBuffer(aBuf); writeBinaryBuffer(aMaskBuf); + #endif } void PDFOutDev::drawSoftMaskedImage(GfxState*, Object*, Stream* str, @@ -785,6 +889,11 @@ void PDFOutDev::drawSoftMaskedImage(GfxState*, Object*, Stream* str, 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 ); + #if 0 + OutputBuffer aBuf; initBuf(aBuf); OutputBuffer aMaskBuf; initBuf(aMaskBuf); printf( "drawSoftMaskedImage %d %d %d %d", width, height, maskWidth, maskHeight ); @@ -792,6 +901,7 @@ void PDFOutDev::drawSoftMaskedImage(GfxState*, Object*, Stream* str, writeImageLF( aMaskBuf, maskStr, maskWidth, maskHeight, maskColorMap ); writeBinaryBuffer(aBuf); writeBinaryBuffer(aMaskBuf); + #endif } void PDFOutDev::setPageNum( int nNumPages ) diff --git a/sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.hxx b/sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.hxx index 5be2920..af58276 100644 --- a/sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.hxx +++ b/sdext/source/pdfimport/xpdfwrapper/pdfioutdev_gpl.hxx @@ -64,6 +64,7 @@ #endif #include <hash_map> +#include <vector> class GfxPath; class GfxFont; @@ -286,5 +287,10 @@ namespace pdfi 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 */ diff --git a/sdext/source/pdfimport/xpdfwrapper/pnghelper.cxx b/sdext/source/pdfimport/xpdfwrapper/pnghelper.cxx new file mode 100644 index 0000000..abe293b --- /dev/null +++ b/sdext/source/pdfimport/xpdfwrapper/pnghelper.cxx @@ -0,0 +1,411 @@ +/************************************************************************* + * + * 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 "zlib/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; + 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 Output_t aHeader[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a }; + + o_rOutputBuf.insert( o_rOutputBuf.end(), aHeader, aHeader + sizeof(aHeader)/sizeof(aHeader[0]) ); +} + +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, 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 ); +} + diff --git a/sdext/source/pdfimport/xpdfwrapper/pnghelper.hxx b/sdext/source/pdfimport/xpdfwrapper/pnghelper.hxx new file mode 100644 index 0000000..a8ca8f4 --- /dev/null +++ b/sdext/source/pdfimport/xpdfwrapper/pnghelper.hxx @@ -0,0 +1,92 @@ +/************************************************************************* + * + * 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, 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 diff --git a/sdext/source/pdfimport/xpdfwrapper/wrapper_gpl.cxx b/sdext/source/pdfimport/xpdfwrapper/wrapper_gpl.cxx index c53eaed..21a4bc7 100644 --- a/sdext/source/pdfimport/xpdfwrapper/wrapper_gpl.cxx +++ b/sdext/source/pdfimport/xpdfwrapper/wrapper_gpl.cxx @@ -49,12 +49,12 @@ static char userPassword[33] = "\001"; static char outputFile[256] = "\001"; static ArgDesc argDesc[] = { - {"-f", argString, outputFile, sizeof(outputFile), - "output file for binary streams"}, - {"-opw", argString, ownerPassword, sizeof(ownerPassword), - "owner password (for encrypted files)"}, - {"-upw", argString, userPassword, sizeof(userPassword), - "user password (for encrypted files)"}, + {(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 @@ -104,13 +104,30 @@ int main(int argc, char **argv) // 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[34]; + aPwBuf[33] = 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]); @@ -121,12 +138,14 @@ int main(int argc, char **argv) // check for password string(s) - GooString* pOwnerPasswordStr( - ownerPassword[0] != '\001' ? new GooString(ownerPassword) - : (GooString *)NULL ); - GooString* pUserPasswordStr( - userPassword[0] != '\001' ? new GooString(userPassword) - : (GooString *)NULL ); + GooString* pOwnerPasswordStr( ownerPassword[0] != '\001' + ? new GooString(ownerPassword) + : (GooString *)NULL ); + GooString* pUserPasswordStr( aPwBuf[0] != 0 + ? new GooString( aPwBuf ) + : ( userPassword[0] != '\001' + ? new GooString(userPassword) + : (GooString *)NULL ) ); if( outputFile[0] != '\001' ) g_binary_out = fopen(outputFile,"wb"); @@ -150,10 +169,7 @@ int main(int argc, char **argv) !aDoc.okToPrint() || !aDoc.okToChange()|| !aDoc.okToCopy()|| - !aDoc.okToAddNotes()|| - (userPassword[0] != '\001')|| - (ownerPassword[0] != '\001') - ) + !aDoc.okToAddNotes() ) { pdfi::PDFOutDev* pOutDev( new pdfi::PDFOutDev(&aErrDoc) ); |