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