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