From 01ded1e6d362dbcd7148334c6965d6ad00981d4a Mon Sep 17 00:00:00 2001 From: Bartosz Kosiorek Date: Tue, 8 Jun 2021 23:07:28 +0200 Subject: WMF tdf#55058 tdf#142722 Add implementation of BitBlt and StretchBlt With previous implementation, only BitBlt record with 1 bit color depth was supported and StretchBlt was not implemented at all. With this commit the support for 1 bit, 24 bit and 32 bit, for both BitBlt and StretchBlt were added. Change-Id: I061b2beae8c2f143ddff9c8c8bb64bf52f4cf502 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116873 Tested-by: Jenkins Reviewed-by: Bartosz Kosiorek --- emfio/qa/cppunit/emf/EmfImportTest.cxx | 82 +++++++++++++- emfio/qa/cppunit/wmf/data/TestBitBltStretchBlt.wmf | Bin 0 -> 918 bytes emfio/source/reader/wmfreader.cxx | 124 ++++++++------------- 3 files changed, 124 insertions(+), 82 deletions(-) create mode 100644 emfio/qa/cppunit/wmf/data/TestBitBltStretchBlt.wmf (limited to 'emfio') diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx b/emfio/qa/cppunit/emf/EmfImportTest.cxx index d949240a40b5..8c56190203b0 100644 --- a/emfio/qa/cppunit/emf/EmfImportTest.cxx +++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx @@ -62,6 +62,7 @@ class Test : public test::BootstrapFixture, public XmlTestTools, public unotest: void TestFillRegion(); void TestExtTextOutOpaqueAndClipTransform(); + void TestBitBltStretchBltWMF(); void TestExtTextOutOpaqueAndClipWMF(); void TestPaletteWMF(); void TestRoundrectWMF(); @@ -96,6 +97,8 @@ public: CPPUNIT_TEST(TestDrawPolyLine16WithClip); CPPUNIT_TEST(TestFillRegion); CPPUNIT_TEST(TestExtTextOutOpaqueAndClipTransform); + + CPPUNIT_TEST(TestBitBltStretchBltWMF); CPPUNIT_TEST(TestExtTextOutOpaqueAndClipWMF); CPPUNIT_TEST(TestPaletteWMF); CPPUNIT_TEST(TestRoundrectWMF); @@ -511,7 +514,6 @@ void Test::TestPolylinetoCloseStroke() "color", "#000000"); } - void Test::TestExtTextOutOpaqueAndClipTransform() { // tdf#142495 EMF records: SETBKCOLOR, SELECTOBJECT, EXTTEXTOUTW, MODIFYWORLDTRANSFORM, CREATEFONTINDIRECT. @@ -521,7 +523,6 @@ void Test::TestExtTextOutOpaqueAndClipTransform() xmlDocUniquePtr pDocument = dumper.dumpAndParse(comphelper::sequenceToContainer(aSequence)); CPPUNIT_ASSERT (pDocument); - assertXPath(pDocument, "/primitive2D/metafile/transform/textsimpleportion", 2); assertXPath(pDocument, "/primitive2D/metafile/transform/textsimpleportion[1]", "text", "No_rect- DLP-"); @@ -576,6 +577,73 @@ void Test::TestExtTextOutOpaqueAndClipTransform() "fontcolor", "#000000"); } +void Test::TestBitBltStretchBltWMF() +{ + // tdf#55058 tdf#142722 WMF records: BITBLT, STRETCHBLT. + Primitive2DSequence aSequence = parseEmf(u"/emfio/qa/cppunit/wmf/data/TestBitBltStretchBlt.wmf"); + CPPUNIT_ASSERT_EQUAL(1, static_cast(aSequence.getLength())); + drawinglayer::Primitive2dXmlDump dumper; + xmlDocUniquePtr pDocument = dumper.dumpAndParse(comphelper::sequenceToContainer(aSequence)); + CPPUNIT_ASSERT (pDocument); + + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap", 2); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[1]", + "xy11", "508"); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[1]", + "xy12", "0"); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[1]", + "xy13", "711"); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[1]", + "xy21", "0"); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[1]", + "xy22", "508"); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[1]", + "xy23", "508"); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[1]", + "height", "10"); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[1]", + "width", "10"); +#if !defined(MACOSX) && !defined(_WIN32) // TODO Bitmap display needs to be aligned for macOS and Windows + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[1]", + "checksum", "747141214295528493"); +#endif + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[1]/data", + 10); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[1]/data[1]", + "row", "000000,000000,000000,000000,000000,000000,000000,000000,000000,000000"); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[1]/data[4]", + "row", "000000,ffffff,000000,ffffff,000000,ffffff,000000,ffffff,000000,ffffff"); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[1]/data[5]", + "row", "ffffff,000000,ffffff,ffffff,000000,000000,000000,ffffff,ffffff,000000"); + + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[2]", + "xy11", "1524"); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[2]", + "xy12", "0"); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[2]", + "xy13", "1524"); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[2]", + "xy21", "0"); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[2]", + "xy22", "1016"); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[2]", + "xy23", "102"); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[2]", + "height", "10"); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[2]", + "width", "10"); +#if !defined(MACOSX) && !defined(_WIN32) // TODO Bitmap display needs to be aligned for macOS and Windows + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[2]", + "checksum", "3134789313661517563"); +#endif + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[2]/data", + 10); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[2]/data[1]", + "row", "000000,00001c,000038,000055,000071,00008d,0000aa,0000c6,0000e2,0000ff"); + assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap[2]/data[5]", + "row", "720000,721c1c,723838,725555,727171,72728d,55728d,39728d,1d728d,00728d"); +} + void Test::TestExtTextOutOpaqueAndClipWMF() { // tdf#53004 WMF records: SETBKCOLOR, SELECTOBJECT, EXTTEXTOUT, CREATEBRUSHINDIRECT. @@ -713,10 +781,16 @@ void Test::TestStretchDIBWMF() "height", "10"); assertXPath(pDocument, "/primitive2D/metafile/transform/mask/bitmap", "width", "10"); -#if !defined(MACOSX) // TODO DIB display needs to be fixed for macOS +#if !defined(MACOSX) // TODO DIB display needs to be aligned for macOS assertXPath(pDocument, "/primitive2D/metafile/transform/mask/bitmap", - "checksum", "275245357"); + "checksum", "14148300367030905133"); #endif + assertXPath(pDocument, "/primitive2D/metafile/transform/mask/bitmap/data", + 10); + assertXPath(pDocument, "/primitive2D/metafile/transform//mask/bitmap/data[1]", + "row", "000000,00001c,000038,000055,000071,00008d,0000aa,0000c6,0000e2,0000ff"); + assertXPath(pDocument, "/primitive2D/metafile/transform//mask/bitmap/data[5]", + "row", "720000,721c1c,723838,725555,727171,72728d,55728d,39728d,1d728d,00728d"); } void Test::TestPolyLineWidth() diff --git a/emfio/qa/cppunit/wmf/data/TestBitBltStretchBlt.wmf b/emfio/qa/cppunit/wmf/data/TestBitBltStretchBlt.wmf new file mode 100644 index 000000000000..030027c7522e Binary files /dev/null and b/emfio/qa/cppunit/wmf/data/TestBitBltStretchBlt.wmf differ diff --git a/emfio/source/reader/wmfreader.cxx b/emfio/source/reader/wmfreader.cxx index 65c2cff1f465..64dbf6658854 100644 --- a/emfio/source/reader/wmfreader.cxx +++ b/emfio/source/reader/wmfreader.cxx @@ -802,29 +802,19 @@ namespace emfio break; case W_META_BITBLT: + case W_META_STRETCHBLT: { - // 0-3 : nRasterOperation #93454# - // 4-5 : y offset of source bitmap - // 6-7 : x offset of source bitmap - // 8-9 : height of source and destination bitmap - // 10-11 : width of source and destination bitmap - // 12-13 : destination position y (in pixel) - // 14-15 : destination position x (in pixel) - // 16-17 : bitmap type - // 18-19 : Width Bitmap in Pixel - // 20-21 : Height Bitmap in Pixel - // 22-23 : bytes per scanline - // 24 : planes - // 25 : bitcount - sal_uInt32 nRasterOperation = 0; - sal_Int16 nYSrc = 0, nXSrc = 0, nSye = 0, nSxe = 0, nBitmapType = 0, nWidth = 0, nHeight = 0, nBytesPerScan = 0; + sal_Int16 nSrcHeight = 0, nSrcWidth = 0, nYSrc, nXSrc, nSye, nSxe, nBitmapType, nWidth, nHeight, nBytesPerScan; sal_uInt8 nPlanes, nBitCount; const bool bNoSourceBitmap = ( nRecordSize == ( static_cast< sal_uInt32 >( nFunc ) >> 8 ) + 3 ); mpInputStream->ReadUInt32( nRasterOperation ); SAL_INFO("emfio", "\t\t Raster operation: 0x" << std::hex << nRasterOperation << std::dec << ", No source bitmap: " << bNoSourceBitmap); + if( nFunc == W_META_STRETCHBLT ) + mpInputStream->ReadInt16( nSrcHeight ).ReadInt16( nSrcWidth ); + mpInputStream->ReadInt16( nYSrc ).ReadInt16( nXSrc ); if ( bNoSourceBitmap ) mpInputStream->SeekRel( 2 ); // Skip Reserved 2 bytes (it must be ignored) @@ -833,12 +823,13 @@ namespace emfio mpInputStream->ReadInt16( nBitmapType ).ReadInt16( nWidth ).ReadInt16( nHeight ).ReadInt16( nBytesPerScan ).ReadUChar( nPlanes ).ReadUChar( nBitCount ); SAL_INFO("emfio", "\t\t Bitmap type:" << nBitmapType << " Width:" << nWidth << " Height:" << nHeight << " WidthBytes:" << nBytesPerScan << " Planes: " << static_cast< sal_uInt16 >( nPlanes ) << " BitCount: " << static_cast< sal_uInt16 >( nBitCount ) ); - if ( bNoSourceBitmap ) + if ( bNoSourceBitmap || ( nBitCount == 4 ) || ( nBitCount == 8 ) || nPlanes != 1 ) { - SAL_WARN("emfio", "\t\t TODO The unsupported Bitmap record (without embedded source Bitmap). Please fill a bug."); + SAL_WARN("emfio", "\t\t TODO The unsupported Bitmap record. Please fill a bug."); break; } - bool bOk = nWidth && nHeight && nBytesPerScan > 0 && nPlanes == 1 && nBitCount == 1; + const vcl::PixelFormat ePixelFormat = vcl::bitDepthToPixelFormat( nBitCount ); + bool bOk = nWidth && nHeight && nBytesPerScan > 0 && nPlanes == 1 && ePixelFormat != vcl::PixelFormat::INVALID; if (bOk) { // must be enough data to fulfil the request @@ -851,25 +842,10 @@ namespace emfio } if (bOk) { - vcl::bitmap::RawBitmap aBmp( Size( nWidth, nHeight ), 24 ); - for (sal_uInt16 y = 0; y < nHeight && mpInputStream->good(); ++y) - { - sal_uInt16 x = 0; - for (sal_uInt16 scan = 0; scan < nBytesPerScan; scan++ ) - { - sal_Int8 nEightPixels = 0; - mpInputStream->ReadSChar( nEightPixels ); - for (sal_Int8 i = 7; i >= 0; i-- ) - { - if ( x < nWidth ) - { - aBmp.SetPixel( y, x, ((nEightPixels>>i)&1) ? COL_BLACK : COL_WHITE ); - } - x++; - } - } - } - BitmapEx aBitmap = vcl::bitmap::CreateFromData(std::move(aBmp)); + std::unique_ptr< sal_uInt8[] > pData; + pData.reset( new sal_uInt8[ nHeight * nBytesPerScan ] ); + mpInputStream->ReadBytes( pData.get(), nHeight * nBytesPerScan ); + BitmapEx aBitmap = vcl::bitmap::CreateFromData( pData.get(), nWidth, nHeight, nBytesPerScan, ePixelFormat, true ); if ( nSye && nSxe && ( nXSrc + nSxe <= nWidth ) && ( nYSrc + nSye <= nHeight ) ) @@ -885,7 +861,6 @@ namespace emfio case W_META_DIBBITBLT: case W_META_DIBSTRETCHBLT: - case W_META_STRETCHBLT: case W_META_STRETCHDIB: { sal_uInt32 nRasterOperation = 0; @@ -902,56 +877,49 @@ namespace emfio // nSrcHeight and nSrcWidth is the number of pixels that has to been used // If they are set to zero, it is as indicator not to scale the bitmap later if( nFunc == W_META_DIBSTRETCHBLT || - nFunc == W_META_STRETCHBLT || nFunc == W_META_STRETCHDIB ) mpInputStream->ReadInt16( nSrcHeight ).ReadInt16( nSrcWidth ); // nYSrc and nXSrc is the offset of the first pixel mpInputStream->ReadInt16( nYSrc ).ReadInt16( nXSrc ); - // TODO Add META_STRETCHBLT support, which is defined by Bitmap16 Object - if( nFunc == W_META_DIBBITBLT || - nFunc == W_META_DIBSTRETCHBLT || - nFunc == W_META_STRETCHDIB ) - { - if ( bNoSourceBitmap ) - mpInputStream->SeekRel( 2 ); // Skip Reserved 2 bytes (it must be ignored) + if ( bNoSourceBitmap ) + mpInputStream->SeekRel( 2 ); // Skip Reserved 2 bytes (it must be ignored) - Size aDestSize( ReadYXExt() ); - if ( aDestSize.Width() && aDestSize.Height() ) // #92623# do not try to read buggy bitmaps + Size aDestSize( ReadYXExt() ); + if ( aDestSize.Width() && aDestSize.Height() ) // #92623# do not try to read buggy bitmaps + { + tools::Rectangle aDestRect( ReadYX(), aDestSize ); + if ( !bNoSourceBitmap ) { - tools::Rectangle aDestRect( ReadYX(), aDestSize ); - if ( !bNoSourceBitmap ) - { - // tdf#142625 Read the DIBHeader and check if bitmap is supported - // If bitmap is not supported don't run ReadDIB, as it will interrupt image processing - const auto nOldPos(mpInputStream->Tell()); - sal_uInt32 nHeaderSize; - sal_uInt16 nBitCount; - mpInputStream->ReadUInt32( nHeaderSize ); - if ( nHeaderSize == 0xC ) // BitmapCoreHeader - mpInputStream->SeekRel( 6 ); // skip Width (16), Height (16), Planes (16) - else - mpInputStream->SeekRel( 10 ); // skip Width (32), Height (32), Planes (16) - mpInputStream->ReadUInt16( nBitCount ); - if ( nBitCount == 0 ) // TODO Undefined BitCount (JPEG/PNG), which are not supported - break; - mpInputStream->Seek(nOldPos); - - if ( !ReadDIB( aBmp, *mpInputStream, false ) ) - SAL_WARN( "emfio", "\tTODO Read DIB failed. Interrupting processing whole image. Please report bug report." ); - } - // test if it is sensible to crop - if ( nSrcHeight && nSrcWidth && - ( nXSrc + nSrcWidth <= aBmp.GetSizePixel().Width() ) && - ( nYSrc + nSrcHeight <= aBmp.GetSizePixel().Height() ) ) - { - tools::Rectangle aCropRect( Point( nXSrc, nYSrc ), Size( nSrcWidth, nSrcHeight ) ); - aBmp.Crop( aCropRect ); - } + // tdf#142625 Read the DIBHeader and check if bitmap is supported + // If bitmap is not supported don't run ReadDIB, as it will interrupt image processing + const auto nOldPos(mpInputStream->Tell()); + sal_uInt32 nHeaderSize; + sal_uInt16 nBitCount; + mpInputStream->ReadUInt32( nHeaderSize ); + if ( nHeaderSize == 0xC ) // BitmapCoreHeader + mpInputStream->SeekRel( 6 ); // skip Width (16), Height (16), Planes (16) + else + mpInputStream->SeekRel( 10 ); // skip Width (32), Height (32), Planes (16) + mpInputStream->ReadUInt16( nBitCount ); + if ( nBitCount == 0 ) // TODO Undefined BitCount (JPEG/PNG), which are not supported + break; + mpInputStream->Seek(nOldPos); - maBmpSaveList.emplace_back(new BSaveStruct(aBmp, aDestRect, nRasterOperation)); + if ( !ReadDIB( aBmp, *mpInputStream, false ) ) + SAL_WARN( "emfio", "\tTODO Read DIB failed. Interrupting processing whole image. Please report bug report." ); } + // test if it is sensible to crop + if ( nSrcHeight && nSrcWidth && + ( nXSrc + nSrcWidth <= aBmp.GetSizePixel().Width() ) && + ( nYSrc + nSrcHeight <= aBmp.GetSizePixel().Height() ) ) + { + tools::Rectangle aCropRect( Point( nXSrc, nYSrc ), Size( nSrcWidth, nSrcHeight ) ); + aBmp.Crop( aCropRect ); + } + + maBmpSaveList.emplace_back(new BSaveStruct(aBmp, aDestRect, nRasterOperation)); } } break; -- cgit on> LibreOffice 核心代码仓库文档基金会
summaryrefslogtreecommitdiff
AgeCommit message (Expand)Author