diff options
author | Noel Grandin <noel.grandin@collabora.co.uk> | 2019-07-04 14:26:41 +0200 |
---|---|---|
committer | Noel Grandin <noel.grandin@collabora.co.uk> | 2019-07-05 08:46:36 +0200 |
commit | 7f4fe205c4b1baf01115a9e0d74655818d03ec40 (patch) | |
tree | f5aead6ec8b31203aeaf8b1c68e2ff736dcd97ea | |
parent | 849b837d1a3b185a8dd893a8f6eaed53605bcab1 (diff) |
move the contour-finding code inside vcl
Change-Id: Iac52b72831868a917fc445e970edabc1c2585b55
Reviewed-on: https://gerrit.libreoffice.org/75080
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
-rw-r--r-- | include/svx/xoutbmp.hxx | 10 | ||||
-rw-r--r-- | include/vcl/bitmapex.hxx | 4 | ||||
-rw-r--r-- | svx/source/dialog/_contdlg.cxx | 9 | ||||
-rw-r--r-- | svx/source/xoutdev/_xoutbmp.cxx | 230 | ||||
-rw-r--r-- | vcl/source/gdi/bitmapex.cxx | 232 |
5 files changed, 242 insertions, 243 deletions
diff --git a/include/svx/xoutbmp.hxx b/include/svx/xoutbmp.hxx index 09d55e3d8d51..8635ed86a30c 100644 --- a/include/svx/xoutbmp.hxx +++ b/include/svx/xoutbmp.hxx @@ -33,9 +33,6 @@ enum class XOutFlags { NONE = 0x00000000, MirrorHorz = 0x00000001, MirrorVert = 0x00000010, - ContourHorz = 0x00000001, - ContourVert = 0x00000002, - ContourEdgeDetect = 0x00000004, DontAddExtension = 0x00000008, DontExpandFilename = 0x00010000, UseGifIfPossible = 0x00020000, @@ -43,7 +40,7 @@ enum class XOutFlags { UseNativeIfPossible = 0x00080000, }; namespace o3tl { - template<> struct typed_flags<XOutFlags> : is_typed_flags<XOutFlags, 0x000f001f> {}; + template<> struct typed_flags<XOutFlags> : is_typed_flags<XOutFlags, 0x000f0019> {}; } class GraphicFilter; @@ -72,11 +69,6 @@ public: static ErrCode ExportGraphic( const Graphic& rGraphic, const INetURLObject& rURL, GraphicFilter& rFilter, const sal_uInt16 nFormat, const css::uno::Sequence< css::beans::PropertyValue >* pFilterData ); - - static Bitmap DetectEdges( const Bitmap& rBmp, const sal_uInt8 cThreshold ); - - static tools::Polygon GetContour( const Bitmap& rBmp, const XOutFlags nContourFlags, - const tools::Rectangle* pWorkRect ); }; #endif // INCLUDED_SVX_XOUTBMP_HXX diff --git a/include/vcl/bitmapex.hxx b/include/vcl/bitmapex.hxx index c3d27edf9d91..71da7cb45dc8 100644 --- a/include/vcl/bitmapex.hxx +++ b/include/vcl/bitmapex.hxx @@ -318,6 +318,10 @@ public: */ void ReplaceTransparency( const Color& rColor ); + /** Get contours in image */ + tools::Polygon GetContour( bool bContourEdgeDetect, bool bContourVert, + const tools::Rectangle* pWorkRect ); + /** Change various global color characteristics @param nLuminancePercent diff --git a/svx/source/dialog/_contdlg.cxx b/svx/source/dialog/_contdlg.cxx index 2832eece6ec2..cc7da3c25fd6 100644 --- a/svx/source/dialog/_contdlg.cxx +++ b/svx/source/dialog/_contdlg.cxx @@ -86,7 +86,8 @@ tools::PolyPolygon SvxContourDlg::CreateAutoContour( const Graphic& rGraphic, const tools::Rectangle* pRect ) { Bitmap aBmp; - XOutFlags nContourFlags = XOutFlags::ContourHorz; + bool bContourEdgeDetect = false; + bool bContourVert = false; if ( rGraphic.GetType() == GraphicType::Bitmap ) { @@ -125,7 +126,7 @@ tools::PolyPolygon SvxContourDlg::CreateAutoContour( const Graphic& rGraphic, else { aBmp = rGraphic.GetBitmapEx().GetBitmap(); - nContourFlags |= XOutFlags::ContourEdgeDetect; + bContourEdgeDetect = true; } } else if( rGraphic.GetType() != GraphicType::NONE ) @@ -157,13 +158,13 @@ tools::PolyPolygon SvxContourDlg::CreateAutoContour( const Graphic& rGraphic, aBmp = pVDev->GetBitmap( aPt, aSizePix ); } - nContourFlags |= XOutFlags::ContourEdgeDetect; + bContourEdgeDetect = true; } aBmp.SetPrefSize( rGraphic.GetPrefSize() ); aBmp.SetPrefMapMode( rGraphic.GetPrefMapMode() ); - return tools::PolyPolygon( XOutBitmap::GetContour( aBmp, nContourFlags, pRect ) ); + return tools::PolyPolygon( BitmapEx(aBmp).GetContour( bContourEdgeDetect, bContourVert, pRect ) ); } // Loop through to super class, no virtual Methods to not become incompatible diff --git a/svx/source/xoutdev/_xoutbmp.cxx b/svx/source/xoutdev/_xoutbmp.cxx index decc1de34565..4d33fda7534d 100644 --- a/svx/source/xoutdev/_xoutbmp.cxx +++ b/svx/source/xoutdev/_xoutbmp.cxx @@ -422,235 +422,5 @@ ErrCode XOutBitmap::ExportGraphic( const Graphic& rGraphic, const INetURLObject& return nRet; } -Bitmap XOutBitmap::DetectEdges( const Bitmap& rBmp, const sal_uInt8 cThreshold ) -{ - const Size aSize( rBmp.GetSizePixel() ); - Bitmap aRetBmp; - - if( ( aSize.Width() > 2 ) && ( aSize.Height() > 2 ) ) - { - Bitmap aWorkBmp( rBmp ); - - if( aWorkBmp.Convert( BmpConversion::N8BitGreys ) ) - { - bool bRet = false; - - ScopedVclPtr<VirtualDevice> pVirDev(VclPtr<VirtualDevice>::Create()); - pVirDev->SetOutputSizePixel(aSize); - Bitmap::ScopedReadAccess pReadAcc(aWorkBmp); - - if( pReadAcc ) - { - const long nWidth = aSize.Width(); - const long nWidth2 = nWidth - 2; - const long nHeight = aSize.Height(); - const long nHeight2 = nHeight - 2; - const long lThres2 = static_cast<long>(cThreshold) * cThreshold; - long nSum1; - long nSum2; - long lGray; - - // initialize border with white pixels - pVirDev->SetLineColor( COL_WHITE ); - pVirDev->DrawLine( Point(), Point( nWidth - 1, 0L ) ); - pVirDev->DrawLine( Point( nWidth - 1, 0L ), Point( nWidth - 1, nHeight - 1 ) ); - pVirDev->DrawLine( Point( nWidth - 1, nHeight - 1 ), Point( 0L, nHeight - 1 ) ); - pVirDev->DrawLine( Point( 0, nHeight - 1 ), Point() ); - - for( long nY = 0, nY1 = 1, nY2 = 2; nY < nHeight2; nY++, nY1++, nY2++ ) - { - Scanline pScanlineRead = pReadAcc->GetScanline( nY ); - Scanline pScanlineRead1 = pReadAcc->GetScanline( nY1 ); - Scanline pScanlineRead2 = pReadAcc->GetScanline( nY2 ); - for( long nX = 0, nXDst = 1, nXTmp; nX < nWidth2; nX++, nXDst++ ) - { - nXTmp = nX; - - nSum2 = lGray = pReadAcc->GetIndexFromData( pScanlineRead, nXTmp++ ); - nSum1 = -nSum2; - nSum2 += static_cast<long>(pReadAcc->GetIndexFromData( pScanlineRead, nXTmp++ )) << 1; - lGray = pReadAcc->GetIndexFromData( pScanlineRead, nXTmp ); - nSum1 += lGray; - nSum2 += lGray; - - nSum1 += static_cast<long>(pReadAcc->GetIndexFromData( pScanlineRead1, nXTmp )) << 1; - nXTmp -= 2; - nSum1 -= static_cast<long>(pReadAcc->GetIndexFromData( pScanlineRead1, nXTmp )) << 1; - - lGray = -static_cast<long>(pReadAcc->GetIndexFromData( pScanlineRead2, nXTmp++ )); - nSum1 += lGray; - nSum2 += lGray; - nSum2 -= static_cast<long>(pReadAcc->GetIndexFromData( pScanlineRead2, nXTmp++ )) << 1; - lGray = static_cast<long>(pReadAcc->GetIndexFromData( pScanlineRead2, nXTmp )); - nSum1 += lGray; - nSum2 -= lGray; - - if( ( nSum1 * nSum1 + nSum2 * nSum2 ) < lThres2 ) - pVirDev->DrawPixel( Point(nXDst, nY), COL_WHITE ); - else - pVirDev->DrawPixel( Point(nXDst, nY), COL_BLACK ); - } - } - - bRet = true; - } - - pReadAcc.reset(); - - if( bRet ) - aRetBmp = pVirDev->GetBitmap(Point(0,0), aSize); - } - } - - if( !aRetBmp ) - aRetBmp = rBmp; - else - { - aRetBmp.SetPrefMapMode( rBmp.GetPrefMapMode() ); - aRetBmp.SetPrefSize( rBmp.GetPrefSize() ); - } - - return aRetBmp; -} - -tools::Polygon XOutBitmap::GetContour( const Bitmap& rBmp, const XOutFlags nFlags, - const tools::Rectangle* pWorkRectPixel ) -{ - const sal_uInt8 cEdgeDetectThreshold = 128; - Bitmap aWorkBmp; - tools::Polygon aRetPoly; - tools::Rectangle aWorkRect( Point(), rBmp.GetSizePixel() ); - - if( pWorkRectPixel ) - aWorkRect.Intersection( *pWorkRectPixel ); - - aWorkRect.Justify(); - - if( ( aWorkRect.GetWidth() > 4 ) && ( aWorkRect.GetHeight() > 4 ) ) - { - // if the flag is set, we need to detect edges - if( nFlags & XOutFlags::ContourEdgeDetect ) - aWorkBmp = DetectEdges( rBmp, cEdgeDetectThreshold ); - else - aWorkBmp = rBmp; - - BitmapReadAccess* pAcc = aWorkBmp.AcquireReadAccess(); - - const long nWidth = pAcc ? pAcc->Width() : 0; - const long nHeight = pAcc ? pAcc->Height() : 0; - - if (pAcc && nWidth && nHeight) - { - const Size& rPrefSize = aWorkBmp.GetPrefSize(); - const double fFactorX = static_cast<double>(rPrefSize.Width()) / nWidth; - const double fFactorY = static_cast<double>(rPrefSize.Height()) / nHeight; - const long nStartX1 = aWorkRect.Left() + 1; - const long nEndX1 = aWorkRect.Right(); - const long nStartX2 = nEndX1 - 1; - const long nStartY1 = aWorkRect.Top() + 1; - const long nEndY1 = aWorkRect.Bottom(); - const long nStartY2 = nEndY1 - 1; - std::unique_ptr<Point[]> pPoints1; - std::unique_ptr<Point[]> pPoints2; - long nX, nY; - sal_uInt16 nPolyPos = 0; - const BitmapColor aBlack = pAcc->GetBestMatchingColor( COL_BLACK ); - - if( nFlags & XOutFlags::ContourVert ) - { - pPoints1.reset(new Point[ nWidth ]); - pPoints2.reset(new Point[ nWidth ]); - - for( nX = nStartX1; nX < nEndX1; nX++ ) - { - nY = nStartY1; - - // scan row from left to right - while( nY < nEndY1 ) - { - Scanline pScanline = pAcc->GetScanline( nY ); - if( aBlack == pAcc->GetPixelFromData( pScanline, nX ) ) - { - pPoints1[ nPolyPos ] = Point( nX, nY ); - nY = nStartY2; - - // this loop always breaks eventually as there is at least one pixel - while( true ) - { - // coverity[copy_paste_error : FALSE] - this is correct nX, not nY - if( aBlack == pAcc->GetPixelFromData( pScanline, nX ) ) - { - pPoints2[ nPolyPos ] = Point( nX, nY ); - break; - } - - nY--; - } - - nPolyPos++; - break; - } - - nY++; - } - } - } - else - { - pPoints1.reset(new Point[ nHeight ]); - pPoints2.reset(new Point[ nHeight ]); - - for ( nY = nStartY1; nY < nEndY1; nY++ ) - { - nX = nStartX1; - Scanline pScanline = pAcc->GetScanline( nY ); - - // scan row from left to right - while( nX < nEndX1 ) - { - if( aBlack == pAcc->GetPixelFromData( pScanline, nX ) ) - { - pPoints1[ nPolyPos ] = Point( nX, nY ); - nX = nStartX2; - - // this loop always breaks eventually as there is at least one pixel - while( true ) - { - if( aBlack == pAcc->GetPixelFromData( pScanline, nX ) ) - { - pPoints2[ nPolyPos ] = Point( nX, nY ); - break; - } - - nX--; - } - - nPolyPos++; - break; - } - - nX++; - } - } - } - - const sal_uInt16 nNewSize1 = nPolyPos << 1; - - aRetPoly = tools::Polygon( nPolyPos, pPoints1.get() ); - aRetPoly.SetSize( nNewSize1 + 1 ); - aRetPoly[ nNewSize1 ] = aRetPoly[ 0 ]; - - for( sal_uInt16 j = nPolyPos; nPolyPos < nNewSize1; ) - aRetPoly[ nPolyPos++ ] = pPoints2[ --j ]; - - if( ( fFactorX != 0. ) && ( fFactorY != 0. ) ) - aRetPoly.Scale( fFactorX, fFactorY ); - } - - Bitmap::ReleaseAccess(pAcc); - } - - return aRetPoly; -} /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/gdi/bitmapex.cxx b/vcl/source/gdi/bitmapex.cxx index 3681e585ac84..3faaf3fd96e1 100644 --- a/vcl/source/gdi/bitmapex.cxx +++ b/vcl/source/gdi/bitmapex.cxx @@ -1315,6 +1315,238 @@ void BitmapEx::ReplaceTransparency(const Color& rColor) } } +static Bitmap DetectEdges( const Bitmap& rBmp ) +{ + constexpr sal_uInt8 cEdgeDetectThreshold = 128; + const Size aSize( rBmp.GetSizePixel() ); + Bitmap aRetBmp; + + if( ( aSize.Width() > 2 ) && ( aSize.Height() > 2 ) ) + { + Bitmap aWorkBmp( rBmp ); + + if( aWorkBmp.Convert( BmpConversion::N8BitGreys ) ) + { + bool bRet = false; + + ScopedVclPtr<VirtualDevice> pVirDev(VclPtr<VirtualDevice>::Create()); + pVirDev->SetOutputSizePixel(aSize); + Bitmap::ScopedReadAccess pReadAcc(aWorkBmp); + + if( pReadAcc ) + { + const long nWidth = aSize.Width(); + const long nWidth2 = nWidth - 2; + const long nHeight = aSize.Height(); + const long nHeight2 = nHeight - 2; + const long lThres2 = static_cast<long>(cEdgeDetectThreshold) * cEdgeDetectThreshold; + long nSum1; + long nSum2; + long lGray; + + // initialize border with white pixels + pVirDev->SetLineColor( COL_WHITE ); + pVirDev->DrawLine( Point(), Point( nWidth - 1, 0L ) ); + pVirDev->DrawLine( Point( nWidth - 1, 0L ), Point( nWidth - 1, nHeight - 1 ) ); + pVirDev->DrawLine( Point( nWidth - 1, nHeight - 1 ), Point( 0L, nHeight - 1 ) ); + pVirDev->DrawLine( Point( 0, nHeight - 1 ), Point() ); + + for( long nY = 0, nY1 = 1, nY2 = 2; nY < nHeight2; nY++, nY1++, nY2++ ) + { + Scanline pScanlineRead = pReadAcc->GetScanline( nY ); + Scanline pScanlineRead1 = pReadAcc->GetScanline( nY1 ); + Scanline pScanlineRead2 = pReadAcc->GetScanline( nY2 ); + for( long nX = 0, nXDst = 1, nXTmp; nX < nWidth2; nX++, nXDst++ ) + { + nXTmp = nX; + + nSum2 = lGray = pReadAcc->GetIndexFromData( pScanlineRead, nXTmp++ ); + nSum1 = -nSum2; + nSum2 += static_cast<long>(pReadAcc->GetIndexFromData( pScanlineRead, nXTmp++ )) << 1; + lGray = pReadAcc->GetIndexFromData( pScanlineRead, nXTmp ); + nSum1 += lGray; + nSum2 += lGray; + + nSum1 += static_cast<long>(pReadAcc->GetIndexFromData( pScanlineRead1, nXTmp )) << 1; + nXTmp -= 2; + nSum1 -= static_cast<long>(pReadAcc->GetIndexFromData( pScanlineRead1, nXTmp )) << 1; + + lGray = -static_cast<long>(pReadAcc->GetIndexFromData( pScanlineRead2, nXTmp++ )); + nSum1 += lGray; + nSum2 += lGray; + nSum2 -= static_cast<long>(pReadAcc->GetIndexFromData( pScanlineRead2, nXTmp++ )) << 1; + lGray = static_cast<long>(pReadAcc->GetIndexFromData( pScanlineRead2, nXTmp )); + nSum1 += lGray; + nSum2 -= lGray; + + if( ( nSum1 * nSum1 + nSum2 * nSum2 ) < lThres2 ) + pVirDev->DrawPixel( Point(nXDst, nY), COL_WHITE ); + else + pVirDev->DrawPixel( Point(nXDst, nY), COL_BLACK ); + } + } + + bRet = true; + } + + pReadAcc.reset(); + + if( bRet ) + aRetBmp = pVirDev->GetBitmap(Point(0,0), aSize); + } + } + + if( !aRetBmp ) + aRetBmp = rBmp; + else + { + aRetBmp.SetPrefMapMode( rBmp.GetPrefMapMode() ); + aRetBmp.SetPrefSize( rBmp.GetPrefSize() ); + } + + return aRetBmp; +} + +/** Get contours in image */ +tools::Polygon BitmapEx::GetContour( bool bContourEdgeDetect, bool bContourVert, + const tools::Rectangle* pWorkRectPixel ) +{ + Bitmap aWorkBmp; + tools::Polygon aRetPoly; + tools::Rectangle aWorkRect( Point(), maBitmap.GetSizePixel() ); + + if( pWorkRectPixel ) + aWorkRect.Intersection( *pWorkRectPixel ); + + aWorkRect.Justify(); + + if( ( aWorkRect.GetWidth() > 4 ) && ( aWorkRect.GetHeight() > 4 ) ) + { + // if the flag is set, we need to detect edges + if( bContourEdgeDetect ) + aWorkBmp = DetectEdges( maBitmap ); + else + aWorkBmp = maBitmap; + + BitmapReadAccess* pAcc = aWorkBmp.AcquireReadAccess(); + + const long nWidth = pAcc ? pAcc->Width() : 0; + const long nHeight = pAcc ? pAcc->Height() : 0; + + if (pAcc && nWidth && nHeight) + { + const Size& rPrefSize = aWorkBmp.GetPrefSize(); + const double fFactorX = static_cast<double>(rPrefSize.Width()) / nWidth; + const double fFactorY = static_cast<double>(rPrefSize.Height()) / nHeight; + const long nStartX1 = aWorkRect.Left() + 1; + const long nEndX1 = aWorkRect.Right(); + const long nStartX2 = nEndX1 - 1; + const long nStartY1 = aWorkRect.Top() + 1; + const long nEndY1 = aWorkRect.Bottom(); + const long nStartY2 = nEndY1 - 1; + std::unique_ptr<Point[]> pPoints1; + std::unique_ptr<Point[]> pPoints2; + long nX, nY; + sal_uInt16 nPolyPos = 0; + const BitmapColor aBlack = pAcc->GetBestMatchingColor( COL_BLACK ); + + if( bContourVert ) + { + pPoints1.reset(new Point[ nWidth ]); + pPoints2.reset(new Point[ nWidth ]); + + for( nX = nStartX1; nX < nEndX1; nX++ ) + { + nY = nStartY1; + + // scan row from left to right + while( nY < nEndY1 ) + { + Scanline pScanline = pAcc->GetScanline( nY ); + if( aBlack == pAcc->GetPixelFromData( pScanline, nX ) ) + { + pPoints1[ nPolyPos ] = Point( nX, nY ); + nY = nStartY2; + + // this loop always breaks eventually as there is at least one pixel + while( true ) + { + // coverity[copy_paste_error : FALSE] - this is correct nX, not nY + if( aBlack == pAcc->GetPixelFromData( pScanline, nX ) ) + { + pPoints2[ nPolyPos ] = Point( nX, nY ); + break; + } + + nY--; + } + + nPolyPos++; + break; + } + + nY++; + } + } + } + else + { + pPoints1.reset(new Point[ nHeight ]); + pPoints2.reset(new Point[ nHeight ]); + + for ( nY = nStartY1; nY < nEndY1; nY++ ) + { + nX = nStartX1; + Scanline pScanline = pAcc->GetScanline( nY ); + + // scan row from left to right + while( nX < nEndX1 ) + { + if( aBlack == pAcc->GetPixelFromData( pScanline, nX ) ) + { + pPoints1[ nPolyPos ] = Point( nX, nY ); + nX = nStartX2; + + // this loop always breaks eventually as there is at least one pixel + while( true ) + { + if( aBlack == pAcc->GetPixelFromData( pScanline, nX ) ) + { + pPoints2[ nPolyPos ] = Point( nX, nY ); + break; + } + + nX--; + } + + nPolyPos++; + break; + } + + nX++; + } + } + } + + const sal_uInt16 nNewSize1 = nPolyPos << 1; + + aRetPoly = tools::Polygon( nPolyPos, pPoints1.get() ); + aRetPoly.SetSize( nNewSize1 + 1 ); + aRetPoly[ nNewSize1 ] = aRetPoly[ 0 ]; + + for( sal_uInt16 j = nPolyPos; nPolyPos < nNewSize1; ) + aRetPoly[ nPolyPos++ ] = pPoints2[ --j ]; + + if( ( fFactorX != 0. ) && ( fFactorY != 0. ) ) + aRetPoly.Scale( fFactorX, fFactorY ); + } + + Bitmap::ReleaseAccess(pAcc); + } + + return aRetPoly; +} + void BitmapEx::setAlphaFrom( sal_uInt8 cIndexFrom, sal_Int8 nAlphaTo ) { AlphaMask aAlphaMask(GetAlpha()); |