include/vcl/vectorgraphicdata.hxx | 1 vcl/inc/impgraph.hxx | 3 + vcl/source/gdi/impgraph.cxx | 65 ++++++++++++++--------------------- vcl/source/gdi/vectorgraphicdata.cxx | 27 ++++++++++++++ 4 files changed, 56 insertions(+), 40 deletions(-)
New commits: commit c2eb8d81e01ff016358c573b6d2f6c28e14f575a Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Fri Jul 12 10:06:30 2024 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Fri Jul 12 12:06:48 2024 +0200 tdf#129244: Let ImpGraphic update its buffer for new pixel sizes It used getVectorGraphicReplacement once, getting a bitmap with pixel size that depended on the default device DPI, unrelated to the needed bitmap size. It was not updated later, using the cached bitmap for any requested size. The DPI passed to convertPrimitive2DSequenceToBitmapEx must represent the relation between the vector logic size and the pixel size of the generated bitmap, not the target device DPI. This change introduces VectorGraphicData::getBitmap to obtain a bitmap for any requested pixel size, and uses it every time in the introduced ImpGraphic::updateBitmapFromVectorGraphic method every time it needs a new size of the image. Change-Id: Ife1305821fff28f0cd4070615ab032211a5d8c4f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170391 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/include/vcl/vectorgraphicdata.hxx b/include/vcl/vectorgraphicdata.hxx index 6c3a829ab95d..c10b068e384a 100644 --- a/include/vcl/vectorgraphicdata.hxx +++ b/include/vcl/vectorgraphicdata.hxx @@ -105,6 +105,7 @@ public: /// data read and evtl. on demand creation const basegfx::B2DRange& getRange() const; const std::deque<css::uno::Reference<css::graphic::XPrimitive2D>>& getPrimitive2DSequence() const; + BitmapEx getBitmap(const Size& pixelSize) const; const BitmapEx& getReplacement() const; BitmapChecksum GetChecksum() const; diff --git a/vcl/inc/impgraph.hxx b/vcl/inc/impgraph.hxx index e15845c9d99a..cad519c87e5c 100644 --- a/vcl/inc/impgraph.hxx +++ b/vcl/inc/impgraph.hxx @@ -200,7 +200,8 @@ private: const std::shared_ptr<VectorGraphicData>& getVectorGraphicData() const; /// Gets the bitmap replacement for a vector graphic. - BitmapEx getVectorGraphicReplacement() const; + // Hide volatile state of maBitmapEx when using maVectorGraphicData into this method + void updateBitmapFromVectorGraphic(const Size& pixelSize = {}) const; bool ensureAvailable () const; diff --git a/vcl/source/gdi/impgraph.cxx b/vcl/source/gdi/impgraph.cxx index d801fd14b8e2..57865bdf0bd4 100644 --- a/vcl/source/gdi/impgraph.cxx +++ b/vcl/source/gdi/impgraph.cxx @@ -487,16 +487,23 @@ bool ImpGraphic::makeAvailable() return ensureAvailable(); } -BitmapEx ImpGraphic::getVectorGraphicReplacement() const +void ImpGraphic::updateBitmapFromVectorGraphic(const Size& pixelSize) const { - BitmapEx aRet = maVectorGraphicData->getReplacement(); + assert (maVectorGraphicData); - if (maExPrefSize.getWidth() && maExPrefSize.getHeight()) + // use maBitmapEx as local buffer for rendered vector image + if (pixelSize.Width() && pixelSize.Height() + && (maBitmapEx.IsEmpty() || maBitmapEx.GetSizePixel() != pixelSize)) + { + const_cast<ImpGraphic*>(this)->maBitmapEx = maVectorGraphicData->getBitmap(pixelSize); + } + else // maVectorGraphicData caches the replacement, so updating unconditionally is cheap { - aRet.SetPrefSize(maExPrefSize); + const_cast<ImpGraphic*>(this)->maBitmapEx = maVectorGraphicData->getReplacement(); } - return aRet; + if (maExPrefSize.getWidth() && maExPrefSize.getHeight()) + const_cast<ImpGraphic*>(this)->maBitmapEx.SetPrefSize(maExPrefSize); } Bitmap ImpGraphic::getBitmap(const GraphicConversionParameters& rParameters) const @@ -507,11 +514,8 @@ Bitmap ImpGraphic::getBitmap(const GraphicConversionParameters& rParameters) con if( meType == GraphicType::Bitmap ) { - if(maVectorGraphicData && maBitmapEx.IsEmpty()) - { - // use maBitmapEx as local buffer for rendered svg - const_cast< ImpGraphic* >(this)->maBitmapEx = getVectorGraphicReplacement(); - } + if (!mpAnimation && maVectorGraphicData) + updateBitmapFromVectorGraphic(rParameters.getSizePixel()); const BitmapEx& rRetBmpEx = ( mpAnimation ? mpAnimation->GetBitmapEx() : maBitmapEx ); @@ -609,11 +613,8 @@ BitmapEx ImpGraphic::getBitmapEx(const GraphicConversionParameters& rParameters) if( meType == GraphicType::Bitmap ) { - if(maVectorGraphicData && maBitmapEx.IsEmpty()) - { - // use maBitmapEx as local buffer for rendered svg - const_cast< ImpGraphic* >(this)->maBitmapEx = getVectorGraphicReplacement(); - } + if (!mpAnimation && maVectorGraphicData) + updateBitmapFromVectorGraphic(rParameters.getSizePixel()); aRetBmpEx = ( mpAnimation ? mpAnimation->GetBitmapEx() : maBitmapEx ); @@ -692,6 +693,9 @@ const GDIMetaFile& ImpGraphic::getGDIMetaFile() const if (GraphicType::Bitmap == meType && !maMetaFile.GetActionSize()) { + if (maVectorGraphicData) + updateBitmapFromVectorGraphic(); + // #i119735# // Use the local maMetaFile as container for a metafile-representation // of the bitmap graphic. This will be done only once, thus be buffered. @@ -700,12 +704,6 @@ const GDIMetaFile& ImpGraphic::getGDIMetaFile() const // survive copying (change this if not wanted) ImpGraphic* pThat = const_cast< ImpGraphic* >(this); - if(maVectorGraphicData && maBitmapEx.IsEmpty()) - { - // use maBitmapEx as local buffer for rendered svg - pThat->maBitmapEx = getVectorGraphicReplacement(); - } - // #123983# directly create a metafile with the same PrefSize and PrefMapMode // the bitmap has, this will be an always correct metafile if(maBitmapEx.IsAlpha()) @@ -812,7 +810,7 @@ void ImpGraphic::setValuesForPrefSize(const Size& rPrefSize) { // used when importing a writer FlyFrame with SVG as graphic, added conversion // to allow setting the PrefSize at the BitmapEx to hold it - if (maVectorGraphicData && maBitmapEx.IsEmpty()) + if (maVectorGraphicData) { maExPrefSize = rPrefSize; } @@ -824,10 +822,7 @@ void ImpGraphic::setValuesForPrefSize(const Size& rPrefSize) const_cast< BitmapEx& >(mpAnimation->GetBitmapEx()).SetPrefSize(rPrefSize); } - if (!maExPrefSize.getWidth() || !maExPrefSize.getHeight()) - { - maBitmapEx.SetPrefSize(rPrefSize); - } + maBitmapEx.SetPrefSize(rPrefSize); } break; @@ -903,7 +898,7 @@ void ImpGraphic::setValuesForPrefMapMod(const MapMode& rPrefMapMode) if (maVectorGraphicData) { // ignore for Vector Graphic Data. If this is really used (except the grfcache) - // it can be extended by using maBitmapEx as buffer for getVectorGraphicReplacement() + // it can be extended by using maBitmapEx as buffer for updateBitmapFromVectorGraphic() } else { @@ -998,18 +993,14 @@ void ImpGraphic::draw(OutputDevice& rOutDev, const Point& rDestPt) const { case GraphicType::Bitmap: { - if (maVectorGraphicData && maBitmapEx.IsEmpty()) - { - // use maBitmapEx as local buffer for rendered svg - const_cast<ImpGraphic*>(this)->maBitmapEx = getVectorGraphicReplacement(); - } - if (mpAnimation) { mpAnimation->Draw(rOutDev, rDestPt); } else { + if (maVectorGraphicData) + updateBitmapFromVectorGraphic(); maBitmapEx.Draw(&rOutDev, rDestPt); } } @@ -1039,18 +1030,14 @@ void ImpGraphic::draw(OutputDevice& rOutDev, { case GraphicType::Bitmap: { - if (maVectorGraphicData && maBitmapEx.IsEmpty()) - { - // use maBitmapEx as local buffer for rendered svg - const_cast<ImpGraphic*>(this)->maBitmapEx = getVectorGraphicReplacement(); - } - if (mpAnimation) { mpAnimation->Draw(rOutDev, rDestPt, rDestSize); } else { + if (maVectorGraphicData) + updateBitmapFromVectorGraphic(rOutDev.LogicToPixel(rDestSize)); maBitmapEx.Draw(&rOutDev, rDestPt, rDestSize); } } diff --git a/vcl/source/gdi/vectorgraphicdata.cxx b/vcl/source/gdi/vectorgraphicdata.cxx index 2417276dd397..246356cb3a52 100644 --- a/vcl/source/gdi/vectorgraphicdata.cxx +++ b/vcl/source/gdi/vectorgraphicdata.cxx @@ -37,6 +37,7 @@ #include <comphelper/sequence.hxx> #include <comphelper/propertysequence.hxx> #include <comphelper/propertyvalue.hxx> +#include <pdf/PdfConfig.hxx> #include <rtl/crc.h> #include <vcl/svapp.hxx> #include <vcl/outdev.hxx> @@ -182,6 +183,32 @@ void VectorGraphicData::ensureReplacement() } } +BitmapEx VectorGraphicData::getBitmap(const Size& pixelSize) const +{ + if (getType() == VectorGraphicDataType::Pdf) + { + // use PDFium directly + const sal_Int32 nUsePageIndex = mnPageIndex > 0 ? mnPageIndex : 0; + const double dpi = vcl::pdf::getDefaultPdfResolutionDpi(); + basegfx::B2DTuple sizeMM100( + o3tl::convert(pixelSize.Width() / dpi / vcl::PDF_INSERT_MAGIC_SCALE_FACTOR, o3tl::Length::in, o3tl::Length::mm100), + o3tl::convert(pixelSize.Height() / dpi / vcl::PDF_INSERT_MAGIC_SCALE_FACTOR, o3tl::Length::in, o3tl::Length::mm100)); + std::vector<BitmapEx> aBitmaps; + vcl::RenderPDFBitmaps(maDataContainer.getData(), maDataContainer.getSize(), aBitmaps, + nUsePageIndex, 1, &sizeMM100); + if (!aBitmaps.empty()) + return aBitmaps[0]; + } + + if (getPrimitive2DSequence().empty()) + return {}; + + Size dpi( + std::round(pixelSize.Width() / o3tl::convert(maRange.getWidth(), o3tl::Length::mm100, o3tl::Length::in)), + std::round(pixelSize.Height() / o3tl::convert(maRange.getHeight(), o3tl::Length::mm100, o3tl::Length::in))); + return convertPrimitive2DSequenceToBitmapEx(maSequence, maRange, 4096 * 4096, o3tl::Length::mm100, dpi); +} + void VectorGraphicData::ensureSequenceAndRange() { if (mbSequenceCreated || maDataContainer.isEmpty())