Kaydet (Commit) edda1e5f authored tarafından Miklos Vajna's avatar Miklos Vajna

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/53215Reviewed-by: 's avatarMiklos Vajna <vmiklos@collabora.co.uk>
Tested-by: 's avatarJenkins <ci@libreoffice.org>
üst e9c52f55
......@@ -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;
......
......@@ -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());
......
......@@ -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;
......
......@@ -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;
......
......@@ -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 ) )
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment