summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2019-07-04 14:26:41 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2019-07-05 08:46:36 +0200
commit7f4fe205c4b1baf01115a9e0d74655818d03ec40 (patch)
treef5aead6ec8b31203aeaf8b1c68e2ff736dcd97ea
parent849b837d1a3b185a8dd893a8f6eaed53605bcab1 (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.hxx10
-rw-r--r--include/vcl/bitmapex.hxx4
-rw-r--r--svx/source/dialog/_contdlg.cxx9
-rw-r--r--svx/source/xoutdev/_xoutbmp.cxx230
-rw-r--r--vcl/source/gdi/bitmapex.cxx232
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());