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 mpBuf;
200  Scanline* mpScan;
201  long mnWidth;
202  long 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  nLastX += rMove.nDX;
568  nLastY += rMove.nDY;
569  aArr[ ++i ] = Point( nLastX, nLastY );
570  }
571 
572  aArr.ImplSetRealSize( mnCount + 1 );
573  }
574 
575  ImplPostProcess( aArr );
576  }
577  else
578  maPoly.SetSize( 0 );
579 }
580 
581 void ImplChain::ImplPostProcess( const ImplPointArray& rArr )
582 {
583  ImplPointArray aNewArr1;
584  ImplPointArray aNewArr2;
585  Point* pLast;
586  Point* pLeast;
587  sal_uLong nNewPos;
588  sal_uLong nCount = rArr.ImplGetRealSize();
589  sal_uLong n;
590 
591  // pass 1
592  aNewArr1.ImplSetSize( nCount );
593  pLast = &( aNewArr1[ 0 ] );
594  pLast->setX( BACK_MAP( rArr[ 0 ].X() ) );
595  pLast->setY( BACK_MAP( rArr[ 0 ].Y() ) );
596 
597  for( n = nNewPos = 1; n < nCount; )
598  {
599  const Point& rPt = rArr[ n++ ];
600  const long nX = BACK_MAP( rPt.X() );
601  const long nY = BACK_MAP( rPt.Y() );
602 
603  if( nX != pLast->X() || nY != pLast->Y() )
604  {
605  pLast = pLeast = &( aNewArr1[ nNewPos++ ] );
606  pLeast->setX( nX );
607  pLeast->setY( nY );
608  }
609  }
610 
611  nCount = nNewPos;
612  aNewArr1.ImplSetRealSize( nCount );
613 
614  // pass 2
615  aNewArr2.ImplSetSize( nCount );
616  pLast = &( aNewArr2[ 0 ] );
617  *pLast = aNewArr1[ 0 ];
618 
619  for( n = nNewPos = 1; n < nCount; )
620  {
621  pLeast = &( aNewArr1[ n++ ] );
622 
623  if( pLeast->X() == pLast->X() )
624  {
625  while( n < nCount && aNewArr1[ n ].X() == pLast->X() )
626  pLeast = &( aNewArr1[ n++ ] );
627  }
628  else if( pLeast->Y() == pLast->Y() )
629  {
630  while( n < nCount && aNewArr1[ n ].Y() == pLast->Y() )
631  pLeast = &( aNewArr1[ n++ ] );
632  }
633 
634  pLast = pLeast;
635  aNewArr2[ nNewPos++ ] = *pLast;
636  }
637 
638  aNewArr2.ImplSetRealSize( nNewPos );
639  aNewArr2.ImplCreatePoly( maPoly );
640 }
641 
642 namespace ImplVectorizer {
643 
644 bool ImplVectorize( const Bitmap& rColorBmp, GDIMetaFile& rMtf,
645  sal_uInt8 cReduce, const Link<long,void>* pProgress )
646 {
647  bool bRet = false;
648 
649  VECT_PROGRESS( pProgress, 0 );
650 
651  std::unique_ptr<Bitmap> xBmp(new Bitmap( rColorBmp ));
652  Bitmap::ScopedReadAccess pRAcc(*xBmp);
653 
654  if( pRAcc )
655  {
656  tools::PolyPolygon aPolyPoly;
657  double fPercent = 0.0;
658  double fPercentStep_2 = 0.0;
659  const long nWidth = pRAcc->Width();
660  const long nHeight = pRAcc->Height();
661  const sal_uInt16 nColorCount = pRAcc->GetPaletteEntryCount();
662  sal_uInt16 n;
663  std::array<ImplColorSet, 256> aColorSet;
664 
665  rMtf.Clear();
666 
667  // get used palette colors and sort them from light to dark colors
668  for( n = 0; n < nColorCount; n++ )
669  {
670  aColorSet[ n ].mnIndex = n;
671  aColorSet[ n ].maColor = pRAcc->GetPaletteColor( n );
672  }
673 
674  for( long nY = 0; nY < nHeight; nY++ )
675  {
676  Scanline pScanlineRead = pRAcc->GetScanline( nY );
677  for( long nX = 0; nX < nWidth; nX++ )
678  aColorSet[ pRAcc->GetIndexFromData( pScanlineRead, nX ) ].mbSet = true;
679  }
680 
681  std::sort( aColorSet.begin(), aColorSet.end(), ImplColorSetCmpFnc );
682 
683  for( n = 0; n < 256; n++ )
684  if( !aColorSet[ n ].mbSet )
685  break;
686 
687  if( n )
688  fPercentStep_2 = 45.0 / n;
689 
690  fPercent += 10.0;
691  VECT_PROGRESS( pProgress, FRound( fPercent ) );
692 
693  for( sal_uInt16 i = 0; i < n; i++ )
694  {
695  const BitmapColor aBmpCol( pRAcc->GetPaletteColor( aColorSet[ i ].mnIndex ) );
696  const Color aFindColor( aBmpCol.GetRed(), aBmpCol.GetGreen(), aBmpCol.GetBlue() );
697  std::unique_ptr<ImplVectMap> xMap(ImplExpand( pRAcc.get(), aFindColor ));
698 
699  fPercent += fPercentStep_2;
700  VECT_PROGRESS( pProgress, FRound( fPercent ) );
701 
702  if( xMap )
703  {
704  aPolyPoly.Clear();
705  ImplCalculate( xMap.get(), aPolyPoly, cReduce );
706  xMap.reset();
707 
708  if( aPolyPoly.Count() )
709  {
710  ImplLimitPolyPoly( aPolyPoly );
711 
712  aPolyPoly.Optimize( PolyOptimizeFlags::EDGES );
713 
714  if( aPolyPoly.Count() )
715  {
716  rMtf.AddAction( new MetaLineColorAction( aFindColor, true ) );
717  rMtf.AddAction( new MetaFillColorAction( aFindColor, true ) );
718  rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) );
719  }
720  }
721  }
722 
723  fPercent += fPercentStep_2;
724  VECT_PROGRESS( pProgress, FRound( fPercent ) );
725  }
726 
727  if( rMtf.GetActionSize() )
728  {
729  MapMode aMap( MapUnit::Map100thMM );
731  const Size aLogSize1( aVDev->PixelToLogic( Size( 1, 1 ), aMap ) );
732 
733  rMtf.SetPrefMapMode( aMap );
734  rMtf.SetPrefSize( Size( nWidth + 2, nHeight + 2 ) );
735  rMtf.Move( 1, 1 );
736  rMtf.Scale( aLogSize1.Width(), aLogSize1.Height() );
737  bRet = true;
738  }
739  }
740 
741  pRAcc.reset();
742  xBmp.reset();
743  VECT_PROGRESS( pProgress, 100 );
744 
745  return bRet;
746 }
747 
749 {
750  if( rPolyPoly.Count() > VECT_POLY_MAX )
751  {
752  tools::PolyPolygon aNewPolyPoly;
753  long nReduce = 0;
754  sal_uInt16 nNewCount;
755 
756  do
757  {
758  aNewPolyPoly.Clear();
759  nReduce++;
760 
761  for( sal_uInt16 i = 0, nCount = rPolyPoly.Count(); i < nCount; i++ )
762  {
763  const tools::Rectangle aBound( rPolyPoly[ i ].GetBoundRect() );
764 
765  if( aBound.GetWidth() > nReduce && aBound.GetHeight() > nReduce )
766  {
767  if( rPolyPoly[ i ].GetSize() )
768  aNewPolyPoly.Insert( rPolyPoly[ i ] );
769  }
770  }
771 
772  nNewCount = aNewPolyPoly.Count();
773  }
774  while( nNewCount > VECT_POLY_MAX );
775 
776  rPolyPoly = aNewPolyPoly;
777  }
778 }
779 
780 ImplVectMap* ImplExpand( BitmapReadAccess* pRAcc, const Color& rColor )
781 {
782  ImplVectMap* pMap = nullptr;
783 
784  if( pRAcc && pRAcc->Width() && pRAcc->Height() )
785  {
786  const long nOldWidth = pRAcc->Width();
787  const long nOldHeight = pRAcc->Height();
788  const long nNewWidth = ( nOldWidth << 2 ) + 4;
789  const long nNewHeight = ( nOldHeight << 2 ) + 4;
790  const BitmapColor aTest( pRAcc->GetBestMatchingColor( rColor ) );
791  std::unique_ptr<long[]> pMapIn(new long[ std::max( nOldWidth, nOldHeight ) ]);
792  std::unique_ptr<long[]> pMapOut(new long[ std::max( nOldWidth, nOldHeight ) ]);
793  long nX, nY, nTmpX, nTmpY;
794 
795  pMap = new ImplVectMap( nNewWidth, nNewHeight );
796 
797  for( nX = 0; nX < nOldWidth; nX++ )
798  VECT_MAP( pMapIn, pMapOut, nX );
799 
800  for( nY = 0, nTmpY = 5; nY < nOldHeight; nY++, nTmpY += 4 )
801  {
802  Scanline pScanlineRead = pRAcc->GetScanline( nY );
803  for( nX = 0; nX < nOldWidth; )
804  {
805  if( pRAcc->GetPixelFromData( pScanlineRead, nX ) == aTest )
806  {
807  nTmpX = pMapIn[ nX++ ];
808  nTmpY -= 3;
809 
810  pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
811  pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
812  pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
813  pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
814 
815  while( nX < nOldWidth && pRAcc->GetPixelFromData( pScanlineRead, nX ) == aTest )
816  nX++;
817 
818  nTmpX = pMapOut[ nX - 1 ];
819  nTmpY -= 3;
820 
821  pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
822  pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
823  pMap->Set( nTmpY++, nTmpX, VECT_CONT_INDEX );
824  pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
825  }
826  else
827  nX++;
828  }
829  }
830 
831  for( nY = 0; nY < nOldHeight; nY++ )
832  VECT_MAP( pMapIn, pMapOut, nY );
833 
834  for( nX = 0, nTmpX = 5; nX < nOldWidth; nX++, nTmpX += 4 )
835  {
836  for( nY = 0; nY < nOldHeight; )
837  {
838  if( pRAcc->GetPixel( nY, nX ) == aTest )
839  {
840  nTmpX -= 3;
841  nTmpY = pMapIn[ nY++ ];
842 
843  pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
844  pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
845  pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
846  pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
847 
848  while( nY < nOldHeight && pRAcc->GetPixel( nY, nX ) == aTest )
849  nY++;
850 
851  nTmpX -= 3;
852  nTmpY = pMapOut[ nY - 1 ];
853 
854  pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
855  pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
856  pMap->Set( nTmpY, nTmpX++, VECT_CONT_INDEX );
857  pMap->Set( nTmpY, nTmpX, VECT_CONT_INDEX );
858  }
859  else
860  nY++;
861  }
862  }
863  }
864 
865  return pMap;
866 }
867 
868 void ImplCalculate( ImplVectMap* pMap, tools::PolyPolygon& rPolyPoly, sal_uInt8 cReduce )
869 {
870  const long nWidth = pMap->Width(), nHeight= pMap->Height();
871 
872  for( long nY = 0; nY < nHeight; nY++ )
873  {
874  long nX = 0;
875  bool bInner = true;
876 
877  while( nX < nWidth )
878  {
879  // skip free
880  while( ( nX < nWidth ) && pMap->IsFree( nY, nX ) )
881  nX++;
882 
883  if( nX == nWidth )
884  break;
885 
886  if( pMap->IsCont( nY, nX ) )
887  {
888  // new contour
889  ImplChain aChain;
890  const Point aStartPt( nX++, nY );
891 
892  // get chain code
893  aChain.ImplBeginAdd( aStartPt );
894  ImplGetChain( pMap, aStartPt, aChain );
895 
896  aChain.ImplEndAdd( bInner ? VECT_POLY_OUTLINE_INNER : VECT_POLY_OUTLINE_OUTER );
897 
898  const tools::Polygon& rPoly = aChain.ImplGetPoly();
899 
900  if( rPoly.GetSize() > 2 )
901  {
902  if( cReduce )
903  {
904  const tools::Rectangle aBound( rPoly.GetBoundRect() );
905 
906  if( aBound.GetWidth() > cReduce && aBound.GetHeight() > cReduce )
907  rPolyPoly.Insert( rPoly );
908  }
909  else
910  rPolyPoly.Insert( rPoly );
911  }
912 
913  // skip rest of detected contour
914  while( pMap->IsCont( nY, nX ) )
915  nX++;
916  }
917  else
918  {
919  // process done segment
920  const long nStartSegX = nX++;
921 
922  while( pMap->IsDone( nY, nX ) )
923  nX++;
924 
925  if( ( ( nX - nStartSegX ) == 1 ) || ( ImplIsUp( pMap, nY, nStartSegX ) != ImplIsUp( pMap, nY, nX - 1 ) ) )
926  bInner = !bInner;
927  }
928  }
929  }
930 }
931 
932 bool ImplGetChain( ImplVectMap* pMap, const Point& rStartPt, ImplChain& rChain )
933 {
934  long nActX = rStartPt.X();
935  long nActY = rStartPt.Y();
936  sal_uLong nFound;
937  sal_uLong nLastDir = 0;
938  sal_uLong nDir;
939 
940  do
941  {
942  nFound = 0;
943 
944  // first try last direction
945  long nTryX = nActX + aImplMove[ nLastDir ].nDX;
946  long nTryY = nActY + aImplMove[ nLastDir ].nDY;
947 
948  if( pMap->IsCont( nTryY, nTryX ) )
949  {
950  rChain.ImplAdd( static_cast<sal_uInt8>(nLastDir) );
951  nActY = nTryY;
952  nActX = nTryX;
953  pMap->Set( nActY, nActX, VECT_DONE_INDEX );
954  nFound = 1;
955  }
956  else
957  {
958  // try other directions
959  for( nDir = 0; nDir < 8; nDir++ )
960  {
961  // we already tried nLastDir
962  if( nDir != nLastDir )
963  {
964  nTryX = nActX + aImplMove[ nDir ].nDX;
965  nTryY = nActY + aImplMove[ nDir ].nDY;
966 
967  if( pMap->IsCont( nTryY, nTryX ) )
968  {
969  rChain.ImplAdd( static_cast<sal_uInt8>(nDir) );
970  nActY = nTryY;
971  nActX = nTryX;
972  pMap->Set( nActY, nActX, VECT_DONE_INDEX );
973  nFound = 1;
974  nLastDir = nDir;
975  break;
976  }
977  }
978  }
979  }
980  }
981  while( nFound );
982 
983  return true;
984 }
985 
986 bool ImplIsUp( ImplVectMap const * pMap, long nY, long nX )
987 {
988  if( pMap->IsDone( nY - 1, nX ) )
989  return true;
990  else if( pMap->IsDone( nY + 1, nX ) )
991  return false;
992  else if( pMap->IsDone( nY - 1, nX - 1 ) || pMap->IsDone( nY - 1, nX + 1 ) )
993  return true;
994  else
995  return false;
996 }
997 
998 }
999 
1000 /* 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:748
#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:644
static ImplVectMap * ImplExpand(BitmapReadAccess *pRAcc, const Color &rColor)
Definition: impvect.cxx:780
sal_Int64 n
void SetPrefSize(const Size &rSize)
Definition: gdimtf.hxx:174
void Clear()
Definition: gdimtf.cxx:248
basegfx::BColor maColor
long Width() const
#define VECT_POLY_MAX
Definition: impvect.cxx:32
#define VECT_POLY_INLINE_INNER
Definition: impvect.cxx:38
HashMap_OWString_Interface aMap
#define X
Definition: field.cxx:1063
int nCount
#define VECT_CONT_INDEX
Definition: impvect.cxx:35
void Insert(const tools::Polygon &rPoly, sal_uInt16 nPos=POLYPOLY_APPEND)
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:868
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
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
void AddAction(const rtl::Reference< MetaAction > &pAction)
Definition: gdimtf.cxx:543
void Move(long nX, long nY)
Definition: gdimtf.cxx:611
double mnWidth
void Scale(double fScaleX, double fScaleY)
Definition: gdimtf.cxx:688
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
SVXCORE_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:932
#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:986
void SetPrefMapMode(const MapMode &rMapMode)
Definition: gdimtf.hxx:177
sal_uInt8 GetIndexFromData(const sal_uInt8 *pData, long nX) const
sal_uInt32 mnSize