LibreOffice Module vcl (master)  1
impvect.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/log.hxx>
21 #include <vcl/bitmapaccess.hxx>
22 #include <tools/link.hxx>
23 #include <tools/poly.hxx>
24 #include <tools/helpers.hxx>
25 #include <vcl/gdimtf.hxx>
26 #include <vcl/metaact.hxx>
27 #include <vcl/virdev.hxx>
28 #include "impvect.hxx"
29 #include <array>
30 #include <memory>
31 
32 #define VECT_POLY_MAX 8192
33 
34 #define VECT_FREE_INDEX 0
35 #define VECT_CONT_INDEX 1
36 #define VECT_DONE_INDEX 2
37 
38 #define VECT_POLY_INLINE_INNER 1UL
39 #define VECT_POLY_INLINE_OUTER 2UL
40 #define VECT_POLY_OUTLINE_INNER 4UL
41 #define VECT_POLY_OUTLINE_OUTER 8UL
42 
43 static void VECT_MAP( const std::unique_ptr<long []> & pMapIn, const std::unique_ptr<long []>& pMapOut, long nVal )
44 {
45  pMapIn[nVal] = (nVal * 4) + 1;
46  pMapOut[nVal] = pMapIn[nVal] + 5;
47 }
48 static constexpr long BACK_MAP( long _def_nVal )
49 {
50  return ((_def_nVal + 2) >> 2) - 1;
51 }
52 static void VECT_PROGRESS( const Link<long, void>* pProgress, long _def_nVal )
53 {
54  if(pProgress)
55  pProgress->Call(_def_nVal);
56 }
57 
58 class ImplVectMap;
59 class ImplChain;
60 
61 namespace ImplVectorizer
62 {
63  static ImplVectMap* ImplExpand( BitmapReadAccess* pRAcc, const Color& rColor );
64  static void ImplCalculate( ImplVectMap* pMap, tools::PolyPolygon& rPolyPoly, sal_uInt8 cReduce );
65  static bool ImplGetChain( ImplVectMap* pMap, const Point& rStartPt, ImplChain& rChain );
66  static bool ImplIsUp( ImplVectMap const * pMap, long nY, long nX );
67  static void ImplLimitPolyPoly( tools::PolyPolygon& rPolyPoly );
68 }
69 
70 struct ChainMove { long nDX; long nDY; };
71 
72 static const ChainMove aImplMove[ 8 ] = {
73  { 1, 0 },
74  { 0, -1 },
75  { -1, 0 },
76  { 0, 1 },
77  { 1, -1 },
78  { -1, -1 },
79  { -1, 1 },
80  { 1, 1 }
81  };
82 
83 static const ChainMove aImplMoveInner[ 8 ] = {
84  { 0, 1 },
85  { 1, 0 },
86  { 0, -1 },
87  { -1, 0 },
88  { 0, 1 },
89  { 1, 0 },
90  { 0, -1 },
91  { -1, 0 }
92  };
93 
94 static const ChainMove aImplMoveOuter[ 8 ] = {
95  { 0, -1 },
96  { -1, 0 },
97  { 0, 1 },
98  { 1, 0 },
99  { -1, 0 },
100  { 0, 1 },
101  { 1, 0 },
102  { 0, -1 }
103  };
104 
106 {
108  sal_uInt16 mnIndex = 0;
109  bool mbSet = false;
110 };
111 
112 static int ImplColorSetCmpFnc( const ImplColorSet& lhs, const ImplColorSet& rhs)
113 {
114  int nRet;
115 
116  if( lhs.mbSet && rhs.mbSet )
117  {
118  const sal_uInt8 cLum1 = lhs.maColor.GetLuminance();
119  const sal_uInt8 cLum2 = rhs.maColor.GetLuminance();
120  nRet = ( cLum1 > cLum2 ) ? -1 : ( ( cLum1 == cLum2 ) ? 0 : 1 );
121  }
122  else if( lhs.mbSet )
123  nRet = -1;
124  else if( rhs.mbSet )
125  nRet = 1;
126  else
127  nRet = 0;
128 
129  return nRet;
130 }
131 
133 {
134  std::unique_ptr<Point[]> mpArray;
137 
138 public:
139 
140  ImplPointArray();
141 
142  void ImplSetSize( sal_uLong nSize );
144  void ImplSetRealSize( sal_uLong nRealSize ) { mnRealSize = nRealSize; }
145  void ImplCreatePoly( tools::Polygon& rPoly ) const;
146 
147  inline Point& operator[]( sal_uLong nPos );
148  inline const Point& operator[]( sal_uLong nPos ) const;
149 
150 };
151 
153  mnSize ( 0 ),
154  mnRealSize ( 0 )
155 
156 {
157 }
158 
160 {
161  const sal_uLong nTotal = nSize * sizeof( Point );
162 
163  mnSize = nSize;
164  mnRealSize = 0;
165 
166  mpArray = std::make_unique<Point[]>( nTotal );
167 }
168 
170 {
171  SAL_WARN_IF( nPos >= mnSize, "vcl", "ImplPointArray::operator[]: nPos out of range!" );
172  return mpArray[ nPos ];
173 }
174 
175 inline const Point& ImplPointArray::operator[]( sal_uLong nPos ) const
176 {
177  SAL_WARN_IF( nPos >= mnSize, "vcl", "ImplPointArray::operator[]: nPos out of range!" );
178  return mpArray[ nPos ];
179 }
180 
182 {
183  rPoly = tools::Polygon( sal::static_int_cast<sal_uInt16>(mnRealSize), mpArray.get() );
184 }
185 
187 {
188 private:
189 
192  long const mnWidth;
193  long const mnHeight;
194 
195 public:
196 
197  ImplVectMap( long nWidth, long nHeight );
198  ~ImplVectMap();
199 
200  long Width() const { return mnWidth; }
201  long Height() const { return mnHeight; }
202 
203  inline void Set( long nY, long nX, sal_uInt8 cVal );
204  inline sal_uInt8 Get( long nY, long nX ) const;
205 
206  inline bool IsFree( long nY, long nX ) const;
207  inline bool IsCont( long nY, long nX ) const;
208  inline bool IsDone( long nY, long nX ) const;
209 
210 };
211 
212 ImplVectMap::ImplVectMap( long nWidth, long nHeight ) :
213  mpBuf ( static_cast<Scanline>(rtl_allocateZeroMemory(nWidth * nHeight)) ),
214  mpScan ( static_cast<Scanline*>(std::malloc(nHeight * sizeof(Scanline))) ),
215  mnWidth ( nWidth ),
216  mnHeight( nHeight )
217 {
218  const long nWidthAl = ( nWidth >> 2 ) + 1;
219  Scanline pTmp = mpBuf;
220 
221  for( long nY = 0; nY < nHeight; pTmp += nWidthAl )
222  mpScan[ nY++ ] = pTmp;
223 }
224 
226 {
227  std::free( mpBuf );
228  std::free( mpScan );
229 }
230 
231 inline void ImplVectMap::Set( long nY, long nX, sal_uInt8 cVal )
232 {
233  const sal_uInt8 cShift = sal::static_int_cast<sal_uInt8>(6 - ( ( nX & 3 ) << 1 ));
234  auto & rPixel = mpScan[ nY ][ nX >> 2 ];
235  rPixel = (rPixel & ~( 3 << cShift ) ) | ( cVal << cShift );
236 }
237 
238 inline sal_uInt8 ImplVectMap::Get( long nY, long nX ) const
239 {
240  return sal::static_int_cast<sal_uInt8>( ( ( mpScan[ nY ][ nX >> 2 ] ) >> ( 6 - ( ( nX & 3 ) << 1 ) ) ) & 3 );
241 }
242 
243 inline bool ImplVectMap::IsFree( long nY, long nX ) const
244 {
245  return( VECT_FREE_INDEX == Get( nY, nX ) );
246 }
247 
248 inline bool ImplVectMap::IsCont( long nY, long nX ) const
249 {
250  return( VECT_CONT_INDEX == Get( nY, nX ) );
251 }
252 
253 inline bool ImplVectMap::IsDone( long nY, long nX ) const
254 {
255  return( VECT_DONE_INDEX == Get( nY, nX ) );
256 }
257 
259 {
260 private:
261 
266  std::unique_ptr<sal_uInt8[]>
268 
269  void ImplGetSpace();
270 
271  void ImplPostProcess( const ImplPointArray& rArr );
272 
273  ImplChain(const ImplChain&) = delete;
274  ImplChain& operator=(const ImplChain&) = delete;
275 
276 public:
277 
278  ImplChain();
279 
280  void ImplBeginAdd( const Point& rStartPt );
281  inline void ImplAdd( sal_uInt8 nCode );
282  void ImplEndAdd( sal_uLong nTypeFlag );
283 
284  const tools::Polygon& ImplGetPoly() const { return maPoly; }
285 };
286 
288  mnArraySize ( 1024 ),
289  mnCount ( 0 ),
290  mpCodes ( new sal_uInt8[mnArraySize] )
291 {
292 }
293 
295 {
296  const sal_uLong nOldArraySize = mnArraySize;
297  sal_uInt8* pNewCodes;
298 
299  mnArraySize = mnArraySize << 1;
300  pNewCodes = new sal_uInt8[ mnArraySize ];
301  memcpy( pNewCodes, mpCodes.get(), nOldArraySize );
302  mpCodes.reset( pNewCodes );
303 }
304 
305 void ImplChain::ImplBeginAdd( const Point& rStartPt )
306 {
308  maStartPt = rStartPt;
309  mnCount = 0;
310 }
311 
312 inline void ImplChain::ImplAdd( sal_uInt8 nCode )
313 {
314  if( mnCount == mnArraySize )
315  ImplGetSpace();
316 
317  mpCodes[ mnCount++ ] = nCode;
318 }
319 
321 {
322  if( mnCount )
323  {
325 
326  if( nFlag & VECT_POLY_INLINE_INNER )
327  {
328  long nFirstX, nFirstY;
329  long nLastX, nLastY;
330 
331  nFirstX = nLastX = maStartPt.X();
332  nFirstY = nLastY = maStartPt.Y();
333  aArr.ImplSetSize( mnCount << 1 );
334 
335  sal_uInt16 nPolyPos;
336  sal_uLong i;
337  for( i = 0, nPolyPos = 0; i < ( mnCount - 1 ); i++ )
338  {
339  const sal_uInt8 cMove = mpCodes[ i ];
340  const sal_uInt8 cNextMove = mpCodes[ i + 1 ];
341  const ChainMove& rMove = aImplMove[ cMove ];
342  const ChainMove& rMoveInner = aImplMoveInner[ cMove ];
343 // Point& rPt = aArr[ nPolyPos ];
344  bool bDone = true;
345 
346  nLastX += rMove.nDX;
347  nLastY += rMove.nDY;
348 
349  if( cMove < 4 )
350  {
351  if( ( cMove == 0 && cNextMove == 3 ) ||
352  ( cMove == 3 && cNextMove == 2 ) ||
353  ( cMove == 2 && cNextMove == 1 ) ||
354  ( cMove == 1 && cNextMove == 0 ) )
355  {
356  }
357  else if( cMove == 2 && cNextMove == 3 )
358  {
359  aArr[ nPolyPos ].setX( nLastX );
360  aArr[ nPolyPos++ ].setY( nLastY - 1 );
361 
362  aArr[ nPolyPos ].setX( nLastX - 1 );
363  aArr[ nPolyPos++ ].setY( nLastY - 1 );
364 
365  aArr[ nPolyPos ].setX( nLastX - 1 );
366  aArr[ nPolyPos++ ].setY( nLastY );
367  }
368  else if( cMove == 3 && cNextMove == 0 )
369  {
370  aArr[ nPolyPos ].setX( nLastX - 1 );
371  aArr[ nPolyPos++ ].setY( nLastY );
372 
373  aArr[ nPolyPos ].setX( nLastX - 1 );
374  aArr[ nPolyPos++ ].setY( nLastY + 1 );
375 
376  aArr[ nPolyPos ].setX( nLastX );
377  aArr[ nPolyPos++ ].setY( nLastY + 1 );
378  }
379  else if( cMove == 0 && cNextMove == 1 )
380  {
381  aArr[ nPolyPos ].setX( nLastX );
382  aArr[ nPolyPos++ ].setY( nLastY + 1 );
383 
384  aArr[ nPolyPos ].setX( nLastX + 1 );
385  aArr[ nPolyPos++ ].setY( nLastY + 1 );
386 
387  aArr[ nPolyPos ].setX( nLastX + 1 );
388  aArr[ nPolyPos++ ].setY( nLastY );
389  }
390  else if( cMove == 1 && cNextMove == 2 )
391  {
392  aArr[ nPolyPos ].setX( nLastX + 1 );
393  aArr[ nPolyPos++ ].setY( nLastY + 1 );
394 
395  aArr[ nPolyPos ].setX( nLastX + 1 );
396  aArr[ nPolyPos++ ].setY( nLastY - 1 );
397 
398  aArr[ nPolyPos ].setX( nLastX );
399  aArr[ nPolyPos++ ].setY( nLastY - 1 );
400  }
401  else
402  bDone = false;
403  }
404  else if( cMove == 7 && cNextMove == 0 )
405  {
406  aArr[ nPolyPos ].setX( nLastX - 1 );
407  aArr[ nPolyPos++ ].setY( nLastY );
408 
409  aArr[ nPolyPos ].setX( nLastX );
410  aArr[ nPolyPos++ ].setY( nLastY + 1 );
411  }
412  else if( cMove == 4 && cNextMove == 1 )
413  {
414  aArr[ nPolyPos ].setX( nLastX );
415  aArr[ nPolyPos++ ].setY( nLastY + 1 );
416 
417  aArr[ nPolyPos ].setX( nLastX + 1 );
418  aArr[ nPolyPos++ ].setY( nLastY );
419  }
420  else
421  bDone = false;
422 
423  if( !bDone )
424  {
425  aArr[ nPolyPos ].setX( nLastX + rMoveInner.nDX );
426  aArr[ nPolyPos++ ].setY( nLastY + rMoveInner.nDY );
427  }
428  }
429 
430  aArr[ nPolyPos ].setX( nFirstX + 1 );
431  aArr[ nPolyPos++ ].setY( nFirstY + 1 );
432  aArr.ImplSetRealSize( nPolyPos );
433  }
434  else if( nFlag & VECT_POLY_INLINE_OUTER )
435  {
436  long nFirstX, nFirstY;
437  long nLastX, nLastY;
438 
439  nFirstX = nLastX = maStartPt.X();
440  nFirstY = nLastY = maStartPt.Y();
441  aArr.ImplSetSize( mnCount << 1 );
442 
443  sal_uInt16 nPolyPos;
444  sal_uLong i;
445  for( i = 0, nPolyPos = 0; i < ( mnCount - 1 ); i++ )
446  {
447  const sal_uInt8 cMove = mpCodes[ i ];
448  const sal_uInt8 cNextMove = mpCodes[ i + 1 ];
449  const ChainMove& rMove = aImplMove[ cMove ];
450  const ChainMove& rMoveOuter = aImplMoveOuter[ cMove ];
451 // Point& rPt = aArr[ nPolyPos ];
452  bool bDone = true;
453 
454  nLastX += rMove.nDX;
455  nLastY += rMove.nDY;
456 
457  if( cMove < 4 )
458  {
459  if( ( cMove == 0 && cNextMove == 1 ) ||
460  ( cMove == 1 && cNextMove == 2 ) ||
461  ( cMove == 2 && cNextMove == 3 ) ||
462  ( cMove == 3 && cNextMove == 0 ) )
463  {
464  }
465  else if( cMove == 0 && cNextMove == 3 )
466  {
467  aArr[ nPolyPos ].setX( nLastX );
468  aArr[ nPolyPos++ ].setY( nLastY - 1 );
469 
470  aArr[ nPolyPos ].setX( nLastX + 1 );
471  aArr[ nPolyPos++ ].setY( nLastY - 1 );
472 
473  aArr[ nPolyPos ].setX( nLastX + 1 );
474  aArr[ nPolyPos++ ].setY( nLastY );
475  }
476  else if( cMove == 3 && cNextMove == 2 )
477  {
478  aArr[ nPolyPos ].setX( nLastX + 1 );
479  aArr[ nPolyPos++ ].setY( nLastY );
480 
481  aArr[ nPolyPos ].setX( nLastX + 1 );
482  aArr[ nPolyPos++ ].setY( nLastY + 1 );
483 
484  aArr[ nPolyPos ].setX( nLastX );
485  aArr[ nPolyPos++ ].setY( nLastY + 1 );
486  }
487  else if( cMove == 2 && cNextMove == 1 )
488  {
489  aArr[ nPolyPos ].setX( nLastX );
490  aArr[ nPolyPos++ ].setY( nLastY + 1 );
491 
492  aArr[ nPolyPos ].setX( nLastX - 1 );
493  aArr[ nPolyPos++ ].setY( nLastY + 1 );
494 
495  aArr[ nPolyPos ].setX( nLastX - 1 );
496  aArr[ nPolyPos++ ].setY( nLastY );
497  }
498  else if( cMove == 1 && cNextMove == 0 )
499  {
500  aArr[ nPolyPos ].setX( nLastX - 1 );
501  aArr[ nPolyPos++ ].setY( nLastY );
502 
503  aArr[ nPolyPos ].setX( nLastX - 1 );
504  aArr[ nPolyPos++ ].setY( nLastY - 1 );
505 
506  aArr[ nPolyPos ].setX( nLastX );
507  aArr[ nPolyPos++ ].setY( nLastY - 1 );
508  }
509  else
510  bDone = false;
511  }
512  else if( cMove == 7 && cNextMove == 3 )
513  {
514  aArr[ nPolyPos ].setX( nLastX );
515  aArr[ nPolyPos++ ].setY( nLastY - 1 );
516 
517  aArr[ nPolyPos ].setX( nLastX + 1 );
518  aArr[ nPolyPos++ ].setY( nLastY );
519  }
520  else if( cMove == 6 && cNextMove == 2 )
521  {
522  aArr[ nPolyPos ].setX( nLastX + 1 );
523  aArr[ nPolyPos++ ].setY( nLastY );
524 
525  aArr[ nPolyPos ].setX( nLastX );
526  aArr[ nPolyPos++ ].setY( nLastY + 1 );
527  }
528  else
529  bDone = false;
530 
531  if( !bDone )
532  {
533  aArr[ nPolyPos ].setX( nLastX + rMoveOuter.nDX );
534  aArr[ nPolyPos++ ].setY( nLastY + rMoveOuter.nDY );
535  }
536  }
537 
538  aArr[ nPolyPos ].setX( nFirstX - 1 );
539  aArr[ nPolyPos++ ].setY( nFirstY - 1 );
540  aArr.ImplSetRealSize( nPolyPos );
541  }
542  else
543  {
544  long nLastX = maStartPt.X(), nLastY = maStartPt.Y();
545 
546  aArr.ImplSetSize( mnCount + 1 );
547  aArr[ 0 ] = Point( nLastX, nLastY );
548 
549  for( sal_uLong i = 0; i < mnCount; )
550  {
551  const ChainMove& rMove = aImplMove[ mpCodes[ i ] ];
552  aArr[ ++i ] = Point( nLastX += rMove.nDX, nLastY += rMove.nDY );
553  }
554 
555  aArr.ImplSetRealSize( mnCount + 1 );
556  }
557 
558  ImplPostProcess( aArr );
559  }
560  else
561  maPoly.SetSize( 0 );
562 }
563 
565 {
566  ImplPointArray aNewArr1;
567  ImplPointArray aNewArr2;
568  Point* pLast;
569  Point* pLeast;
570  sal_uLong nNewPos;
571  sal_uLong nCount = rArr.ImplGetRealSize();
572  sal_uLong n;
573 
574  // pass 1
575  aNewArr1.ImplSetSize( nCount );
576  pLast = &( aNewArr1[ 0 ] );
577  pLast->setX( BACK_MAP( rArr[ 0 ].X() ) );
578  pLast->setY( BACK_MAP( rArr[ 0 ].Y() ) );
579 
580  for( n = nNewPos = 1; n < nCount; )
581  {
582  const Point& rPt = rArr[ n++ ];
583  const long nX = BACK_MAP( rPt.X() );
584  const long nY = BACK_MAP( rPt.Y() );
585 
586  if( nX != pLast->X() || nY != pLast->Y() )
587  {
588  pLast = pLeast = &( aNewArr1[ nNewPos++ ] );
589  pLeast->setX( nX );
590  pLeast->setY( nY );
591  }
592  }
593 
594  nCount = nNewPos;
595  aNewArr1.ImplSetRealSize( nCount );
596 
597  // pass 2
598  aNewArr2.ImplSetSize( nCount );
599  pLast = &( aNewArr2[ 0 ] );
600  *pLast = aNewArr1[ 0 ];
601 
602  for( n = nNewPos = 1; n < nCount; )
603  {
604  pLeast = &( aNewArr1[ n++ ] );
605 
606  if( pLeast->X() == pLast->X() )
607  {
608  while( n < nCount && aNewArr1[ n ].X() == pLast->X() )
609  pLeast = &( aNewArr1[ n++ ] );
610  }
611  else if( pLeast->Y() == pLast->Y() )
612  {
613  while( n < nCount && aNewArr1[ n ].Y() == pLast->Y() )
614  pLeast = &( aNewArr1[ n++ ] );
615  }
616 
617  pLast = pLeast;
618  aNewArr2[ nNewPos++ ] = *pLast;
619  }
620 
621  aNewArr2.ImplSetRealSize( nNewPos );
622  aNewArr2.ImplCreatePoly( maPoly );
623 }
624 
625 namespace ImplVectorizer {
626 
627 bool ImplVectorize( const Bitmap& rColorBmp, GDIMetaFile& rMtf,
628  sal_uInt8 cReduce, const Link<long,void>* pProgress )
629 {
630  bool bRet = false;
631 
632  VECT_PROGRESS( pProgress, 0 );
633 
634  std::unique_ptr<Bitmap> xBmp(new Bitmap( rColorBmp ));
635  Bitmap::ScopedReadAccess pRAcc(*xBmp);
636 
637  if( pRAcc )
638  {
639  tools::PolyPolygon aPolyPoly;
640  double fPercent = 0.0;
641  double fPercentStep_2 = 0.0;
642  const long nWidth = pRAcc->Width();
643  const long nHeight = pRAcc->Height();
644  const sal_uInt16 nColorCount = pRAcc->GetPaletteEntryCount();
645  sal_uInt16 n;
646  std::array<ImplColorSet, 256> aColorSet;
647 
648  rMtf.Clear();
649 
650  // get used palette colors and sort them from light to dark colors
651  for( n = 0; n < nColorCount; n++ )
652  {
653  aColorSet[ n ].mnIndex = n;
654  aColorSet[ n ].maColor = pRAcc->GetPaletteColor( n );
655  }
656 
657  for( long nY = 0; nY < nHeight; nY++ )
658  {
659  Scanline pScanlineRead = pRAcc->GetScanline( nY );
660  for( long nX = 0; nX < nWidth; nX++ )
661  aColorSet[ pRAcc->GetIndexFromData( pScanlineRead, nX ) ].mbSet = true;
662  }
663 
664  std::sort( aColorSet.begin(), aColorSet.end(), ImplColorSetCmpFnc );
665 
666  for( n = 0; n < 256; n++ )
667  if( !aColorSet[ n ].mbSet )
668  break;
669 
670  if( n )
671  fPercentStep_2 = 45.0 / n;
672 
673  fPercent += 10.0;
674  VECT_PROGRESS( pProgress, FRound( fPercent ) );
675 
676  for( sal_uInt16 i = 0; i < n; i++ )
677  {
678  const BitmapColor aBmpCol( pRAcc->GetPaletteColor( aColorSet[ i ].mnIndex ) );
679  const Color aFindColor( aBmpCol.GetRed(), aBmpCol.GetGreen(), aBmpCol.GetBlue() );
680  std::unique_ptr<ImplVectMap> xMap(ImplExpand( pRAcc.get(), aFindColor ));
681 
682  fPercent += fPercentStep_2;
683  VECT_PROGRESS( pProgress, FRound( fPercent ) );
684 
685  if( xMap )
686  {
687  aPolyPoly.Clear();
688  ImplCalculate( xMap.get(), aPolyPoly, cReduce );
689  xMap.reset();
690 
691  if( aPolyPoly.Count() )
692  {
693  ImplLimitPolyPoly( aPolyPoly );
694 
695  aPolyPoly.Optimize( PolyOptimizeFlags::EDGES );
696 
697  if( aPolyPoly.Count() )
698  {
699  rMtf.AddAction( new MetaLineColorAction( aFindColor, true ) );
700  rMtf.AddAction( new MetaFillColorAction( aFindColor, true ) );
701  rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) );
702  }
703  }
704  }
705 
706  fPercent += fPercentStep_2;
707  VECT_PROGRESS( pProgress, FRound( fPercent ) );
708  }
709 
710  if( rMtf.GetActionSize() )
711  {
712  MapMode aMap( MapUnit::Map100thMM );
714  const Size aLogSize1( aVDev->PixelToLogic( Size( 1, 1 ), aMap ) );
715 
716  rMtf.SetPrefMapMode( aMap );
717  rMtf.SetPrefSize( Size( nWidth + 2, nHeight + 2 ) );
718  rMtf.Move( 1, 1 );
719  rMtf.Scale( aLogSize1.Width(), aLogSize1.Height() );
720  bRet = true;
721  }
722  }
723 
724  pRAcc.reset();
725  xBmp.reset();
726  VECT_PROGRESS( pProgress, 100 );
727 
728  return bRet;
729 }
730 
732 {
733  if( rPolyPoly.Count() > VECT_POLY_MAX )
734  {
735  tools::PolyPolygon aNewPolyPoly;
736  long nReduce = 0;
737  sal_uInt16 nNewCount;
738 
739  do
740  {
741  aNewPolyPoly.Clear();
742  nReduce++;
743 
744  for( sal_uInt16 i = 0, nCount = rPolyPoly.Count(); i < nCount; i++ )
745  {
746  const tools::Rectangle aBound( rPolyPoly[ i ].GetBoundRect() );
747 
748  if( aBound.GetWidth() > nReduce && aBound.GetHeight() > nReduce )
749  {
750  if( rPolyPoly[ i ].GetSize() )
751  aNewPolyPoly.Insert( rPolyPoly[ i ] );
752  }
753  }
754 
755  nNewCount = aNewPolyPoly.Count();
756  }
757  while( nNewCount > VECT_POLY_MAX );
758 
759  rPolyPoly = aNewPolyPoly;
760  }
761 }
762 
763 ImplVectMap* ImplExpand( BitmapReadAccess* pRAcc, const Color& rColor )
764 {
765  ImplVectMap* pMap = nullptr;
766 
767  if( pRAcc && pRAcc->Width() && pRAcc->Height() )
768  {
769  const long nOldWidth = pRAcc->Width();
770  const long nOldHeight = pRAcc->Height();
771  const long nNewWidth = ( nOldWidth << 2 ) + 4;
772  const long nNewHeight = ( nOldHeight << 2 ) + 4;
773  const BitmapColor aTest( pRAcc->GetBestMatchingColor( rColor ) );
774  std::unique_ptr<long[]> pMapIn(new long[ std::max( nOldWidth, nOldHeight ) ]);
775  std::unique_ptr<long[]> pMapOut(new long[ std::max( nOldWidth, nOldHeight ) ]);
776  long nX, nY, nTmpX, nTmpY;
777 
778  pMap = new ImplVectMap( nNewWidth, nNewHeight );
779 
780  for( nX = 0; nX < nOldWidth; nX++ )
781  VECT_MAP( pMapIn, pMapOut, nX );
782 
783  for( nY = 0, nTmpY = 5; nY < nOldHeight; nY++, nTmpY += 4 )
784  {
785  Scanline pScanlineRead = pRAcc->GetScanline( nY );
786  for( nX = 0; nX < nOldWidth; )
787  {
788  if( pRAcc->GetPixelFromData( pScanlineRead, nX ) == aTest )
789  {
790  nTmpX = pMapIn[ nX++ ];
791  nTmpY -= 3;
792 
793  pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
794  pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
795  pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
796  pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
797 
798  while( nX < nOldWidth && pRAcc->GetPixelFromData( pScanlineRead, nX ) == aTest )
799  nX++;
800 
801  nTmpX = pMapOut[ nX - 1 ];
802  nTmpY -= 3;
803 
804  pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
805  pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
806  pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
807  pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
808  }
809  else
810  nX++;
811  }
812  }
813 
814  for( nY = 0; nY < nOldHeight; nY++ )
815  VECT_MAP( pMapIn, pMapOut, nY );
816 
817  for( nX = 0, nTmpX = 5; nX < nOldWidth; nX++, nTmpX += 4 )
818  {
819  for( nY = 0; nY < nOldHeight; )
820  {
821  if( pRAcc->GetPixel( nY, nX ) == aTest )
822  {
823  nTmpX -= 3;
824  nTmpY = pMapIn[ nY++ ];
825 
826  pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
827  pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
828  pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
829  pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
830 
831  while( nY < nOldHeight && pRAcc->GetPixel( nY, nX ) == aTest )
832  nY++;
833 
834  nTmpX -= 3;
835  nTmpY = pMapOut[ nY - 1 ];
836 
837  pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
838  pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
839  pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
840  pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
841  }
842  else
843  nY++;
844  }
845  }
846  }
847 
848  return pMap;
849 }
850 
851 void ImplCalculate( ImplVectMap* pMap, tools::PolyPolygon& rPolyPoly, sal_uInt8 cReduce )
852 {
853  const long nWidth = pMap->Width(), nHeight= pMap->Height();
854 
855  for( long nY = 0; nY < nHeight; nY++ )
856  {
857  long nX = 0;
858  bool bInner = true;
859 
860  while( nX < nWidth )
861  {
862  // skip free
863  while( ( nX < nWidth ) && pMap->IsFree( nY, nX ) )
864  nX++;
865 
866  if( nX == nWidth )
867  break;
868 
869  if( pMap->IsCont( nY, nX ) )
870  {
871  // new contour
872  ImplChain aChain;
873  const Point aStartPt( nX++, nY );
874 
875  // get chain code
876  aChain.ImplBeginAdd( aStartPt );
877  ImplGetChain( pMap, aStartPt, aChain );
878 
880 
881  const tools::Polygon& rPoly = aChain.ImplGetPoly();
882 
883  if( rPoly.GetSize() > 2 )
884  {
885  if( cReduce )
886  {
887  const tools::Rectangle aBound( rPoly.GetBoundRect() );
888 
889  if( aBound.GetWidth() > cReduce && aBound.GetHeight() > cReduce )
890  rPolyPoly.Insert( rPoly );
891  }
892  else
893  rPolyPoly.Insert( rPoly );
894  }
895 
896  // skip rest of detected contour
897  while( pMap->IsCont( nY, nX ) )
898  nX++;
899  }
900  else
901  {
902  // process done segment
903  const long nStartSegX = nX++;
904 
905  while( pMap->IsDone( nY, nX ) )
906  nX++;
907 
908  if( ( ( nX - nStartSegX ) == 1 ) || ( ImplIsUp( pMap, nY, nStartSegX ) != ImplIsUp( pMap, nY, nX - 1 ) ) )
909  bInner = !bInner;
910  }
911  }
912  }
913 }
914 
915 bool ImplGetChain( ImplVectMap* pMap, const Point& rStartPt, ImplChain& rChain )
916 {
917  long nActX = rStartPt.X();
918  long nActY = rStartPt.Y();
919  sal_uLong nFound;
920  sal_uLong nLastDir = 0;
921  sal_uLong nDir;
922 
923  do
924  {
925  nFound = 0;
926 
927  // first try last direction
928  long nTryX = nActX + aImplMove[ nLastDir ].nDX;
929  long nTryY = nActY + aImplMove[ nLastDir ].nDY;
930 
931  if( pMap->IsCont( nTryY, nTryX ) )
932  {
933  rChain.ImplAdd( static_cast<sal_uInt8>(nLastDir) );
934  nActY = nTryY;
935  nActX = nTryX;
936  pMap->Set( nActY, nActX, VECT_DONE_INDEX );
937  nFound = 1;
938  }
939  else
940  {
941  // try other directions
942  for( nDir = 0; nDir < 8; nDir++ )
943  {
944  // we already tried nLastDir
945  if( nDir != nLastDir )
946  {
947  nTryX = nActX + aImplMove[ nDir ].nDX;
948  nTryY = nActY + aImplMove[ nDir ].nDY;
949 
950  if( pMap->IsCont( nTryY, nTryX ) )
951  {
952  rChain.ImplAdd( static_cast<sal_uInt8>(nDir) );
953  nActY = nTryY;
954  nActX = nTryX;
955  pMap->Set( nActY, nActX, VECT_DONE_INDEX );
956  nFound = 1;
957  nLastDir = nDir;
958  break;
959  }
960  }
961  }
962  }
963  }
964  while( nFound );
965 
966  return true;
967 }
968 
969 bool ImplIsUp( ImplVectMap const * pMap, long nY, long nX )
970 {
971  if( pMap->IsDone( nY - 1, nX ) )
972  return true;
973  else if( pMap->IsDone( nY + 1, nX ) )
974  return false;
975  else if( pMap->IsDone( nY - 1, nX - 1 ) || pMap->IsDone( nY - 1, nX + 1 ) )
976  return true;
977  else
978  return false;
979 }
980 
981 }
982 
983 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt16 Count() const
Scanline * mpScan
Definition: impvect.cxx:191
long Width() const
Definition: impvect.cxx:200
double mnHeight
#define VECT_POLY_OUTLINE_OUTER
Definition: impvect.cxx:41
sal_uInt8 Get(long nY, long nX) const
Definition: impvect.cxx:238
long GetWidth() const
#define VECT_DONE_INDEX
Definition: impvect.cxx:36
sal_uLong mnArraySize
Definition: impvect.cxx:264
long GetHeight() const
ImplVectMap(long nWidth, long nHeight)
Definition: impvect.cxx:212
void ImplEndAdd(sal_uLong nTypeFlag)
Definition: impvect.cxx:320
long FRound(double fVal)
Scanline GetScanline(long nY) const
static const ChainMove aImplMoveOuter[8]
Definition: impvect.cxx:94
void ImplCreatePoly(tools::Polygon &rPoly) const
Definition: impvect.cxx:181
Scanline const mpBuf
Definition: impvect.cxx:190
#define VECT_POLY_OUTLINE_INNER
Definition: impvect.cxx:40
sal_uIntPtr sal_uLong
static void ImplLimitPolyPoly(tools::PolyPolygon &rPolyPoly)
Definition: impvect.cxx:731
ImplChain & operator=(const ImplChain &)=delete
bool IsDone(long nY, long nX) const
Definition: impvect.cxx:253
#define VECT_FREE_INDEX
Definition: impvect.cxx:34
sal_uInt8 GetLuminance() const
bool ImplVectorize(const Bitmap &rColorBmp, GDIMetaFile &rMtf, sal_uInt8 cReduce, const Link< long, void > *pProgress)
Definition: impvect.cxx:627
static ImplVectMap * ImplExpand(BitmapReadAccess *pRAcc, const Color &rColor)
Definition: impvect.cxx:763
void SetPrefSize(const Size &rSize)
Definition: gdimtf.hxx:174
void Clear()
Definition: gdimtf.cxx:243
void ImplSetSize(sal_uLong nSize)
Definition: impvect.cxx:159
void ImplPostProcess(const ImplPointArray &rArr)
Definition: impvect.cxx:564
void SetSize(sal_uInt16 nNewSize)
sal_uInt16 mnIndex
Definition: impvect.cxx:108
long Width() const
#define VECT_POLY_MAX
Definition: impvect.cxx:32
std::unique_ptr< Point[]> mpArray
Definition: impvect.cxx:134
#define VECT_POLY_INLINE_INNER
Definition: impvect.cxx:38
BitmapColor maColor
Definition: impvect.cxx:107
bool IsCont(long nY, long nX) const
Definition: impvect.cxx:248
void setX(long nX)
sal_uLong mnSize
Definition: impvect.cxx:135
#define X
Definition: field.cxx:1015
std::unique_ptr< sal_uInt8[]> mpCodes
Definition: impvect.cxx:267
#define VECT_CONT_INDEX
Definition: impvect.cxx:35
void Insert(const tools::Polygon &rPoly, sal_uInt16 nPos=POLYPOLY_APPEND)
void setY(long nY)
Point & operator[](sal_uLong nPos)
Definition: impvect.cxx:169
void ImplSetRealSize(sal_uLong nRealSize)
Definition: impvect.cxx:144
void Optimize(PolyOptimizeFlags nOptimizeFlags)
sal_uInt8 * Scanline
Definition: Scanline.hxx:25
int i
const SvxPageUsage aArr[]
bool IsFree(long nY, long nX) const
Definition: impvect.cxx:243
sal_uLong ImplGetRealSize() const
Definition: impvect.cxx:143
const tools::Polygon & ImplGetPoly() const
Definition: impvect.cxx:284
static void ImplCalculate(ImplVectMap *pMap, tools::PolyPolygon &rPolyPoly, sal_uInt8 cReduce)
Definition: impvect.cxx:851
static const ChainMove aImplMove[8]
Definition: impvect.cxx:72
sal_uInt16 GetSize() const
static void VECT_MAP(const std::unique_ptr< long[]> &pMapIn, const std::unique_ptr< long[]> &pMapOut, long nVal)
Definition: impvect.cxx:43
void ImplGetSpace()
Definition: impvect.cxx:294
std::size_t mnCount
void Set(long nY, long nX, sal_uInt8 cVal)
Definition: impvect.cxx:231
sal_uInt32 const mnSize
long X() const
sal_uLong mnCount
Definition: impvect.cxx:265
BitmapColor GetPixel(long nY, long nX) const
#define Y
sal_uInt16 GetPaletteEntryCount() const
tools::Polygon maPoly
Definition: impvect.cxx:262
static const ChainMove aImplMoveInner[8]
Definition: impvect.cxx:83
long Height() const
#define SAL_WARN_IF(condition, area, stream)
unsigned char sal_uInt8
sal_uLong mnRealSize
Definition: impvect.cxx:136
void AddAction(const rtl::Reference< MetaAction > &pAction)
Definition: gdimtf.cxx:539
void Move(long nX, long nY)
Definition: gdimtf.cxx:607
void ImplAdd(sal_uInt8 nCode)
Definition: impvect.cxx:312
double mnWidth
static int ImplColorSetCmpFnc(const ImplColorSet &lhs, const ImplColorSet &rhs)
Definition: impvect.cxx:112
void Scale(double fScaleX, double fScaleY)
Definition: gdimtf.cxx:684
long const mnWidth
Definition: impvect.cxx:192
size_t GetActionSize() const
Definition: gdimtf.cxx:152
long Height() const
Definition: impvect.cxx:201
BitmapColor GetPixelFromData(const sal_uInt8 *pData, long nX) const
static constexpr long BACK_MAP(long _def_nVal)
Definition: impvect.cxx:48
long nDY
Definition: impvect.cxx:70
Point maStartPt
Definition: impvect.cxx:263
const BitmapColor & GetPaletteColor(sal_uInt16 nColor) const
tools::Rectangle GetBoundRect() const
void ImplBeginAdd(const Point &rStartPt)
Definition: impvect.cxx:305
long const mnHeight
Definition: impvect.cxx:193
static void VECT_PROGRESS(const Link< long, void > *pProgress, long _def_nVal)
Definition: impvect.cxx:52
static bool ImplGetChain(ImplVectMap *pMap, const Point &rStartPt, ImplChain &rChain)
Definition: impvect.cxx:915
#define VECT_POLY_INLINE_OUTER
Definition: impvect.cxx:39
BitmapColor GetBestMatchingColor(const BitmapColor &rBitmapColor)
static bool ImplIsUp(ImplVectMap const *pMap, long nY, long nX)
Definition: impvect.cxx:969
long nDX
Definition: impvect.cxx:70
long Y() const
void SetPrefMapMode(const MapMode &rMapMode)
Definition: gdimtf.hxx:177
sal_uInt8 GetIndexFromData(const sal_uInt8 *pData, long nX) const