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