include/vcl/pdfwriter.hxx | 2 vcl/source/gdi/pdfextoutdevdata.cxx | 4 vcl/source/gdi/pdfwriter.cxx | 4 vcl/source/gdi/pdfwriter_impl.cxx | 203 +++++++++++++++++------------------- vcl/source/gdi/pdfwriter_impl.hxx | 42 +++++-- vcl/source/gdi/pdfwriter_impl2.cxx | 2 6 files changed, 137 insertions(+), 120 deletions(-)
New commits: commit 78e25558e86188314b9b72048b8ddca18697cb86 Author: Miklos Vajna <vmik...@collabora.co.uk> Date: Thu Feb 23 16:35:15 2017 +0100 tdf#106059 PDF export: create a reference XObject for JPG images with PDF data In case the bitmap is large enough, the bitmap for the PDF image is a JPG one, not a PNG one. Handle this case as well. Also stop compressing the PDF data: Adobe Acrobat gets confused when the second bugdoc is compressed and it doesn't provide much as most of a PDF is already compressed anyway. The rest is just refactoring to decouple the reference XObject code from PNG, to be able to use it for JPG as well. Change-Id: I5314a39b0f6d8c6493ecb36a0c588c895f5a70ee diff --git a/include/vcl/pdfwriter.hxx b/include/vcl/pdfwriter.hxx index 6beeea1..aaacbce 100644 --- a/include/vcl/pdfwriter.hxx +++ b/include/vcl/pdfwriter.hxx @@ -868,7 +868,7 @@ The following structure describes the permissions used in PDF security the same pixel size as the image and be either 1 bit black&white or 8 bit grey */ - void DrawJPGBitmap( SvStream& rJPGData, bool bIsTrueColor, const Size& rSrcSizePixel, const Rectangle& rTargetArea, const Bitmap& rMask ); + void DrawJPGBitmap( SvStream& rJPGData, bool bIsTrueColor, const Size& rSrcSizePixel, const Rectangle& rTargetArea, const Bitmap& rMask, const Graphic& rGraphic ); /** Create a new named destination to be used in a link from another PDF document diff --git a/vcl/source/gdi/pdfextoutdevdata.cxx b/vcl/source/gdi/pdfextoutdevdata.cxx index 10b5a31..6defb59 100644 --- a/vcl/source/gdi/pdfextoutdevdata.cxx +++ b/vcl/source/gdi/pdfextoutdevdata.cxx @@ -412,7 +412,7 @@ bool PageSyncData::PlaySyncPageAct( PDFWriter& rWriter, sal_uInt32& rCurGDIMtfAc } else if ((eType == GfxLinkType::NativePng || eType == GfxLinkType::NativePdf) && mParaRects.size() >= 2) { - if ( rOutDevData.HasAdequateCompression(rGraphic, mParaRects[0], mParaRects[1]) ) + if ( rOutDevData.HasAdequateCompression(rGraphic, mParaRects[0], mParaRects[1]) || eType == GfxLinkType::NativePdf ) mCurrentGraphic = rGraphic; } } @@ -465,7 +465,7 @@ bool PageSyncData::PlaySyncPageAct( PDFWriter& rWriter, sal_uInt32& rCurGDIMtfAc if( pData && nBytes ) { aTmp.WriteBytes( pData, nBytes ); - rWriter.DrawJPGBitmap( aTmp, aGraphic.GetBitmap().GetBitCount() > 8, aGraphic.GetSizePixel(), aOutputRect, aMask ); + rWriter.DrawJPGBitmap( aTmp, aGraphic.GetBitmap().GetBitCount() > 8, aGraphic.GetSizePixel(), aOutputRect, aMask, aGraphic ); } if ( bClippingNeeded ) diff --git a/vcl/source/gdi/pdfwriter.cxx b/vcl/source/gdi/pdfwriter.cxx index c17c3f6..bd204cf 100644 --- a/vcl/source/gdi/pdfwriter.cxx +++ b/vcl/source/gdi/pdfwriter.cxx @@ -334,9 +334,9 @@ void PDFWriter::SetTextAlign( ::TextAlign eAlign ) xImplementation->setTextAlign( eAlign ); } -void PDFWriter::DrawJPGBitmap( SvStream& rStreamData, bool bIsTrueColor, const Size& rSrcSizePixel, const Rectangle& rTargetArea, const Bitmap& rMask ) +void PDFWriter::DrawJPGBitmap( SvStream& rStreamData, bool bIsTrueColor, const Size& rSrcSizePixel, const Rectangle& rTargetArea, const Bitmap& rMask, const Graphic& rGraphic ) { - xImplementation->drawJPGBitmap( rStreamData, bIsTrueColor, rSrcSizePixel, rTargetArea, rMask ); + xImplementation->drawJPGBitmap( rStreamData, bIsTrueColor, rSrcSizePixel, rTargetArea, rMask, rGraphic ); } sal_Int32 PDFWriter::CreateLink( const Rectangle& rRect, sal_Int32 nPageNr ) diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 3fe1bf4..054b7a3 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -4982,25 +4982,16 @@ bool PDFWriterImpl::emitEmbeddedFiles() if (!updateObject(rEmbeddedFile.m_nObject)) continue; - SvMemoryStream aUncompressed; - aUncompressed.WriteBytes(rEmbeddedFile.m_aData.getArray(), rEmbeddedFile.m_aData.getLength()); - aUncompressed.Seek(0); - SvMemoryStream aCompressed; - ZCodec aZCodec; - aZCodec.BeginCompression(); - aZCodec.Compress(aUncompressed, aCompressed); - aZCodec.EndCompression(); - OStringBuffer aLine; aLine.append(rEmbeddedFile.m_nObject); aLine.append(" 0 obj\n"); - aLine.append("<< /Type /EmbeddedFile /Filter /FlateDecode /Length "); - aLine.append(static_cast<sal_Int64>(aCompressed.GetSize())); + aLine.append("<< /Type /EmbeddedFile /Length "); + aLine.append(static_cast<sal_Int64>(rEmbeddedFile.m_aData.getLength())); aLine.append(" >>\nstream\n"); CHECK_RETURN(writeBuffer(aLine.getStr(), aLine.getLength())); aLine.setLength(0); - CHECK_RETURN(writeBuffer(aCompressed.GetData(), aCompressed.GetSize())); + CHECK_RETURN(writeBuffer(rEmbeddedFile.m_aData.getArray(), rEmbeddedFile.m_aData.getLength())); aLine.append("\nendstream\nendobj\n\n"); CHECK_RETURN(writeBuffer(aLine.getStr(), aLine.getLength())); @@ -10870,6 +10861,75 @@ void PDFWriterImpl::writeJPG( JPGEmit& rObject ) aEmit.m_aBitmap = BitmapEx( rObject.m_aMask, AlphaMask( rObject.m_aMask ) ); writeBitmapObject( aEmit, true ); } + + writeReferenceXObject(rObject.m_aReferenceXObject); +} + +void PDFWriterImpl::writeReferenceXObject(ReferenceXObjectEmit& rEmit) +{ + if (rEmit.m_nFormObject <= 0 || rEmit.m_nEmbeddedObject <= 0) + return; + + OStringBuffer aLine; + if (!updateObject(rEmit.m_nFormObject)) + return; + + // Count /Matrix and /BBox. + // vcl::ImportPDF() works with 96 DPI so use the same values here, too. + sal_Int32 nOldDPIX = getReferenceDevice()->GetDPIX(); + getReferenceDevice()->SetDPIX(96); + sal_Int32 nOldDPIY = getReferenceDevice()->GetDPIY(); + getReferenceDevice()->SetDPIY(96); + Size aSize = getReferenceDevice()->PixelToLogic(rEmit.m_aPixelSize, MapMode(m_aMapMode.GetMapUnit())); + getReferenceDevice()->SetDPIX(nOldDPIX); + getReferenceDevice()->SetDPIY(nOldDPIY); + double fScaleX = 1.0 / aSize.Width(); + double fScaleY = 1.0 / aSize.Height(); + + // Now have all the info to write the form XObject. + aLine.append(rEmit.m_nFormObject); + aLine.append(" 0 obj\n"); + aLine.append("<< /Type /XObject"); + aLine.append(" /Subtype /Form"); + aLine.append(" /Resources << /XObject<</Im"); + aLine.append(rEmit.m_nBitmapObject); + aLine.append(" "); + aLine.append(rEmit.m_nBitmapObject); + aLine.append(" 0 R>> >>"); + aLine.append(" /Matrix [ "); + appendDouble(fScaleX, aLine); + aLine.append(" 0 0 "); + appendDouble(fScaleY, aLine); + aLine.append(" 0 0 ]"); + aLine.append(" /BBox [ 0 0 "); + aLine.append(aSize.Width()); + aLine.append(" "); + aLine.append(aSize.Height()); + aLine.append(" ]\n"); + + // Write the reference dictionary. + aLine.append("/Ref<< /F << /Type /Filespec /F (<embedded file>) /EF << /F "); + aLine.append(rEmit.m_nEmbeddedObject); + aLine.append(" 0 R >> >> /Page 0 >>\n"); + + aLine.append("/Length "); + + OStringBuffer aStream; + aStream.append("q "); + aStream.append(aSize.Width()); + aStream.append(" 0 0 "); + aStream.append(aSize.Height()); + aStream.append(" 0 0 cm\n"); + aStream.append("/Im"); + aStream.append(rEmit.m_nBitmapObject); + aStream.append(" Do\n"); + aStream.append("Q"); + aLine.append(aStream.getLength()); + + aLine.append(">>\nstream\n"); + aLine.append(aStream.getStr()); + aLine.append("\nendstream\nendobj\n\n"); + CHECK_RETURN2(writeBuffer(aLine.getStr(), aLine.getLength())); } namespace @@ -11185,75 +11245,28 @@ bool PDFWriterImpl::writeBitmapObject( BitmapEmit& rObject, bool bMask ) return writeBitmapObject( aEmit, true ); } - // Write the form XObject proxy for the image. - if (rObject.m_nFormObject > 0 && rObject.m_nEmbeddedObject > 0) - { - aLine.setLength(0); - if (!updateObject(rObject.m_nFormObject)) - return false; - - // Count /Matrix and /BBox. - // vcl::ImportPDF() works with 96 DPI so use the same values here, too. - sal_Int32 nOldDPIX = getReferenceDevice()->GetDPIX(); - getReferenceDevice()->SetDPIX(96); - sal_Int32 nOldDPIY = getReferenceDevice()->GetDPIY(); - getReferenceDevice()->SetDPIY(96); - Size aSize = getReferenceDevice()->PixelToLogic(rObject.m_aBitmap.GetPrefSize(), MapMode(m_aMapMode.GetMapUnit())); - getReferenceDevice()->SetDPIX(nOldDPIX); - getReferenceDevice()->SetDPIY(nOldDPIY); - double fScaleX = 1.0 / aSize.Width(); - double fScaleY = 1.0 / aSize.Height(); - - // Now have all the info to write the form XObject. - aLine.append(rObject.m_nFormObject); - aLine.append(" 0 obj\n"); - aLine.append("<< /Type /XObject"); - aLine.append(" /Subtype /Form"); - aLine.append(" /Resources << /XObject<</Im"); - aLine.append(rObject.m_nObject); - aLine.append(" "); - aLine.append(rObject.m_nObject); - aLine.append(" 0 R>> >>"); - aLine.append(" /Matrix [ "); - appendDouble(fScaleX, aLine); - aLine.append(" 0 0 "); - appendDouble(fScaleY, aLine); - aLine.append(" 0 0 ]"); - aLine.append(" /BBox [ 0 0 "); - aLine.append(aSize.Width()); - aLine.append(" "); - aLine.append(aSize.Height()); - aLine.append(" ]\n"); - - // Write the reference dictionary. - aLine.append("/Ref<< /F << /Type /Filespec /F (<embedded file>) /EF << /F "); - aLine.append(rObject.m_nEmbeddedObject); - aLine.append(" 0 R >> >> /Page 0 >>\n"); - - aLine.append("/Length "); - - OStringBuffer aStream; - aStream.append("q "); - aStream.append(aSize.Width()); - aStream.append(" 0 0 "); - aStream.append(aSize.Height()); - aStream.append(" 0 0 cm\n"); - aStream.append("/Im"); - aStream.append(rObject.m_nObject); - aStream.append(" Do\n"); - aStream.append("Q"); - aLine.append(aStream.getLength()); - - aLine.append(">>\nstream\n"); - aLine.append(aStream.getStr()); - aLine.append("\nendstream\nendobj\n\n"); - CHECK_RETURN(writeBuffer(aLine.getStr(), aLine.getLength())); - } + writeReferenceXObject(rObject.m_aReferenceXObject); return true; } -void PDFWriterImpl::drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const Size& rSizePixel, const Rectangle& rTargetArea, const Bitmap& rMask ) +void PDFWriterImpl::createEmbeddedFile(const Graphic& rGraphic, ReferenceXObjectEmit& rEmit, sal_Int32 nBitmapObject) +{ + if (!rGraphic.getPdfData().hasElements()) + return; + + // Store the original PDF data as an embedded file. + m_aEmbeddedFiles.push_back(PDFEmbeddedFile()); + m_aEmbeddedFiles.back().m_nObject = createObject(); + m_aEmbeddedFiles.back().m_aData = rGraphic.getPdfData(); + + rEmit.m_nFormObject = createObject(); + rEmit.m_nEmbeddedObject = m_aEmbeddedFiles.back().m_nObject; + rEmit.m_nBitmapObject = nBitmapObject; + rEmit.m_aPixelSize = rGraphic.GetBitmap().GetPrefSize(); +} + +void PDFWriterImpl::drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const Size& rSizePixel, const Rectangle& rTargetArea, const Bitmap& rMask, const Graphic& rGraphic ) { MARK( "drawJPGBitmap" ); @@ -11309,6 +11322,7 @@ void PDFWriterImpl::drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const rEmit.m_bTrueColor = bIsTrueColor; if( !! rMask && rMask.GetSizePixel() == rSizePixel ) rEmit.m_aMask = rMask; + createEmbeddedFile(rGraphic, rEmit.m_aReferenceXObject, rEmit.m_nObject); it = m_aJPGs.begin(); } @@ -11324,7 +11338,8 @@ void PDFWriterImpl::drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const aLine.append( ' ' ); m_aPages.back().appendPoint( rTargetArea.BottomLeft(), aLine ); aLine.append( " cm\n/Im" ); - aLine.append( it->m_nObject ); + sal_Int32 nObject = it->m_aReferenceXObject.getObject(); + aLine.append(nObject); aLine.append( " Do Q\n" ); if( nCheckWidth == 0 || nCheckHeight == 0 ) { @@ -11338,8 +11353,8 @@ void PDFWriterImpl::drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const OStringBuffer aObjName( 16 ); aObjName.append( "Im" ); - aObjName.append( it->m_nObject ); - pushResource( ResXObject, aObjName.makeStringAndClear(), it->m_nObject ); + aObjName.append(nObject); + pushResource( ResXObject, aObjName.makeStringAndClear(), nObject ); } @@ -11362,7 +11377,7 @@ void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, aLine.append( ' ' ); m_aPages.back().appendPoint( rDestPoint + Point( 0, rDestSize.Height()-1 ), aLine ); aLine.append( " cm\n/Im" ); - sal_Int32 nObject = rBitmap.getObject(); + sal_Int32 nObject = rBitmap.m_aReferenceXObject.getObject(); aLine.append(nObject); aLine.append( " Do Q\n" ); if( nCheckWidth == 0 || nCheckHeight == 0 ) @@ -11413,22 +11428,13 @@ const PDFWriterImpl::BitmapEmit& PDFWriterImpl::createBitmapEmit( const BitmapEx m_aBitmaps.front().m_aID = aID; m_aBitmaps.front().m_aBitmap = aBitmap; m_aBitmaps.front().m_nObject = createObject(); - if (rGraphic.getPdfData().hasElements()) - { - // Store the original PDF data as an embedded file. - m_aEmbeddedFiles.push_back(PDFEmbeddedFile()); - m_aEmbeddedFiles.back().m_nObject = createObject(); - m_aEmbeddedFiles.back().m_aData = rGraphic.getPdfData(); - - m_aBitmaps.front().m_nFormObject = createObject(); - m_aBitmaps.front().m_nEmbeddedObject = m_aEmbeddedFiles.back().m_nObject; - } + createEmbeddedFile(rGraphic, m_aBitmaps.front().m_aReferenceXObject, m_aBitmaps.front().m_nObject); it = m_aBitmaps.begin(); } OStringBuffer aObjName( 16 ); aObjName.append( "Im" ); - sal_Int32 nObject = it->getObject(); + sal_Int32 nObject = it->m_aReferenceXObject.getObject(); aObjName.append(nObject); pushResource( ResXObject, aObjName.makeStringAndClear(), nObject ); @@ -13278,21 +13284,12 @@ void PDFWriterImpl::MARK( const char* pString ) emitComment( pString ); } -PDFWriterImpl::JPGEmit::JPGEmit(PDFWriterImpl::JPGEmit&& rOther) -{ - m_aID = rOther.m_aID; - m_pStream = std::move(rOther.m_pStream); - m_aMask = std::move(rOther.m_aMask); - m_nObject = rOther.m_nObject; - m_bTrueColor = rOther.m_bTrueColor; -} - -sal_Int32 PDFWriterImpl::BitmapEmit::getObject() const +sal_Int32 PDFWriterImpl::ReferenceXObjectEmit::getObject() const { if (m_nFormObject > 0) return m_nFormObject; else - return m_nObject; + return m_nBitmapObject; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/gdi/pdfwriter_impl.hxx b/vcl/source/gdi/pdfwriter_impl.hxx index 022679f..3e50c0b 100644 --- a/vcl/source/gdi/pdfwriter_impl.hxx +++ b/vcl/source/gdi/pdfwriter_impl.hxx @@ -208,20 +208,22 @@ public: } }; - struct BitmapEmit + /// Contains information to emit a reference XObject. + struct ReferenceXObjectEmit { - BitmapID m_aID; - BitmapEx m_aBitmap; - sal_Int32 m_nObject; /// ID of the Form XObject, if any. sal_Int32 m_nFormObject; - /// ID of the embedded object, if m_nFormObject is used. + /// ID of the vector/embedded object, if m_nFormObject is used. sal_Int32 m_nEmbeddedObject; - - BitmapEmit() - : m_nObject(0), - m_nFormObject(0), - m_nEmbeddedObject(0) + /// ID of the bitmap object, if m_nFormObject is used. + sal_Int32 m_nBitmapObject; + /// Size of the bitmap replacement, in pixels. + Size m_aPixelSize; + + ReferenceXObjectEmit() + : m_nFormObject(0), + m_nEmbeddedObject(0), + m_nBitmapObject(0) { } @@ -229,6 +231,19 @@ public: sal_Int32 getObject() const; }; + struct BitmapEmit + { + BitmapID m_aID; + BitmapEx m_aBitmap; + sal_Int32 m_nObject; + ReferenceXObjectEmit m_aReferenceXObject; + + BitmapEmit() + : m_nObject(0) + { + } + }; + struct JPGEmit { BitmapID m_aID; @@ -237,6 +252,7 @@ public: Bitmap m_aMask; sal_Int32 m_nObject; bool m_bTrueColor; + ReferenceXObjectEmit m_aReferenceXObject; JPGEmit() : m_pStream(nullptr) @@ -827,6 +843,8 @@ i12626 bool writeBitmapObject( BitmapEmit& rObject, bool bMask = false ); void writeJPG( JPGEmit& rEmit ); + /// Writes the form XObject proxy for the image. + void writeReferenceXObject(ReferenceXObjectEmit& rEmit); /* tries to find the bitmap by its id and returns its emit data if exists, else creates a new emit data block */ @@ -1194,7 +1212,9 @@ public: void drawBitmap( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap, const Graphic& rGraphic ); void drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEx& rBitmap ); - void drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const Size& rSizePixel, const Rectangle& rTargetArea, const Bitmap& rMask ); + void drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const Size& rSizePixel, const Rectangle& rTargetArea, const Bitmap& rMask, const Graphic& rGraphic ); + /// Stores the original PDF data from rGraphic as an embedded file. + void createEmbeddedFile(const Graphic& rGraphic, ReferenceXObjectEmit& rEmit, sal_Int32 nBitmapObject); void drawGradient( const Rectangle& rRect, const Gradient& rGradient ); void drawHatch( const tools::PolyPolygon& rPolyPoly, const Hatch& rHatch ); diff --git a/vcl/source/gdi/pdfwriter_impl2.cxx b/vcl/source/gdi/pdfwriter_impl2.cxx index 6de2a88..00120c5 100644 --- a/vcl/source/gdi/pdfwriter_impl2.cxx +++ b/vcl/source/gdi/pdfwriter_impl2.cxx @@ -243,7 +243,7 @@ void PDFWriterImpl::implWriteBitmapEx( const Point& i_rPoint, const Size& i_rSiz } } if ( bUseJPGCompression ) - m_rOuterFace.DrawJPGBitmap( aStrm, bTrueColorJPG, aSizePixel, Rectangle( aPoint, aSize ), aMask ); + m_rOuterFace.DrawJPGBitmap( aStrm, bTrueColorJPG, aSizePixel, Rectangle( aPoint, aSize ), aMask, i_Graphic ); else if ( aBitmapEx.IsTransparent() ) m_rOuterFace.DrawBitmapEx( aPoint, aSize, aBitmapEx ); else _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits