diff options
author | Luke Deller <luke@deller.id.au> | 2019-10-31 01:36:22 +1100 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2019-10-31 08:51:49 +0100 |
commit | ef3dabd1f814d1b005efc5d5144978c1d26a8e73 (patch) | |
tree | 12e670ed7d28c2cd054aa3a3af48be42f4df468f /vcl | |
parent | 0dd56a4a745266dcf88d43150ef1d798619ab522 (diff) |
Fix IsTransparent() for unloaded graphics
Fix Graphic::IsAlpha() and Graphic::IsTransparent() for unloaded
graphics. This fixes tdf#118036.
GraphicDescriptor::Detect(true) is currently used to read the image size
from the header of images which are not being fully loaded yet. This
change extends GraphicDescriptor to also report whether the image
supports transparency or alpha, implemented only for PNG format so far.
Change-Id: I1753c0d11491f1dc518e23da8d7b3842945770cb
Reviewed-on: https://gerrit.libreoffice.org/81785
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/qa/cppunit/GraphicTest.cxx | 55 | ||||
-rw-r--r-- | vcl/source/filter/graphicfilter2.cxx | 72 | ||||
-rw-r--r-- | vcl/source/gdi/impgraph.cxx | 16 |
3 files changed, 98 insertions, 45 deletions
diff --git a/vcl/qa/cppunit/GraphicTest.cxx b/vcl/qa/cppunit/GraphicTest.cxx index af5985b01f99..56e05c8bf3de 100644 --- a/vcl/qa/cppunit/GraphicTest.cxx +++ b/vcl/qa/cppunit/GraphicTest.cxx @@ -28,25 +28,40 @@ class GraphicTest : public CppUnit::TestFixture void testUnloadedGraphic(); void testUnloadedGraphicLoading(); void testUnloadedGraphicWmf(); + void testUnloadedGraphicAlpha(); CPPUNIT_TEST_SUITE(GraphicTest); CPPUNIT_TEST(testUnloadedGraphic); CPPUNIT_TEST(testUnloadedGraphicLoading); CPPUNIT_TEST(testUnloadedGraphicWmf); + CPPUNIT_TEST(testUnloadedGraphicAlpha); CPPUNIT_TEST_SUITE_END(); }; -BitmapEx createBitmap() +BitmapEx createBitmap(bool alpha = false) { - Bitmap aBitmap(Size(100, 100), 24); + Bitmap aBitmap(Size(120, 100), 24); aBitmap.Erase(COL_LIGHTRED); - return BitmapEx(aBitmap); + aBitmap.SetPrefSize(Size(6000, 5000)); + aBitmap.SetPrefMapMode(MapMode(MapUnit::Map100thMM)); + + if (alpha) + { + sal_uInt8 uAlphaValue = 0x80; + AlphaMask aAlphaMask(Size(120, 100), &uAlphaValue); + + return BitmapEx(aBitmap, aAlphaMask); + } + else + { + return BitmapEx(aBitmap); + } } -void createBitmapAndExportForType(SvStream& rStream, OUString const& sType) +void createBitmapAndExportForType(SvStream& rStream, OUString const& sType, bool alpha) { - BitmapEx aBitmapEx = createBitmap(); + BitmapEx aBitmapEx = createBitmap(alpha); uno::Sequence<beans::PropertyValue> aFilterData; GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); @@ -56,11 +71,11 @@ void createBitmapAndExportForType(SvStream& rStream, OUString const& sType) rStream.Seek(STREAM_SEEK_TO_BEGIN); } -Graphic makeUnloadedGraphic(OUString const& sType) +Graphic makeUnloadedGraphic(OUString const& sType, bool alpha = false) { SvMemoryStream aStream; GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); - createBitmapAndExportForType(aStream, sType); + createBitmapAndExportForType(aStream, sType, alpha); return rGraphicFilter.ImportUnloadedGraphic(aStream); } @@ -81,10 +96,15 @@ void GraphicTest::testUnloadedGraphic() // check GetSizePixel doesn't load graphic aGraphic = makeUnloadedGraphic("png"); CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); - CPPUNIT_ASSERT_EQUAL(100L, aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(120L, aGraphic.GetSizePixel().Width()); CPPUNIT_ASSERT_EQUAL(100L, aGraphic.GetSizePixel().Height()); CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + // check GetPrefSize doesn't load graphic + CPPUNIT_ASSERT_EQUAL(6000L, aGraphic.GetPrefSize().Width()); + CPPUNIT_ASSERT_EQUAL(5000L, aGraphic.GetPrefSize().Height()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + // check GetSizeBytes loads graphic CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); CPPUNIT_ASSERT(aGraphic.GetSizeBytes() > 0); @@ -101,7 +121,7 @@ void GraphicTest::testUnloadedGraphicLoading() // check available CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); - CPPUNIT_ASSERT_EQUAL(100L, aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(120L, aGraphic.GetSizePixel().Width()); CPPUNIT_ASSERT_EQUAL(100L, aGraphic.GetSizePixel().Height()); CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); CPPUNIT_ASSERT(aGraphic.GetSizeBytes() > 0); @@ -157,6 +177,23 @@ void GraphicTest::testUnloadedGraphicWmf() CPPUNIT_ASSERT_EQUAL(Size(42, 42), aGraphic.GetPrefSize()); } +void GraphicTest::testUnloadedGraphicAlpha() +{ + // make unloaded test graphic with alpha + Graphic aGraphic = makeUnloadedGraphic("png", true); + + CPPUNIT_ASSERT_EQUAL(true, aGraphic.IsAlpha()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.IsTransparent()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + // make unloaded test graphic without alpha + aGraphic = makeUnloadedGraphic("png", false); + + CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsAlpha()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsTransparent()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); +} + } // namespace CPPUNIT_TEST_SUITE_REGISTRATION(GraphicTest); diff --git a/vcl/source/filter/graphicfilter2.cxx b/vcl/source/filter/graphicfilter2.cxx index 03e1ac228067..5640e7c96ed2 100644 --- a/vcl/source/filter/graphicfilter2.cxx +++ b/vcl/source/filter/graphicfilter2.cxx @@ -99,6 +99,8 @@ void GraphicDescriptor::ImpConstruct() nBitsPerPixel = 0; nPlanes = 0; mnNumberOfImageComponents = 0; + bIsTransparent = false; + bIsAlpha = false; } bool GraphicDescriptor::ImpDetectBMP( SvStream& rStm, bool bExtendedInfo ) @@ -548,6 +550,11 @@ bool GraphicDescriptor::ImpDetectPNG( SvStream& rStm, bool bExtendedInfo ) rStm.ReadUChar( cByte ); nBitsPerPixel = cByte; + // Colour type - check whether it supports alpha values + sal_uInt8 cColType = 0; + rStm.ReadUChar( cColType ); + bIsAlpha = bIsTransparent = ( cColType == 4 || cColType == 6 ); + // Planes always 1; // compression always nPlanes = 1; @@ -555,46 +562,53 @@ bool GraphicDescriptor::ImpDetectPNG( SvStream& rStm, bool bExtendedInfo ) sal_uInt32 nLen32 = 0; nTemp32 = 0; - rStm.SeekRel( 8 ); + rStm.SeekRel( 7 ); - // read up to the pHYs-Chunk or the start of the image + // read up to the start of the image rStm.ReadUInt32( nLen32 ); rStm.ReadUInt32( nTemp32 ); - while( ( nTemp32 != 0x70485973 ) && ( nTemp32 != 0x49444154 ) - && rStm.good() ) + while( ( nTemp32 != 0x49444154 ) && rStm.good() ) { - rStm.SeekRel( 4 + nLen32 ); - rStm.ReadUInt32( nLen32 ); - rStm.ReadUInt32( nTemp32 ); - } + if ( nTemp32 == 0x70485973 ) // physical pixel dimensions + { + sal_uLong nXRes; + sal_uLong nYRes; - if (nTemp32 == 0x70485973 && rStm.good()) - { - sal_uLong nXRes; - sal_uLong nYRes; + // horizontal resolution + nTemp32 = 0; + rStm.ReadUInt32( nTemp32 ); + nXRes = nTemp32; - // horizontal resolution - nTemp32 = 0; - rStm.ReadUInt32( nTemp32 ); - nXRes = nTemp32; + // vertical resolution + nTemp32 = 0; + rStm.ReadUInt32( nTemp32 ); + nYRes = nTemp32; - // vertical resolution - nTemp32 = 0; - rStm.ReadUInt32( nTemp32 ); - nYRes = nTemp32; + // unit + cByte = 0; + rStm.ReadUChar( cByte ); - // unit - cByte = 0; - rStm.ReadUChar( cByte ); + if ( cByte ) + { + if ( nXRes ) + aLogSize.setWidth( (aPixSize.Width() * 100000) / nXRes ); - if ( cByte ) - { - if ( nXRes ) - aLogSize.setWidth( (aPixSize.Width() * 100000) / nXRes ); + if ( nYRes ) + aLogSize.setHeight( (aPixSize.Height() * 100000) / nYRes ); + } - if ( nYRes ) - aLogSize.setHeight( (aPixSize.Height() * 100000) / nYRes ); + nLen32 -= 9; + } + else if ( nTemp32 == 0x74524e53 ) // transparency + { + bIsTransparent = true; + bIsAlpha = ( cColType != 0 && cColType != 2 ); } + + // skip forward to next chunk + rStm.SeekRel( 4 + nLen32 ); + rStm.ReadUInt32( nLen32 ); + rStm.ReadUInt32( nTemp32 ); } } } diff --git a/vcl/source/gdi/impgraph.cxx b/vcl/source/gdi/impgraph.cxx index 0a215fede7b0..17c371e6d77f 100644 --- a/vcl/source/gdi/impgraph.cxx +++ b/vcl/source/gdi/impgraph.cxx @@ -545,10 +545,11 @@ void ImpGraphic::ImplSetPrepared(bool bAnimated, const Size* pSizeHint) maSwapInfo.maPrefSize = *pSizeHint; maSwapInfo.maPrefMapMode = MapMode(MapUnit::Map100thMM); } - else + + GraphicDescriptor aDescriptor(aMemoryStream, nullptr); + if (aDescriptor.Detect(true)) { - GraphicDescriptor aDescriptor(aMemoryStream, nullptr); - if (aDescriptor.Detect(true)) + if (!pSizeHint) { // If we have logic size, work with that, as later pixel -> logic // conversion will work with the output device DPI, not the graphic @@ -564,14 +565,15 @@ void ImpGraphic::ImplSetPrepared(bool bAnimated, const Size* pSizeHint) maSwapInfo.maPrefSize = aDescriptor.GetSizePixel(); maSwapInfo.maPrefMapMode = MapMode(MapUnit::MapPixel); } - - maSwapInfo.maSizePixel = aDescriptor.GetSizePixel(); } + + maSwapInfo.maSizePixel = aDescriptor.GetSizePixel(); + maSwapInfo.mbIsTransparent = aDescriptor.IsTransparent(); + maSwapInfo.mbIsAlpha = aDescriptor.IsAlpha(); } + maSwapInfo.mnAnimationLoopCount = 0; maSwapInfo.mbIsEPS = false; - maSwapInfo.mbIsTransparent = false; - maSwapInfo.mbIsAlpha = false; maSwapInfo.mbIsAnimated = bAnimated; } |