xref: /trunk/main/vcl/source/gdi/bitmap4.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <stdlib.h>
32 #include <vos/macros.hxx>
33 #include <vcl/bmpacc.hxx>
34 #include <vcl/bitmap.hxx>
35 
36 // -----------
37 // - Defines -
38 // -----------
39 
40 #define S2(a,b)             { register long t; if( ( t = b - a ) < 0 ) { a += t; b -= t; } }
41 #define MN3(a,b,c)          S2(a,b); S2(a,c);
42 #define MX3(a,b,c)          S2(b,c); S2(a,c);
43 #define MNMX3(a,b,c)        MX3(a,b,c); S2(a,b);
44 #define MNMX4(a,b,c,d)      S2(a,b); S2(c,d); S2(a,c); S2(b,d);
45 #define MNMX5(a,b,c,d,e)    S2(a,b); S2(c,d); MN3(a,c,e); MX3(b,d,e);
46 #define MNMX6(a,b,c,d,e,f)  S2(a,d); S2(b,e); S2(c,f); MN3(a,b,c); MX3(d,e,f);
47 
48 // ----------
49 // - Bitmap -
50 // ----------
51 
52 sal_Bool Bitmap::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, const Link* pProgress )
53 {
54     sal_Bool bRet = sal_False;
55 
56     switch( eFilter )
57     {
58         case( BMP_FILTER_SMOOTH ):
59         {
60             const long pSmoothMatrix[] = { 1, 2, 1, 2, 5, 2, 1, 2, 1 };
61             bRet = ImplConvolute3( &pSmoothMatrix[ 0 ], 17, pFilterParam, pProgress );
62         }
63         break;
64 
65         case( BMP_FILTER_SHARPEN ):
66         {
67             const long pSharpenMatrix[] = { -1, -1,  -1, -1, 16, -1, -1, -1,  -1 };
68             bRet = ImplConvolute3( &pSharpenMatrix[ 0 ], 8, pFilterParam, pProgress );
69         }
70         break;
71 
72         case( BMP_FILTER_REMOVENOISE ):
73             bRet = ImplMedianFilter( pFilterParam, pProgress );
74         break;
75 
76         case( BMP_FILTER_SOBEL_GREY ):
77             bRet = ImplSobelGrey( pFilterParam, pProgress );
78         break;
79 
80         case( BMP_FILTER_SOLARIZE ):
81             bRet = ImplSolarize( pFilterParam, pProgress );
82         break;
83 
84         case( BMP_FILTER_SEPIA ):
85             bRet = ImplSepia( pFilterParam, pProgress );
86         break;
87 
88         case( BMP_FILTER_MOSAIC ):
89             bRet = ImplMosaic( pFilterParam, pProgress );
90         break;
91 
92         case( BMP_FILTER_EMBOSS_GREY ):
93             bRet = ImplEmbossGrey( pFilterParam, pProgress );
94         break;
95 
96         case( BMP_FILTER_POPART ):
97             bRet = ImplPopArt( pFilterParam, pProgress );
98         break;
99 
100         default:
101             DBG_ERROR( "Bitmap::Convert(): Unsupported filter" );
102         break;
103     }
104 
105     return bRet;
106 }
107 
108 // -----------------------------------------------------------------------------
109 
110 sal_Bool Bitmap::ImplConvolute3( const long* pMatrix, long nDivisor,
111                              const BmpFilterParam* /*pFilterParam*/, const Link* /*pProgress*/ )
112 {
113     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
114     sal_Bool                bRet = sal_False;
115 
116     if( pReadAcc )
117     {
118         Bitmap              aNewBmp( GetSizePixel(), 24 );
119         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
120 
121         if( pWriteAcc )
122         {
123             const long      nWidth = pWriteAcc->Width(), nWidth2 = nWidth + 2;
124             const long      nHeight = pWriteAcc->Height(), nHeight2 = nHeight + 2;
125             long*           pColm = new long[ nWidth2 ];
126             long*           pRows = new long[ nHeight2 ];
127             BitmapColor*    pColRow1 = (BitmapColor*) new sal_uInt8[ sizeof( BitmapColor ) * nWidth2 ];
128             BitmapColor*    pColRow2 = (BitmapColor*) new sal_uInt8[ sizeof( BitmapColor ) * nWidth2 ];
129             BitmapColor*    pColRow3 = (BitmapColor*) new sal_uInt8[ sizeof( BitmapColor ) * nWidth2 ];
130             BitmapColor*    pRowTmp1 = pColRow1;
131             BitmapColor*    pRowTmp2 = pColRow2;
132             BitmapColor*    pRowTmp3 = pColRow3;
133             BitmapColor*    pColor;
134             long            nY, nX, i, nSumR, nSumG, nSumB, nMatrixVal, nTmp;
135             long            (*pKoeff)[ 256 ] = new long[ 9 ][ 256 ];
136             long*           pTmp;
137 
138             // create LUT of products of matrix value and possible color component values
139             for( nY = 0; nY < 9; nY++ )
140                 for( nX = nTmp = 0, nMatrixVal = pMatrix[ nY ]; nX < 256; nX++, nTmp += nMatrixVal )
141                     pKoeff[ nY ][ nX ] = nTmp;
142 
143             // create column LUT
144             for( i = 0; i < nWidth2; i++ )
145                 pColm[ i ] = ( i > 0 ) ? ( i - 1 ) : 0;
146 
147             pColm[ nWidth + 1 ] = pColm[ nWidth ];
148 
149             // create row LUT
150             for( i = 0; i < nHeight2; i++ )
151                 pRows[ i ] = ( i > 0 ) ? ( i - 1 ) : 0;
152 
153             pRows[ nHeight + 1 ] = pRows[ nHeight ];
154 
155             // read first three rows of bitmap color
156             for( i = 0; i < nWidth2; i++ )
157             {
158                 pColRow1[ i ] = pReadAcc->GetColor( pRows[ 0 ], pColm[ i ] );
159                 pColRow2[ i ] = pReadAcc->GetColor( pRows[ 1 ], pColm[ i ] );
160                 pColRow3[ i ] = pReadAcc->GetColor( pRows[ 2 ], pColm[ i ] );
161             }
162 
163             // do convolution
164             for( nY = 0; nY < nHeight; )
165             {
166                 for( nX = 0; nX < nWidth; nX++ )
167                 {
168                     // first row
169                     nSumR = ( pTmp = pKoeff[ 0 ] )[ ( pColor = pRowTmp1 + nX )->GetRed() ];
170                     nSumG = pTmp[ pColor->GetGreen() ];
171                     nSumB = pTmp[ pColor->GetBlue() ];
172 
173                     nSumR += ( pTmp = pKoeff[ 1 ] )[ ( ++pColor )->GetRed() ];
174                     nSumG += pTmp[ pColor->GetGreen() ];
175                     nSumB += pTmp[ pColor->GetBlue() ];
176 
177                     nSumR += ( pTmp = pKoeff[ 2 ] )[ ( ++pColor )->GetRed() ];
178                     nSumG += pTmp[ pColor->GetGreen() ];
179                     nSumB += pTmp[ pColor->GetBlue() ];
180 
181                     // second row
182                     nSumR += ( pTmp = pKoeff[ 3 ] )[ ( pColor = pRowTmp2 + nX )->GetRed() ];
183                     nSumG += pTmp[ pColor->GetGreen() ];
184                     nSumB += pTmp[ pColor->GetBlue() ];
185 
186                     nSumR += ( pTmp = pKoeff[ 4 ] )[ ( ++pColor )->GetRed() ];
187                     nSumG += pTmp[ pColor->GetGreen() ];
188                     nSumB += pTmp[ pColor->GetBlue() ];
189 
190                     nSumR += ( pTmp = pKoeff[ 5 ] )[ ( ++pColor )->GetRed() ];
191                     nSumG += pTmp[ pColor->GetGreen() ];
192                     nSumB += pTmp[ pColor->GetBlue() ];
193 
194                     // third row
195                     nSumR += ( pTmp = pKoeff[ 6 ] )[ ( pColor = pRowTmp3 + nX )->GetRed() ];
196                     nSumG += pTmp[ pColor->GetGreen() ];
197                     nSumB += pTmp[ pColor->GetBlue() ];
198 
199                     nSumR += ( pTmp = pKoeff[ 7 ] )[ ( ++pColor )->GetRed() ];
200                     nSumG += pTmp[ pColor->GetGreen() ];
201                     nSumB += pTmp[ pColor->GetBlue() ];
202 
203                     nSumR += ( pTmp = pKoeff[ 8 ] )[ ( ++pColor )->GetRed() ];
204                     nSumG += pTmp[ pColor->GetGreen() ];
205                     nSumB += pTmp[ pColor->GetBlue() ];
206 
207                     // calculate destination color
208                     pWriteAcc->SetPixel( nY, nX, BitmapColor( (sal_uInt8) MinMax( nSumR / nDivisor, 0, 255 ),
209                                                               (sal_uInt8) MinMax( nSumG / nDivisor, 0, 255 ),
210                                                               (sal_uInt8) MinMax( nSumB / nDivisor, 0, 255 ) ) );
211                 }
212 
213                 if( ++nY < nHeight )
214                 {
215                     if( pRowTmp1 == pColRow1 )
216                         pRowTmp1 = pColRow2, pRowTmp2 = pColRow3, pRowTmp3 = pColRow1;
217                     else if( pRowTmp1 == pColRow2 )
218                         pRowTmp1 = pColRow3, pRowTmp2 = pColRow1, pRowTmp3 = pColRow2;
219                     else
220                         pRowTmp1 = pColRow1, pRowTmp2 = pColRow2, pRowTmp3 = pColRow3;
221 
222                     for( i = 0; i < nWidth2; i++ )
223                         pRowTmp3[ i ] = pReadAcc->GetColor( pRows[ nY + 2 ], pColm[ i ] );
224                 }
225             }
226 
227             delete[] pKoeff;
228             delete[] (sal_uInt8*) pColRow1;
229             delete[] (sal_uInt8*) pColRow2;
230             delete[] (sal_uInt8*) pColRow3;
231             delete[] pColm;
232             delete[] pRows;
233 
234             aNewBmp.ReleaseAccess( pWriteAcc );
235 
236             bRet = sal_True;
237         }
238 
239         ReleaseAccess( pReadAcc );
240 
241         if( bRet )
242         {
243             const MapMode   aMap( maPrefMapMode );
244             const Size      aSize( maPrefSize );
245 
246             *this = aNewBmp;
247 
248             maPrefMapMode = aMap;
249             maPrefSize = aSize;
250         }
251     }
252 
253     return bRet;
254 }
255 
256 // -----------------------------------------------------------------------------
257 
258 sal_Bool Bitmap::ImplMedianFilter( const BmpFilterParam* /*pFilterParam*/, const Link* /*pProgress*/ )
259 {
260     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
261     sal_Bool                bRet = sal_False;
262 
263     if( pReadAcc )
264     {
265         Bitmap              aNewBmp( GetSizePixel(), 24 );
266         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
267 
268         if( pWriteAcc )
269         {
270             const long      nWidth = pWriteAcc->Width(), nWidth2 = nWidth + 2;
271             const long      nHeight = pWriteAcc->Height(), nHeight2 = nHeight + 2;
272             long*           pColm = new long[ nWidth2 ];
273             long*           pRows = new long[ nHeight2 ];
274             BitmapColor*    pColRow1 = (BitmapColor*) new sal_uInt8[ sizeof( BitmapColor ) * nWidth2 ];
275             BitmapColor*    pColRow2 = (BitmapColor*) new sal_uInt8[ sizeof( BitmapColor ) * nWidth2 ];
276             BitmapColor*    pColRow3 = (BitmapColor*) new sal_uInt8[ sizeof( BitmapColor ) * nWidth2 ];
277             BitmapColor*    pRowTmp1 = pColRow1;
278             BitmapColor*    pRowTmp2 = pColRow2;
279             BitmapColor*    pRowTmp3 = pColRow3;
280             BitmapColor*    pColor;
281             long            nY, nX, i;
282             long            nR1, nR2, nR3, nR4, nR5, nR6, nR7, nR8, nR9;
283             long            nG1, nG2, nG3, nG4, nG5, nG6, nG7, nG8, nG9;
284             long            nB1, nB2, nB3, nB4, nB5, nB6, nB7, nB8, nB9;
285 
286             // create column LUT
287             for( i = 0; i < nWidth2; i++ )
288                 pColm[ i ] = ( i > 0 ) ? ( i - 1 ) : 0;
289 
290             pColm[ nWidth + 1 ] = pColm[ nWidth ];
291 
292             // create row LUT
293             for( i = 0; i < nHeight2; i++ )
294                 pRows[ i ] = ( i > 0 ) ? ( i - 1 ) : 0;
295 
296             pRows[ nHeight + 1 ] = pRows[ nHeight ];
297 
298             // read first three rows of bitmap color
299             if (nHeight2 > 2)
300             {
301                 for( i = 0; i < nWidth2; i++ )
302                 {
303                     pColRow1[ i ] = pReadAcc->GetColor( pRows[ 0 ], pColm[ i ] );
304                     pColRow2[ i ] = pReadAcc->GetColor( pRows[ 1 ], pColm[ i ] );
305                     pColRow3[ i ] = pReadAcc->GetColor( pRows[ 2 ], pColm[ i ] );
306                 }
307             }
308 
309             // do median filtering
310             for( nY = 0; nY < nHeight; )
311             {
312                 for( nX = 0; nX < nWidth; nX++ )
313                 {
314                     nR1 = ( pColor = pRowTmp1 + nX )->GetRed(), nG1 = pColor->GetGreen(), nB1 = pColor->GetBlue();
315                     nR2 = ( ++pColor )->GetRed(), nG2 = pColor->GetGreen(), nB2 = pColor->GetBlue();
316                     nR3 = ( ++pColor )->GetRed(), nG3 = pColor->GetGreen(), nB3 = pColor->GetBlue();
317 
318                     nR4 = ( pColor = pRowTmp2 + nX )->GetRed(), nG4 = pColor->GetGreen(), nB4 = pColor->GetBlue();
319                     nR5 = ( ++pColor )->GetRed(), nG5 = pColor->GetGreen(), nB5 = pColor->GetBlue();
320                     nR6 = ( ++pColor )->GetRed(), nG6 = pColor->GetGreen(), nB6 = pColor->GetBlue();
321 
322                     nR7 = ( pColor = pRowTmp3 + nX )->GetRed(), nG7 = pColor->GetGreen(), nB7 = pColor->GetBlue();
323                     nR8 = ( ++pColor )->GetRed(), nG8 = pColor->GetGreen(), nB8 = pColor->GetBlue();
324                     nR9 = ( ++pColor )->GetRed(), nG9 = pColor->GetGreen(), nB9 = pColor->GetBlue();
325 
326                     MNMX6( nR1, nR2, nR3, nR4, nR5, nR6 );
327                     MNMX5( nR7, nR2, nR3, nR4, nR5 );
328                     MNMX4( nR8, nR2, nR3, nR4 );
329                     MNMX3( nR9, nR2, nR3 );
330 
331                     MNMX6( nG1, nG2, nG3, nG4, nG5, nG6 );
332                     MNMX5( nG7, nG2, nG3, nG4, nG5 );
333                     MNMX4( nG8, nG2, nG3, nG4 );
334                     MNMX3( nG9, nG2, nG3 );
335 
336                     MNMX6( nB1, nB2, nB3, nB4, nB5, nB6 );
337                     MNMX5( nB7, nB2, nB3, nB4, nB5 );
338                     MNMX4( nB8, nB2, nB3, nB4 );
339                     MNMX3( nB9, nB2, nB3 );
340 
341                     // set destination color
342                     pWriteAcc->SetPixel( nY, nX, BitmapColor( (sal_uInt8) nR2, (sal_uInt8) nG2, (sal_uInt8) nB2 ) );
343                 }
344 
345                 if( ++nY < nHeight )
346                 {
347                     if( pRowTmp1 == pColRow1 )
348                         pRowTmp1 = pColRow2, pRowTmp2 = pColRow3, pRowTmp3 = pColRow1;
349                     else if( pRowTmp1 == pColRow2 )
350                         pRowTmp1 = pColRow3, pRowTmp2 = pColRow1, pRowTmp3 = pColRow2;
351                     else
352                         pRowTmp1 = pColRow1, pRowTmp2 = pColRow2, pRowTmp3 = pColRow3;
353 
354                     for( i = 0; i < nWidth2; i++ )
355                         pRowTmp3[ i ] = pReadAcc->GetColor( pRows[ nY + 2 ], pColm[ i ] );
356                 }
357             }
358 
359             delete[] (sal_uInt8*) pColRow1;
360             delete[] (sal_uInt8*) pColRow2;
361             delete[] (sal_uInt8*) pColRow3;
362             delete[] pColm;
363             delete[] pRows;
364 
365             aNewBmp.ReleaseAccess( pWriteAcc );
366 
367             bRet = sal_True;
368         }
369 
370         ReleaseAccess( pReadAcc );
371 
372         if( bRet )
373         {
374             const MapMode   aMap( maPrefMapMode );
375             const Size      aSize( maPrefSize );
376 
377             *this = aNewBmp;
378 
379             maPrefMapMode = aMap;
380             maPrefSize = aSize;
381         }
382     }
383 
384     return bRet;
385 }
386 
387 // -----------------------------------------------------------------------------
388 
389 sal_Bool Bitmap::ImplSobelGrey( const BmpFilterParam* /*pFilterParam*/, const Link* /*pProgress*/ )
390 {
391     sal_Bool bRet = ImplMakeGreyscales( 256 );
392 
393     if( bRet )
394     {
395         bRet = sal_False;
396 
397         BitmapReadAccess* pReadAcc = AcquireReadAccess();
398 
399         if( pReadAcc )
400         {
401             Bitmap              aNewBmp( GetSizePixel(), 8, &pReadAcc->GetPalette() );
402             BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
403 
404             if( pWriteAcc )
405             {
406                 BitmapColor aGrey( (sal_uInt8) 0 );
407                 const long  nWidth = pWriteAcc->Width();
408                 const long  nHeight = pWriteAcc->Height();
409                 const long  nMask111 = -1, nMask121 =  0, nMask131 =  1;
410                 const long  nMask211 = -2, nMask221 =  0, nMask231 =  2;
411                 const long  nMask311 = -1, nMask321 =  0, nMask331 =  1;
412                 const long  nMask112 =  1, nMask122 =  2, nMask132 =  1;
413                 const long  nMask212 =  0, nMask222 =  0, nMask232 =  0;
414                 const long  nMask312 = -1, nMask322 = -2, nMask332 = -1;
415                 long        nGrey11, nGrey12, nGrey13;
416                 long        nGrey21, nGrey22, nGrey23;
417                 long        nGrey31, nGrey32, nGrey33;
418                 long*       pHMap = new long[ nWidth + 2 ];
419                 long*       pVMap = new long[ nHeight + 2 ];
420                 long        nX, nY, nSum1, nSum2;
421 
422                 // fill mapping tables
423                 pHMap[ 0 ] = 0;
424                 for( nX = 1; nX <= nWidth; nX++ )
425                     pHMap[ nX ] = nX - 1;
426                 pHMap[ nWidth + 1 ] = nWidth - 1;
427 
428                 pVMap[ 0 ] = 0;
429                 for( nY = 1; nY <= nHeight; nY++ )
430                     pVMap[ nY ] = nY - 1;
431                 pVMap[ nHeight + 1 ] = nHeight - 1;
432 
433                 for( nY = 0; nY < nHeight ; nY++ )
434                 {
435                     nGrey11 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 0 ] ).GetIndex();
436                     nGrey12 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 1 ] ).GetIndex();
437                     nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 2 ] ).GetIndex();
438                     nGrey21 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 0 ] ).GetIndex();
439                     nGrey22 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 1 ] ).GetIndex();
440                     nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 2 ] ).GetIndex();
441                     nGrey31 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 0 ] ).GetIndex();
442                     nGrey32 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 1 ] ).GetIndex();
443                     nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 2 ] ).GetIndex();
444 
445                     for( nX = 0; nX < nWidth; nX++ )
446                     {
447                         nSum1 = nSum2 = 0;
448 
449                         nSum1 += nMask111 * nGrey11;
450                         nSum2 += nMask112 * nGrey11;
451 
452                         nSum1 += nMask121 * nGrey12;
453                         nSum2 += nMask122 * nGrey12;
454 
455                         nSum1 += nMask131 * nGrey13;
456                         nSum2 += nMask132 * nGrey13;
457 
458                         nSum1 += nMask211 * nGrey21;
459                         nSum2 += nMask212 * nGrey21;
460 
461                         nSum1 += nMask221 * nGrey22;
462                         nSum2 += nMask222 * nGrey22;
463 
464                         nSum1 += nMask231 * nGrey23;
465                         nSum2 += nMask232 * nGrey23;
466 
467                         nSum1 += nMask311 * nGrey31;
468                         nSum2 += nMask312 * nGrey31;
469 
470                         nSum1 += nMask321 * nGrey32;
471                         nSum2 += nMask322 * nGrey32;
472 
473                         nSum1 += nMask331 * nGrey33;
474                         nSum2 += nMask332 * nGrey33;
475 
476                         nSum1 = (long) sqrt( (double)( nSum1 * nSum1 + nSum2 * nSum2 ) );
477                         aGrey.SetIndex( ~(sal_uInt8) VOS_BOUND( nSum1, 0, 255 ) );
478                         pWriteAcc->SetPixel( nY, nX, aGrey );
479 
480                         if( nX < ( nWidth - 1 ) )
481                         {
482                             const long nNextX = pHMap[ nX + 3 ];
483 
484                             nGrey11 = nGrey12; nGrey12 = nGrey13; nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], nNextX ).GetIndex();
485                             nGrey21 = nGrey22; nGrey22 = nGrey23; nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], nNextX ).GetIndex();
486                             nGrey31 = nGrey32; nGrey32 = nGrey33; nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], nNextX ).GetIndex();
487                         }
488                     }
489                 }
490 
491                 delete[] pHMap;
492                 delete[] pVMap;
493                 aNewBmp.ReleaseAccess( pWriteAcc );
494                 bRet = sal_True;
495             }
496 
497             ReleaseAccess( pReadAcc );
498 
499             if( bRet )
500             {
501                 const MapMode   aMap( maPrefMapMode );
502                 const Size      aSize( maPrefSize );
503 
504                 *this = aNewBmp;
505 
506                 maPrefMapMode = aMap;
507                 maPrefSize = aSize;
508             }
509         }
510     }
511 
512     return bRet;
513 }
514 
515 // -----------------------------------------------------------------------------
516 
517 sal_Bool Bitmap::ImplEmbossGrey( const BmpFilterParam* pFilterParam, const Link* /*pProgress*/ )
518 {
519     sal_Bool bRet = ImplMakeGreyscales( 256 );
520 
521     if( bRet )
522     {
523         bRet = sal_False;
524 
525         BitmapReadAccess* pReadAcc = AcquireReadAccess();
526 
527         if( pReadAcc )
528         {
529             Bitmap              aNewBmp( GetSizePixel(), 8, &pReadAcc->GetPalette() );
530             BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
531 
532             if( pWriteAcc )
533             {
534                 BitmapColor aGrey( (sal_uInt8) 0 );
535                 const long  nWidth = pWriteAcc->Width();
536                 const long  nHeight = pWriteAcc->Height();
537                 long        nGrey11, nGrey12, nGrey13;
538                 long        nGrey21, nGrey22, nGrey23;
539                 long        nGrey31, nGrey32, nGrey33;
540                 double      fAzim = ( ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_EMBOSS_GREY ) ?
541                                       ( pFilterParam->maEmbossAngles.mnAzimuthAngle100 * 0.01 ) : 0.0 ) * F_PI180;
542                 double      fElev = ( ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_EMBOSS_GREY ) ?
543                                       ( pFilterParam->maEmbossAngles.mnElevationAngle100 * 0.01 ) : 90.0 ) * F_PI180;
544                 long*       pHMap = new long[ nWidth + 2 ];
545                 long*       pVMap = new long[ nHeight + 2 ];
546                 long        nX, nY, nNx, nNy, nDotL;
547                 const long  nLx = FRound( cos( fAzim ) * cos( fElev ) * 255.0 );
548                 const long  nLy = FRound( sin( fAzim ) * cos( fElev ) * 255.0 );
549                 const long  nLz = FRound( sin( fElev ) * 255.0 );
550                 const long  nZ2 = ( ( 6 * 255 ) / 4 ) * ( ( 6 * 255 ) / 4 );
551                 const long  nNzLz = ( ( 6 * 255 ) / 4 ) * nLz;
552                 const sal_uInt8 cLz = (sal_uInt8) VOS_BOUND( nLz, 0, 255 );
553 
554                 // fill mapping tables
555                 pHMap[ 0 ] = 0;
556                 for( nX = 1; nX <= nWidth; nX++ )
557                     pHMap[ nX ] = nX - 1;
558                 pHMap[ nWidth + 1 ] = nWidth - 1;
559 
560                 pVMap[ 0 ] = 0;
561                 for( nY = 1; nY <= nHeight; nY++ )
562                     pVMap[ nY ] = nY - 1;
563                 pVMap[ nHeight + 1 ] = nHeight - 1;
564 
565                 for( nY = 0; nY < nHeight ; nY++ )
566                 {
567                     nGrey11 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 0 ] ).GetIndex();
568                     nGrey12 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 1 ] ).GetIndex();
569                     nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], pHMap[ 2 ] ).GetIndex();
570                     nGrey21 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 0 ] ).GetIndex();
571                     nGrey22 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 1 ] ).GetIndex();
572                     nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], pHMap[ 2 ] ).GetIndex();
573                     nGrey31 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 0 ] ).GetIndex();
574                     nGrey32 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 1 ] ).GetIndex();
575                     nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], pHMap[ 2 ] ).GetIndex();
576 
577                     for( nX = 0; nX < nWidth; nX++ )
578                     {
579                         nNx = nGrey11 + nGrey21 + nGrey31 - nGrey13 - nGrey23 - nGrey33;
580                         nNy = nGrey31 + nGrey32 + nGrey33 - nGrey11 - nGrey12 - nGrey13;
581 
582                         if( !nNx && !nNy )
583                             aGrey.SetIndex( cLz );
584                         else if( ( nDotL = nNx * nLx + nNy * nLy +nNzLz ) < 0 )
585                             aGrey.SetIndex( 0 );
586                         else
587                         {
588                             const double fGrey = nDotL / sqrt( (double)(nNx * nNx + nNy * nNy + nZ2) );
589                             aGrey.SetIndex( (sal_uInt8) VOS_BOUND( fGrey, 0, 255 ) );
590                         }
591 
592                         pWriteAcc->SetPixel( nY, nX, aGrey );
593 
594                         if( nX < ( nWidth - 1 ) )
595                         {
596                             const long nNextX = pHMap[ nX + 3 ];
597 
598                             nGrey11 = nGrey12; nGrey12 = nGrey13; nGrey13 = pReadAcc->GetPixel( pVMap[ nY ], nNextX ).GetIndex();
599                             nGrey21 = nGrey22; nGrey22 = nGrey23; nGrey23 = pReadAcc->GetPixel( pVMap[ nY + 1 ], nNextX ).GetIndex();
600                             nGrey31 = nGrey32; nGrey32 = nGrey33; nGrey33 = pReadAcc->GetPixel( pVMap[ nY + 2 ], nNextX ).GetIndex();
601                         }
602                     }
603                 }
604 
605                 delete[] pHMap;
606                 delete[] pVMap;
607                 aNewBmp.ReleaseAccess( pWriteAcc );
608                 bRet = sal_True;
609             }
610 
611             ReleaseAccess( pReadAcc );
612 
613             if( bRet )
614             {
615                 const MapMode   aMap( maPrefMapMode );
616                 const Size      aSize( maPrefSize );
617 
618                 *this = aNewBmp;
619 
620                 maPrefMapMode = aMap;
621                 maPrefSize = aSize;
622             }
623         }
624     }
625 
626     return bRet;
627 }
628 
629 // -----------------------------------------------------------------------------
630 
631 sal_Bool Bitmap::ImplSolarize( const BmpFilterParam* pFilterParam, const Link* /*pProgress*/ )
632 {
633     sal_Bool                bRet = sal_False;
634     BitmapWriteAccess*  pWriteAcc = AcquireWriteAccess();
635 
636     if( pWriteAcc )
637     {
638         const sal_uInt8 cThreshold = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_SOLARIZE ) ?
639                                 pFilterParam->mcSolarGreyThreshold : 128;
640 
641         if( pWriteAcc->HasPalette() )
642         {
643             const BitmapPalette& rPal = pWriteAcc->GetPalette();
644 
645             for( sal_uInt16 i = 0, nCount = rPal.GetEntryCount(); i < nCount; i++ )
646             {
647                 if( rPal[ i ].GetLuminance() >= cThreshold )
648                 {
649                     BitmapColor aCol( rPal[ i ] );
650                     pWriteAcc->SetPaletteColor( i, aCol.Invert() );
651                 }
652             }
653         }
654         else
655         {
656             BitmapColor aCol;
657             const long  nWidth = pWriteAcc->Width();
658             const long  nHeight = pWriteAcc->Height();
659 
660             for( long nY = 0; nY < nHeight ; nY++ )
661             {
662                 for( long nX = 0; nX < nWidth; nX++ )
663                 {
664                     aCol = pWriteAcc->GetPixel( nY, nX );
665 
666                     if( aCol.GetLuminance() >= cThreshold )
667                         pWriteAcc->SetPixel( nY, nX, aCol.Invert() );
668                 }
669             }
670         }
671 
672         ReleaseAccess( pWriteAcc );
673         bRet = sal_True;
674     }
675 
676     return bRet;
677 }
678 
679 // -----------------------------------------------------------------------------
680 
681 sal_Bool Bitmap::ImplSepia( const BmpFilterParam* pFilterParam, const Link* /*pProgress*/ )
682 {
683     BitmapReadAccess*   pReadAcc = AcquireReadAccess();
684     sal_Bool                bRet = sal_False;
685 
686     if( pReadAcc )
687     {
688         long            nSepiaPercent = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_SEPIA ) ?
689                                         pFilterParam->mcSolarGreyThreshold : 10;
690         const long      nSepia = 10000 - 100 * VOS_BOUND( nSepiaPercent, 0, 100 );
691         BitmapPalette   aSepiaPal( 256 );
692 
693         DBG_ASSERT( nSepiaPercent <= 100, "Bitmap::ImplSepia(): sepia value out of range; defaulting to 100%" );
694 
695         for( sal_uInt16 i = 0; i < 256; i++ )
696         {
697             BitmapColor&    rCol = aSepiaPal[ i ];
698             const sal_uInt8     cSepiaValue = (sal_uInt8) ( ( nSepia * i ) / 10000 );
699 
700             rCol.SetRed( (sal_uInt8) i );
701             rCol.SetGreen( cSepiaValue );
702             rCol.SetBlue( cSepiaValue );
703         }
704 
705         Bitmap              aNewBmp( GetSizePixel(), 8, &aSepiaPal );
706         BitmapWriteAccess*  pWriteAcc = aNewBmp.AcquireWriteAccess();
707 
708         if( pWriteAcc )
709         {
710             BitmapColor aCol( (sal_uInt8) 0 );
711             const long  nWidth = pWriteAcc->Width();
712             const long  nHeight = pWriteAcc->Height();
713 
714             if( pReadAcc->HasPalette() )
715             {
716                 for( long nY = 0; nY < nHeight ; nY++ )
717                 {
718                     const sal_uInt16    nPalCount = pReadAcc->GetPaletteEntryCount();
719                     sal_uInt8*          pIndexMap = new sal_uInt8[ nPalCount ];
720 
721                     for( sal_uInt16 i = 0; i < nPalCount; i++ )
722                         pIndexMap[ i ] = pReadAcc->GetPaletteColor( i ).GetLuminance();
723 
724                     for( long nX = 0; nX < nWidth; nX++ )
725                     {
726                         aCol.SetIndex( pIndexMap[ pReadAcc->GetPixel( nY, nX ).GetIndex() ] );
727                         pWriteAcc->SetPixel( nY, nX, aCol );
728                     }
729 
730                     delete[] pIndexMap;
731                 }
732             }
733             else
734             {
735                 for( long nY = 0; nY < nHeight ; nY++ )
736                 {
737                     for( long nX = 0; nX < nWidth; nX++ )
738                     {
739                         aCol.SetIndex( pReadAcc->GetPixel( nY, nX ).GetLuminance() );
740                         pWriteAcc->SetPixel( nY, nX, aCol );
741                     }
742                 }
743             }
744 
745             aNewBmp.ReleaseAccess( pWriteAcc );
746             bRet = sal_True;
747         }
748 
749         ReleaseAccess( pReadAcc );
750 
751         if( bRet )
752         {
753             const MapMode   aMap( maPrefMapMode );
754             const Size      aSize( maPrefSize );
755 
756             *this = aNewBmp;
757 
758             maPrefMapMode = aMap;
759             maPrefSize = aSize;
760         }
761     }
762 
763     return bRet;
764 }
765 
766 // -----------------------------------------------------------------------------
767 
768 sal_Bool Bitmap::ImplMosaic( const BmpFilterParam* pFilterParam, const Link* /*pProgress*/ )
769 {
770     sal_uLong               nTileWidth = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_MOSAIC ) ?
771                                      pFilterParam->maMosaicTileSize.mnTileWidth : 4;
772     sal_uLong               nTileHeight = ( pFilterParam && pFilterParam->meFilter == BMP_FILTER_MOSAIC ) ?
773                                       pFilterParam->maMosaicTileSize.mnTileHeight : 4;
774     sal_Bool                bRet = sal_False;
775 
776     if( !nTileWidth )
777         nTileWidth = 1;
778 
779     if( !nTileHeight )
780         nTileHeight = 1;
781 
782     if( nTileWidth > 1 || nTileHeight > 1 )
783     {
784         Bitmap*             pNewBmp;
785         BitmapReadAccess*   pReadAcc;
786         BitmapWriteAccess*  pWriteAcc;
787 
788         if( GetBitCount() > 8 )
789         {
790             pNewBmp = NULL;
791             pReadAcc = pWriteAcc = AcquireWriteAccess();
792         }
793         else
794         {
795             pNewBmp = new Bitmap( GetSizePixel(), 24 );
796             pReadAcc = AcquireReadAccess();
797             pWriteAcc = pNewBmp->AcquireWriteAccess();
798         }
799 
800         if( pReadAcc && pWriteAcc )
801         {
802             BitmapColor aCol;
803             long        nWidth = pReadAcc->Width();
804             long        nHeight = pReadAcc->Height();
805             long        nX, nY, nX1, nX2, nY1, nY2, nSumR, nSumG, nSumB;
806             double      fArea_1;
807 
808             nY1 = 0; nY2 = nTileHeight - 1;
809 
810             if( nY2 >= nHeight )
811                 nY2 = nHeight - 1;
812 
813             do
814             {
815                 nX1 = 0; nX2 = nTileWidth - 1;
816 
817                 if( nX2 >= nWidth )
818                     nX2 = nWidth - 1;
819 
820                 fArea_1 = 1.0 / ( ( nX2 - nX1 + 1 ) * ( nY2 - nY1 + 1 ) );
821 
822                 if( !pNewBmp )
823                 {
824                     do
825                     {
826                         for( nY = nY1, nSumR = nSumG = nSumB = 0; nY <= nY2; nY++ )
827                         {
828                             for( nX = nX1; nX <= nX2; nX++ )
829                             {
830                                 aCol = pReadAcc->GetPixel( nY, nX );
831                                 nSumR += aCol.GetRed();
832                                 nSumG += aCol.GetGreen();
833                                 nSumB += aCol.GetBlue();
834                             }
835                         }
836 
837                         aCol.SetRed( (sal_uInt8) ( nSumR * fArea_1 ) );
838                         aCol.SetGreen( (sal_uInt8) ( nSumG * fArea_1 ) );
839                         aCol.SetBlue( (sal_uInt8) ( nSumB * fArea_1 ) );
840 
841                         for( nY = nY1; nY <= nY2; nY++ )
842                             for( nX = nX1; nX <= nX2; nX++ )
843                                 pWriteAcc->SetPixel( nY, nX, aCol );
844 
845                         nX1 += nTileWidth; nX2 += nTileWidth;
846 
847                         if( nX2 >= nWidth )
848                         {
849                             nX2 = nWidth - 1;
850                             fArea_1 = 1.0 / ( ( nX2 - nX1 + 1 ) * ( nY2 - nY1 + 1 ) );
851                         }
852                     }
853                     while( nX1 < nWidth );
854                 }
855                 else
856                 {
857                     do
858                     {
859                         for( nY = nY1, nSumR = nSumG = nSumB = 0; nY <= nY2; nY++ )
860                         {
861                             for( nX = nX1; nX <= nX2; nX++ )
862                             {
863                                 const BitmapColor& rCol = pReadAcc->GetPaletteColor( (sal_uInt8) pReadAcc->GetPixel( nY, nX ) );
864                                 nSumR += rCol.GetRed();
865                                 nSumG += rCol.GetGreen();
866                                 nSumB += rCol.GetBlue();
867                             }
868                         }
869 
870                         aCol.SetRed( (sal_uInt8) ( nSumR * fArea_1 ) );
871                         aCol.SetGreen( (sal_uInt8) ( nSumG * fArea_1 ) );
872                         aCol.SetBlue( (sal_uInt8) ( nSumB * fArea_1 ) );
873 
874                         for( nY = nY1; nY <= nY2; nY++ )
875                             for( nX = nX1; nX <= nX2; nX++ )
876                                 pWriteAcc->SetPixel( nY, nX, aCol );
877 
878                         nX1 += nTileWidth; nX2 += nTileWidth;
879 
880                         if( nX2 >= nWidth )
881                         {
882                             nX2 = nWidth - 1;
883                             fArea_1 = 1.0 / ( ( nX2 - nX1 + 1 ) * ( nY2 - nY1 + 1 ) );
884                         }
885                     }
886                     while( nX1 < nWidth );
887                 }
888 
889                 nY1 += nTileHeight; nY2 += nTileHeight;
890 
891                 if( nY2 >= nHeight )
892                     nY2 = nHeight - 1;
893             }
894             while( nY1 < nHeight );
895 
896             bRet = sal_True;
897         }
898 
899         ReleaseAccess( pReadAcc );
900 
901         if( pNewBmp )
902         {
903             pNewBmp->ReleaseAccess( pWriteAcc );
904 
905             if( bRet )
906             {
907                 const MapMode   aMap( maPrefMapMode );
908                 const Size      aSize( maPrefSize );
909 
910                 *this = *pNewBmp;
911 
912                 maPrefMapMode = aMap;
913                 maPrefSize = aSize;
914             }
915 
916             delete pNewBmp;
917         }
918     }
919     else
920         bRet = sal_True;
921 
922     return bRet;
923 }
924 
925 // -----------------------------------------------------------------------------
926 
927 struct PopArtEntry
928 {
929     sal_uInt32  mnIndex;
930     sal_uInt32  mnCount;
931 };
932 
933 // ------------------------------------------------------------------------
934 
935 extern "C" int __LOADONCALLAPI ImplPopArtCmpFnc( const void* p1, const void* p2 )
936 {
937     int nRet;
938 
939     if( ( (PopArtEntry*) p1 )->mnCount < ( (PopArtEntry*) p2 )->mnCount )
940         nRet = 1;
941     else if( ( (PopArtEntry*) p1 )->mnCount == ( (PopArtEntry*) p2 )->mnCount )
942         nRet = 0;
943     else
944         nRet = -1;
945 
946     return nRet;
947 }
948 
949 // ------------------------------------------------------------------------
950 
951 sal_Bool Bitmap::ImplPopArt( const BmpFilterParam* /*pFilterParam*/, const Link* /*pProgress*/ )
952 {
953     sal_Bool bRet = ( GetBitCount() > 8 ) ? Convert( BMP_CONVERSION_8BIT_COLORS ) : sal_True;
954 
955     if( bRet )
956     {
957         bRet = sal_False;
958 
959         BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
960 
961         if( pWriteAcc )
962         {
963             const long      nWidth = pWriteAcc->Width();
964             const long      nHeight = pWriteAcc->Height();
965             const sal_uLong     nEntryCount = 1 << pWriteAcc->GetBitCount();
966             sal_uLong           n;
967             PopArtEntry*    pPopArtTable = new PopArtEntry[ nEntryCount ];
968 
969             for( n = 0; n < nEntryCount; n++ )
970             {
971                 PopArtEntry& rEntry = pPopArtTable[ n ];
972                 rEntry.mnIndex = (sal_uInt16) n;
973                 rEntry.mnCount = 0;
974             }
975 
976             // get pixel count for each palette entry
977             for( long nY = 0; nY < nHeight ; nY++ )
978                 for( long nX = 0; nX < nWidth; nX++ )
979                     pPopArtTable[ pWriteAcc->GetPixel( nY, nX ).GetIndex() ].mnCount++;
980 
981             // sort table
982             qsort( pPopArtTable, nEntryCount, sizeof( PopArtEntry ), ImplPopArtCmpFnc );
983 
984             // get last used entry
985             sal_uLong nFirstEntry;
986             sal_uLong nLastEntry = 0;
987 
988             for( n = 0; n < nEntryCount; n++ )
989                 if( pPopArtTable[ n ].mnCount )
990                     nLastEntry = n;
991 
992             // rotate palette (one entry)
993             const BitmapColor aFirstCol( pWriteAcc->GetPaletteColor( sal::static_int_cast<sal_uInt16>(pPopArtTable[ 0 ].mnIndex) ) );
994             for( nFirstEntry = 0; nFirstEntry < nLastEntry; nFirstEntry++ )
995             {
996                 pWriteAcc->SetPaletteColor( sal::static_int_cast<sal_uInt16>(pPopArtTable[ nFirstEntry ].mnIndex),
997                                             pWriteAcc->GetPaletteColor( sal::static_int_cast<sal_uInt16>(pPopArtTable[ nFirstEntry + 1 ].mnIndex) ) );
998             }
999             pWriteAcc->SetPaletteColor( sal::static_int_cast<sal_uInt16>(pPopArtTable[ nLastEntry ].mnIndex), aFirstCol );
1000 
1001             // cleanup
1002             delete[] pPopArtTable;
1003             ReleaseAccess( pWriteAcc );
1004             bRet = sal_True;
1005         }
1006     }
1007 
1008     return bRet;
1009 }
1010