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