diff options
author | Miklos Vajna <vmiklos@collabora.co.uk> | 2018-04-20 16:32:00 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2018-04-20 21:04:35 +0200 |
commit | edda1e5fc8113aa4744e32f97c96a3cc311485ca (patch) | |
tree | b6da5a4a637a9a3ae3ed9307fe59d6f1df80b197 | |
parent | e9c52f55f0cc7155d6883e4d2abf14f1638b03b3 (diff) |
DOCX import: lazy-read images without external headers
So that similar to ODT, images are not loaded on file open, only when
the user scrolls there.
Notes:
1) GraphicDescriptor::ImpDetectJPG() would try to calculate the logic
size before the pixel size is available, so the logic size would be 0x0.
Also, ImpGraphic::ImplSetPrepared() would always work with a pixel map
mode. Any of these two would result in a failure of
testDMLShapeFillBitmapCrop in CppunitTest_sw_ooxmlexport6.
2) Lazy-loading seems to (at the moment) not recognize EMF files, so
don't lazy-load in case an external header is provided. This probably
has to be revisited, since the ODF import doesn't go via
GraphicProvider::queryGraphic().
Change-Id: I44754e659effebca8339715df114dbaadb9b5e9f
Reviewed-on: https://gerrit.libreoffice.org/53215
Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Tested-by: Jenkins <ci@libreoffice.org>
-rw-r--r-- | oox/source/helper/graphichelper.cxx | 15 | ||||
-rw-r--r-- | sw/qa/extras/ooxmlimport/data/image-lazy-read.docx | bin | 0 -> 9392 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlimport/ooxmlimport.cxx | 8 | ||||
-rw-r--r-- | vcl/source/filter/graphicfilter2.cxx | 9 | ||||
-rw-r--r-- | vcl/source/gdi/impgraph.cxx | 16 | ||||
-rw-r--r-- | vcl/source/graphic/UnoGraphicProvider.cxx | 19 |
6 files changed, 58 insertions, 9 deletions
diff --git a/oox/source/helper/graphichelper.cxx b/oox/source/helper/graphichelper.cxx index 7f4262de787c..002d54b946b5 100644 --- a/oox/source/helper/graphichelper.cxx +++ b/oox/source/helper/graphichelper.cxx @@ -238,11 +238,13 @@ Reference< XGraphic > GraphicHelper::importGraphic( const Reference< XInputStrea Reference< XGraphic > xGraphic; if( rxInStrm.is() && mxGraphicProvider.is() ) try { - Sequence< PropertyValue > aArgs( 1 ); + Sequence< PropertyValue > aArgs( 2 ); aArgs[ 0 ].Name = "InputStream"; aArgs[ 0 ].Value <<= rxInStrm; + aArgs[ 1 ].Name = "LazyRead"; + aArgs[ 1 ].Value <<= true; - if ( pExtHeader && pExtHeader->mapMode > 0 ) + if ( pExtHeader ) { aArgs.realloc( aArgs.getLength() + 1 ); Sequence< PropertyValue > aFilterData( 3 ); @@ -252,8 +254,8 @@ Reference< XGraphic > GraphicHelper::importGraphic( const Reference< XInputStrea aFilterData[ 1 ].Value <<= pExtHeader->yExt; aFilterData[ 2 ].Name = "ExternalMapMode"; aFilterData[ 2 ].Value <<= pExtHeader->mapMode; - aArgs[ 1 ].Name = "FilterData"; - aArgs[ 1 ].Value <<= aFilterData; + aArgs[ 2 ].Name = "FilterData"; + aArgs[ 2 ].Value <<= aFilterData; } xGraphic = mxGraphicProvider->queryGraphic( aArgs ); @@ -339,6 +341,11 @@ Reference< XGraphic > GraphicHelper::importEmbeddedGraphic( const OUString& rStr EmbeddedGraphicMap::const_iterator aIt = maEmbeddedGraphics.find( rStreamName ); if( aIt == maEmbeddedGraphics.end() ) { + // TODO make lazy-load work for EMF as well. + WmfExternal aHeader; + if (rStreamName.endsWith(".emf") && !pExtHeader) + pExtHeader = &aHeader; + xGraphic = importGraphic(mxStorage->openInputStream(rStreamName), pExtHeader); if( xGraphic.is() ) maEmbeddedGraphics[ rStreamName ] = xGraphic; diff --git a/sw/qa/extras/ooxmlimport/data/image-lazy-read.docx b/sw/qa/extras/ooxmlimport/data/image-lazy-read.docx Binary files differnew file mode 100644 index 000000000000..faf80e41dcd6 --- /dev/null +++ b/sw/qa/extras/ooxmlimport/data/image-lazy-read.docx diff --git a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx index 439658a63b39..7b60b191df67 100644 --- a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx +++ b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx @@ -1422,6 +1422,14 @@ DECLARE_OOXMLIMPORT_TEST(testTdf108714, "tdf108714.docx") CPPUNIT_ASSERT_EQUAL(style::BreakType_PAGE_BEFORE, breakType); } +DECLARE_OOXMLIMPORT_TEST(testImageLazyRead, "image-lazy-read.docx") +{ + auto xGraphic = getProperty<uno::Reference<graphic::XGraphic>>(getShape(1), "Graphic"); + Graphic aGraphic(xGraphic); + // This failed, import loaded the graphic, it wasn't lazy-read. + CPPUNIT_ASSERT(!aGraphic.isAvailable()); +} + DECLARE_OOXMLIMPORT_TEST(testTdf108995, "xml_space.docx") { CPPUNIT_ASSERT_EQUAL(1, getParagraphs()); diff --git a/vcl/source/filter/graphicfilter2.cxx b/vcl/source/filter/graphicfilter2.cxx index f35ac1c37c81..4439c2ab8b50 100644 --- a/vcl/source/filter/graphicfilter2.cxx +++ b/vcl/source/filter/graphicfilter2.cxx @@ -262,6 +262,7 @@ bool GraphicDescriptor::ImpDetectJPG( SvStream& rStm, bool bExtendedInfo ) bool bScanFailure = false; bool bScanFinished = false; + MapMode aMap; while (!bScanFailure && !bScanFinished && rStm.good()) { @@ -331,7 +332,6 @@ bool GraphicDescriptor::ImpDetectJPG( SvStream& rStm, bool bExtendedInfo ) // setting the logical size if ( nUnits && nHorizontalResolution && nVerticalResolution ) { - MapMode aMap; aMap.SetMapUnit( nUnits == 1 ? MapUnit::MapInch : MapUnit::MapCM ); aMap.SetScaleX( Fraction( 1, nHorizontalResolution ) ); aMap.SetScaleY( Fraction( 1, nVerticalResolution ) ); @@ -380,6 +380,13 @@ bool GraphicDescriptor::ImpDetectJPG( SvStream& rStm, bool bExtendedInfo ) nBitsPerPixel = ( nNumberOfImageComponents == 3 ? 24 : nNumberOfImageComponents == 1 ? 8 : 0 ); nPlanes = 1; + if (aMap.GetMapUnit() != MapUnit::MapPixel) + // We already know the DPI, but the + // pixel size arrived later, so do the + // conversion again. + aLogSize = OutputDevice::LogicToLogic( + aPixSize, aMap, MapMode(MapUnit::Map100thMM)); + bScanFinished = true; } break; diff --git a/vcl/source/gdi/impgraph.cxx b/vcl/source/gdi/impgraph.cxx index 9cd9bbb11717..1a9cca6ce0da 100644 --- a/vcl/source/gdi/impgraph.cxx +++ b/vcl/source/gdi/impgraph.cxx @@ -523,8 +523,20 @@ void ImpGraphic::ImplSetPrepared() GraphicDescriptor aDescriptor(aMemoryStream, nullptr); if (aDescriptor.Detect(true)) { - maSwapInfo.maPrefSize = aDescriptor.GetSizePixel(); - maSwapInfo.maPrefMapMode = MapMode(MapUnit::MapPixel); + // If we have logic size, work with that, as later pixel -> logic + // conversion will work with the output device DPI, not the graphic + // DPI. + Size aLogSize = aDescriptor.GetSize_100TH_MM(); + if (aLogSize.getWidth() && aLogSize.getHeight()) + { + maSwapInfo.maPrefSize = aLogSize; + maSwapInfo.maPrefMapMode = MapMode(MapUnit::Map100thMM); + } + else + { + maSwapInfo.maPrefSize = aDescriptor.GetSizePixel(); + maSwapInfo.maPrefMapMode = MapMode(MapUnit::MapPixel); + } } maSwapInfo.mnAnimationLoopCount = 0; maSwapInfo.mbIsAnimated = false; diff --git a/vcl/source/graphic/UnoGraphicProvider.cxx b/vcl/source/graphic/UnoGraphicProvider.cxx index 50c273006b85..8b9ccb93bf94 100644 --- a/vcl/source/graphic/UnoGraphicProvider.cxx +++ b/vcl/source/graphic/UnoGraphicProvider.cxx @@ -304,6 +304,7 @@ uno::Reference< ::graphic::XGraphic > SAL_CALL GraphicProvider::queryGraphic( co uno::Sequence< ::beans::PropertyValue > aFilterData; + bool bLazyRead = false; for( sal_Int32 i = 0; ( i < rMediaProperties.getLength() ) && !pIStm && !xRet.is(); ++i ) { const OUString aName( rMediaProperties[ i ].Name ); @@ -327,6 +328,8 @@ uno::Reference< ::graphic::XGraphic > SAL_CALL GraphicProvider::queryGraphic( co { aValue >>= aFilterData; } + else if (aName == "LazyRead") + aValue >>= bLazyRead; } // Check for the goal width and height if they are defined @@ -352,6 +355,9 @@ uno::Reference< ::graphic::XGraphic > SAL_CALL GraphicProvider::queryGraphic( co } } + if (bLazyRead && aFilterData.hasElements()) + bLazyRead = false; + SolarMutexGuard g; if( xIStm.is() ) @@ -392,8 +398,17 @@ uno::Reference< ::graphic::XGraphic > SAL_CALL GraphicProvider::queryGraphic( co if ( nExtMapMode > 0 ) pExtHeader = &aExtHeader; - ErrCode error = rFilter.ImportGraphic( aVCLGraphic, aPath, *pIStm, - GRFILTER_FORMAT_DONTKNOW, nullptr, GraphicFilterImportFlags::NONE, pExtHeader ); + ErrCode error = ERRCODE_NONE; + if (bLazyRead) + { + Graphic aGraphic = rFilter.ImportUnloadedGraphic(*pIStm); + if (aGraphic) + aVCLGraphic = aGraphic; + } + if (!aVCLGraphic) + error = rFilter.ImportGraphic(aVCLGraphic, aPath, *pIStm, GRFILTER_FORMAT_DONTKNOW, + nullptr, GraphicFilterImportFlags::NONE, pExtHeader); + if( (error == ERRCODE_NONE ) && ( aVCLGraphic.GetType() != GraphicType::NONE ) ) { |