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 <math.h>
21 : #include <stdlib.h>
22 :
23 : #include <vcl/bmpacc.hxx>
24 : #include <vcl/bitmapex.hxx>
25 : #include <vcl/bitmap.hxx>
26 : #include <vcl/bitmapscalesuper.hxx>
27 :
28 : #include <boost/scoped_array.hpp>
29 :
30 : #include <impoct.hxx>
31 : #include <impvect.hxx>
32 :
33 : #include "octree.hxx"
34 :
35 : #define RGB15( _def_cR, _def_cG, _def_cB ) (((sal_uLong)(_def_cR)<<10UL)|((sal_uLong)(_def_cG)<<5UL)|(sal_uLong)(_def_cB))
36 : #define GAMMA( _def_cVal, _def_InvGamma ) ((sal_uInt8)MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0L,255L))
37 :
38 : #define CALC_ERRORS \
39 : nTemp = p1T[nX++] >> 12; \
40 : nBErr = MinMax( nTemp, 0, 255 ); \
41 : nBErr = nBErr - FloydIndexMap[ nBC = FloydMap[nBErr] ]; \
42 : nTemp = p1T[nX++] >> 12; \
43 : nGErr = MinMax( nTemp, 0, 255 ); \
44 : nGErr = nGErr - FloydIndexMap[ nGC = FloydMap[nGErr] ]; \
45 : nTemp = p1T[nX] >> 12; \
46 : nRErr = MinMax( nTemp, 0, 255 ); \
47 : nRErr = nRErr - FloydIndexMap[ nRC = FloydMap[nRErr] ];
48 :
49 : #define CALC_TABLES3 \
50 : p2T[nX++] += FloydError3[nBErr]; \
51 : p2T[nX++] += FloydError3[nGErr]; \
52 : p2T[nX++] += FloydError3[nRErr];
53 :
54 : #define CALC_TABLES5 \
55 : p2T[nX++] += FloydError5[nBErr]; \
56 : p2T[nX++] += FloydError5[nGErr]; \
57 : p2T[nX++] += FloydError5[nRErr];
58 :
59 : #define CALC_TABLES7 \
60 : p1T[++nX] += FloydError7[nBErr]; \
61 : p2T[nX++] += FloydError1[nBErr]; \
62 : p1T[nX] += FloydError7[nGErr]; \
63 : p2T[nX++] += FloydError1[nGErr]; \
64 : p1T[nX] += FloydError7[nRErr]; \
65 : p2T[nX] += FloydError1[nRErr];
66 :
67 : const extern sal_uLong nVCLRLut[ 6 ] = { 16, 17, 18, 19, 20, 21 };
68 : const extern sal_uLong nVCLGLut[ 6 ] = { 0, 6, 12, 18, 24, 30 };
69 : const extern sal_uLong nVCLBLut[ 6 ] = { 0, 36, 72, 108, 144, 180 };
70 :
71 : const extern sal_uLong nVCLDitherLut[ 256 ] =
72 : {
73 : 0, 49152, 12288, 61440, 3072, 52224, 15360, 64512, 768, 49920, 13056,
74 : 62208, 3840, 52992, 16128, 65280, 32768, 16384, 45056, 28672, 35840, 19456,
75 : 48128, 31744, 33536, 17152, 45824, 29440, 36608, 20224, 48896, 32512, 8192,
76 : 57344, 4096, 53248, 11264, 60416, 7168, 56320, 8960, 58112, 4864, 54016,
77 : 12032, 61184, 7936, 57088, 40960, 24576, 36864, 20480, 44032, 27648, 39936,
78 : 23552, 41728, 25344, 37632, 21248, 44800, 28416, 40704, 24320, 2048, 51200,
79 : 14336, 63488, 1024, 50176, 13312, 62464, 2816, 51968, 15104, 64256, 1792,
80 : 50944, 14080, 63232, 34816, 18432, 47104, 30720, 33792, 17408, 46080, 29696,
81 : 35584, 19200, 47872, 31488, 34560, 18176, 46848, 30464, 10240, 59392, 6144,
82 : 55296, 9216, 58368, 5120, 54272, 11008, 60160, 6912, 56064, 9984, 59136,
83 : 5888, 55040, 43008, 26624, 38912, 22528, 41984, 25600, 37888, 21504, 43776,
84 : 27392, 39680, 23296, 42752, 26368, 38656, 22272, 512, 49664, 12800, 61952,
85 : 3584, 52736, 15872, 65024, 256, 49408, 12544, 61696, 3328, 52480, 15616,
86 : 64768, 33280, 16896, 45568, 29184, 36352, 19968, 48640, 32256, 33024, 16640,
87 : 45312, 28928, 36096, 19712, 48384, 32000, 8704, 57856, 4608, 53760, 11776,
88 : 60928, 7680, 56832, 8448, 57600, 4352, 53504, 11520, 60672, 7424, 56576,
89 : 41472, 25088, 37376, 20992, 44544, 28160, 40448, 24064, 41216, 24832, 37120,
90 : 20736, 44288, 27904, 40192, 23808, 2560, 51712, 14848, 64000, 1536, 50688,
91 : 13824, 62976, 2304, 51456, 14592, 63744, 1280, 50432, 13568, 62720, 35328,
92 : 18944, 47616, 31232, 34304, 17920, 46592, 30208, 35072, 18688, 47360, 30976,
93 : 34048, 17664, 46336, 29952, 10752, 59904, 6656, 55808, 9728, 58880, 5632,
94 : 54784, 10496, 59648, 6400, 55552, 9472, 58624, 5376, 54528, 43520, 27136,
95 : 39424, 23040, 42496, 26112, 38400, 22016, 43264, 26880, 39168, 22784, 42240,
96 : 25856, 38144, 21760
97 : };
98 :
99 : const extern sal_uLong nVCLLut[ 256 ] =
100 : {
101 : 0, 1286, 2572, 3858, 5144, 6430, 7716, 9002,
102 : 10288, 11574, 12860, 14146, 15432, 16718, 18004, 19290,
103 : 20576, 21862, 23148, 24434, 25720, 27006, 28292, 29578,
104 : 30864, 32150, 33436, 34722, 36008, 37294, 38580, 39866,
105 : 41152, 42438, 43724, 45010, 46296, 47582, 48868, 50154,
106 : 51440, 52726, 54012, 55298, 56584, 57870, 59156, 60442,
107 : 61728, 63014, 64300, 65586, 66872, 68158, 69444, 70730,
108 : 72016, 73302, 74588, 75874, 77160, 78446, 79732, 81018,
109 : 82304, 83590, 84876, 86162, 87448, 88734, 90020, 91306,
110 : 92592, 93878, 95164, 96450, 97736, 99022,100308,101594,
111 : 102880,104166,105452,106738,108024,109310,110596,111882,
112 : 113168,114454,115740,117026,118312,119598,120884,122170,
113 : 123456,124742,126028,127314,128600,129886,131172,132458,
114 : 133744,135030,136316,137602,138888,140174,141460,142746,
115 : 144032,145318,146604,147890,149176,150462,151748,153034,
116 : 154320,155606,156892,158178,159464,160750,162036,163322,
117 : 164608,165894,167180,168466,169752,171038,172324,173610,
118 : 174896,176182,177468,178754,180040,181326,182612,183898,
119 : 185184,186470,187756,189042,190328,191614,192900,194186,
120 : 195472,196758,198044,199330,200616,201902,203188,204474,
121 : 205760,207046,208332,209618,210904,212190,213476,214762,
122 : 216048,217334,218620,219906,221192,222478,223764,225050,
123 : 226336,227622,228908,230194,231480,232766,234052,235338,
124 : 236624,237910,239196,240482,241768,243054,244340,245626,
125 : 246912,248198,249484,250770,252056,253342,254628,255914,
126 : 257200,258486,259772,261058,262344,263630,264916,266202,
127 : 267488,268774,270060,271346,272632,273918,275204,276490,
128 : 277776,279062,280348,281634,282920,284206,285492,286778,
129 : 288064,289350,290636,291922,293208,294494,295780,297066,
130 : 298352,299638,300924,302210,303496,304782,306068,307354,
131 : 308640,309926,311212,312498,313784,315070,316356,317642,
132 : 318928,320214,321500,322786,324072,325358,326644,327930
133 : };
134 :
135 : const long FloydMap[256] =
136 : {
137 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
138 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
139 : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
140 : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
141 : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
142 : 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
143 : 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
144 : 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
145 : 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
146 : 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
147 : 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
148 : 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
149 : 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
150 : 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
151 : 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
152 : 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
153 : };
154 :
155 : const long FloydError1[61] =
156 : {
157 : -7680, -7424, -7168, -6912, -6656, -6400, -6144,
158 : -5888, -5632, -5376, -5120, -4864, -4608, -4352,
159 : -4096, -3840, -3584, -3328, -3072, -2816, -2560,
160 : -2304, -2048, -1792, -1536, -1280, -1024, -768,
161 : -512, -256, 0, 256, 512, 768, 1024, 1280, 1536,
162 : 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
163 : 3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632,
164 : 5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680
165 : };
166 :
167 : const long FloydError3[61] =
168 : {
169 : -23040, -22272, -21504, -20736, -19968, -19200,
170 : -18432, -17664, -16896, -16128, -15360, -14592,
171 : -13824, -13056, -12288, -11520, -10752, -9984,
172 : -9216, -8448, -7680, -6912, -6144, -5376, -4608,
173 : -3840, -3072, -2304, -1536, -768, 0, 768, 1536,
174 : 2304, 3072, 3840, 4608, 5376, 6144, 6912, 7680,
175 : 8448, 9216, 9984, 10752, 11520, 12288, 13056,
176 : 13824, 14592, 15360, 16128, 16896, 17664, 18432,
177 : 19200, 19968, 20736, 21504, 22272, 23040
178 : };
179 :
180 : const long FloydError5[61] =
181 : {
182 : -38400, -37120, -35840, -34560, -33280, -32000,
183 : -30720, -29440, -28160, -26880, -25600, -24320,
184 : -23040, -21760, -20480, -19200, -17920, -16640,
185 : -15360, -14080, -12800, -11520, -10240, -8960,
186 : -7680, -6400, -5120, -3840, -2560, -1280, 0,
187 : 1280, 2560, 3840, 5120, 6400, 7680, 8960, 10240,
188 : 11520, 12800, 14080, 15360, 16640, 17920, 19200,
189 : 20480, 21760, 23040, 24320, 25600, 26880, 28160,
190 : 29440, 30720, 32000, 33280, 34560, 35840, 37120,
191 : 38400
192 : };
193 :
194 : const long FloydError7[61] =
195 : {
196 : -53760, -51968, -50176, -48384, -46592, -44800,
197 : -43008, -41216, -39424, -37632, -35840, -34048,
198 : -32256, -30464, -28672, -26880, -25088, -23296,
199 : -21504, -19712, -17920, -16128, -14336, -12544,
200 : -10752, -8960, -7168, -5376, -3584, -1792, 0,
201 : 1792, 3584, 5376, 7168, 8960, 10752, 12544, 14336,
202 : 16128, 17920, 19712, 21504, 23296, 25088, 26880,
203 : 28672, 30464, 32256, 34048, 35840, 37632, 39424,
204 : 41216, 43008, 44800, 46592, 48384, 50176, 51968,
205 : 53760
206 : };
207 :
208 : const long FloydIndexMap[6] =
209 : {
210 : -30, 21, 72, 123, 174, 225
211 : };
212 :
213 0 : void ImplCreateDitherMatrix( sal_uInt8 (*pDitherMatrix)[16][16] )
214 : {
215 0 : const double fVal = 3.125;
216 0 : const double fVal16 = fVal / 16.;
217 0 : const double fValScale = 254.;
218 : sal_uInt16 pMtx[ 16 ][ 16 ];
219 0 : sal_uInt16 nMax = 0;
220 : static const sal_uInt8 pMagic[4][4] = { { 0, 14, 3, 13, },
221 : {11, 5, 8, 6, },
222 : {12, 2, 15, 1, },
223 : {7, 9, 4, 10 } };
224 :
225 : // Build MagicSquare
226 0 : for ( long i = 0; i < 4; i++ )
227 0 : for ( long j = 0; j < 4; j++ )
228 0 : for ( long k = 0; k < 4; k++ )
229 0 : for ( long l = 0; l < 4; l++ )
230 : {
231 0 : pMtx[ (k<<2) + i][(l<<2 ) + j ] = (sal_uInt16) ( 0.5 + pMagic[i][j]*fVal + pMagic[k][l]*fVal16 );
232 0 : nMax = std::max ( pMtx[ (k<<2) + i][(l<<2 ) + j], nMax );
233 : }
234 :
235 : // Scale to interval [0;254]
236 0 : double tmp = fValScale / nMax;
237 0 : for ( long i = 0; i < 16; i++ )
238 0 : for( long j = 0; j < 16; j++ )
239 0 : (*pDitherMatrix)[i][j] = (sal_uInt8) ( tmp * pMtx[i][j] );
240 0 : }
241 :
242 274750 : bool Bitmap::Convert( BmpConversion eConversion )
243 : {
244 274750 : const sal_uInt16 nBitCount = GetBitCount ();
245 274750 : bool bRet = false;
246 :
247 274750 : switch( eConversion )
248 : {
249 : case( BMP_CONVERSION_1BIT_THRESHOLD ):
250 0 : bRet = ImplMakeMono( 128 );
251 0 : break;
252 :
253 : case( BMP_CONVERSION_1BIT_MATRIX ):
254 0 : bRet = ImplMakeMonoDither();
255 0 : break;
256 :
257 : case( BMP_CONVERSION_4BIT_GREYS ):
258 0 : bRet = ImplMakeGreyscales( 16 );
259 0 : break;
260 :
261 : case( BMP_CONVERSION_4BIT_COLORS ):
262 : {
263 4 : if( nBitCount < 4 )
264 0 : bRet = ImplConvertUp( 4, NULL );
265 4 : else if( nBitCount > 4 )
266 4 : bRet = ImplConvertDown( 4, NULL );
267 : else
268 0 : bRet = true;
269 : }
270 4 : break;
271 :
272 : case( BMP_CONVERSION_4BIT_TRANS ):
273 : {
274 0 : Color aTrans( BMP_COL_TRANS );
275 :
276 0 : if( nBitCount < 4 )
277 0 : bRet = ImplConvertUp( 4, &aTrans );
278 : else
279 0 : bRet = ImplConvertDown( 4, &aTrans );
280 : }
281 0 : break;
282 :
283 : case( BMP_CONVERSION_8BIT_GREYS ):
284 274170 : bRet = ImplMakeGreyscales( 256 );
285 274170 : break;
286 :
287 : case( BMP_CONVERSION_8BIT_COLORS ):
288 : {
289 548 : if( nBitCount < 8 )
290 0 : bRet = ImplConvertUp( 8 );
291 548 : else if( nBitCount > 8 )
292 548 : bRet = ImplConvertDown( 8 );
293 : else
294 0 : bRet = true;
295 : }
296 548 : break;
297 :
298 : case( BMP_CONVERSION_8BIT_TRANS ):
299 : {
300 2 : Color aTrans( BMP_COL_TRANS );
301 :
302 2 : if( nBitCount < 8 )
303 0 : bRet = ImplConvertUp( 8, &aTrans );
304 : else
305 2 : bRet = ImplConvertDown( 8, &aTrans );
306 : }
307 2 : break;
308 :
309 : case( BMP_CONVERSION_24BIT ):
310 : {
311 26 : if( nBitCount < 24 )
312 26 : bRet = ImplConvertUp( 24, NULL );
313 : else
314 0 : bRet = true;
315 : }
316 26 : break;
317 :
318 : case( BMP_CONVERSION_GHOSTED ):
319 0 : bRet = ImplConvertGhosted();
320 0 : break;
321 :
322 : default:
323 : OSL_FAIL( "Bitmap::Convert(): Unsupported conversion" );
324 0 : break;
325 : }
326 :
327 274750 : return bRet;
328 : }
329 :
330 69 : bool Bitmap::ImplMakeMono( sal_uInt8 cThreshold )
331 : {
332 69 : BitmapReadAccess* pReadAcc = AcquireReadAccess();
333 69 : bool bRet = false;
334 :
335 69 : if( pReadAcc )
336 : {
337 69 : Bitmap aNewBmp( GetSizePixel(), 1 );
338 69 : BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
339 :
340 69 : if( pWriteAcc )
341 : {
342 69 : const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
343 138 : const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
344 69 : const long nWidth = pWriteAcc->Width();
345 69 : const long nHeight = pWriteAcc->Height();
346 :
347 69 : if( pReadAcc->HasPalette() )
348 : {
349 3308 : for( long nY = 0L; nY < nHeight; nY++ )
350 : {
351 2880632 : for( long nX = 0L; nX < nWidth; nX++ )
352 : {
353 2877340 : const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX );
354 2877340 : if( pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >=
355 : cThreshold )
356 : {
357 11440 : pWriteAcc->SetPixel( nY, nX, aWhite );
358 : }
359 : else
360 2865900 : pWriteAcc->SetPixel( nY, nX, aBlack );
361 : }
362 : }
363 : }
364 : else
365 : {
366 806 : for( long nY = 0L; nY < nHeight; nY++ )
367 : {
368 20063 : for( long nX = 0L; nX < nWidth; nX++ )
369 : {
370 19310 : if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >=
371 : cThreshold )
372 : {
373 4966 : pWriteAcc->SetPixel( nY, nX, aWhite );
374 : }
375 : else
376 14344 : pWriteAcc->SetPixel( nY, nX, aBlack );
377 : }
378 : }
379 : }
380 :
381 69 : aNewBmp.ReleaseAccess( pWriteAcc );
382 138 : bRet = true;
383 : }
384 :
385 69 : ReleaseAccess( pReadAcc );
386 :
387 69 : if( bRet )
388 : {
389 69 : const MapMode aMap( maPrefMapMode );
390 69 : const Size aSize( maPrefSize );
391 :
392 69 : *this = aNewBmp;
393 :
394 69 : maPrefMapMode = aMap;
395 69 : maPrefSize = aSize;
396 69 : }
397 : }
398 :
399 69 : return bRet;
400 : }
401 :
402 0 : bool Bitmap::ImplMakeMonoDither()
403 : {
404 0 : BitmapReadAccess* pReadAcc = AcquireReadAccess();
405 0 : bool bRet = false;
406 :
407 0 : if( pReadAcc )
408 : {
409 0 : Bitmap aNewBmp( GetSizePixel(), 1 );
410 0 : BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
411 :
412 0 : if( pWriteAcc )
413 : {
414 0 : const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
415 0 : const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
416 0 : const long nWidth = pWriteAcc->Width();
417 0 : const long nHeight = pWriteAcc->Height();
418 : sal_uInt8 pDitherMatrix[ 16 ][ 16 ];
419 :
420 0 : ImplCreateDitherMatrix( &pDitherMatrix );
421 :
422 0 : if( pReadAcc->HasPalette() )
423 : {
424 0 : for( long nY = 0L; nY < nHeight; nY++ )
425 : {
426 0 : for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
427 : {
428 0 : const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX );
429 0 : if( pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >
430 0 : pDitherMatrix[ nModY ][ nX % 16 ] )
431 : {
432 0 : pWriteAcc->SetPixel( nY, nX, aWhite );
433 : }
434 : else
435 0 : pWriteAcc->SetPixel( nY, nX, aBlack );
436 : }
437 : }
438 : }
439 : else
440 : {
441 0 : for( long nY = 0L; nY < nHeight; nY++ )
442 : {
443 0 : for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
444 : {
445 0 : if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >
446 0 : pDitherMatrix[ nModY ][ nX % 16 ] )
447 : {
448 0 : pWriteAcc->SetPixel( nY, nX, aWhite );
449 : }
450 : else
451 0 : pWriteAcc->SetPixel( nY, nX, aBlack );
452 : }
453 : }
454 : }
455 :
456 0 : aNewBmp.ReleaseAccess( pWriteAcc );
457 0 : bRet = true;
458 : }
459 :
460 0 : ReleaseAccess( pReadAcc );
461 :
462 0 : if( bRet )
463 : {
464 0 : const MapMode aMap( maPrefMapMode );
465 0 : const Size aSize( maPrefSize );
466 :
467 0 : *this = aNewBmp;
468 :
469 0 : maPrefMapMode = aMap;
470 0 : maPrefSize = aSize;
471 0 : }
472 : }
473 :
474 0 : return bRet;
475 : }
476 :
477 274170 : bool Bitmap::ImplMakeGreyscales( sal_uInt16 nGreys )
478 : {
479 : DBG_ASSERT( nGreys == 16 || nGreys == 256, "Only 16 or 256 greyscales are supported!" );
480 :
481 274170 : BitmapReadAccess* pReadAcc = AcquireReadAccess();
482 274170 : bool bRet = false;
483 :
484 274170 : if( pReadAcc )
485 : {
486 274170 : const BitmapPalette& rPal = GetGreyPalette( nGreys );
487 274170 : sal_uLong nShift = ( ( nGreys == 16 ) ? 4UL : 0UL );
488 274170 : bool bPalDiffers = !pReadAcc->HasPalette() || ( rPal.GetEntryCount() != pReadAcc->GetPaletteEntryCount() );
489 :
490 274170 : if( !bPalDiffers )
491 265994 : bPalDiffers = ( (BitmapPalette&) rPal != pReadAcc->GetPalette() );
492 :
493 274170 : if( bPalDiffers )
494 : {
495 8176 : Bitmap aNewBmp( GetSizePixel(), ( nGreys == 16 ) ? 4 : 8, &rPal );
496 8176 : BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
497 :
498 8176 : if( pWriteAcc )
499 : {
500 8176 : const long nWidth = pWriteAcc->Width();
501 8176 : const long nHeight = pWriteAcc->Height();
502 :
503 8176 : if( pReadAcc->HasPalette() )
504 : {
505 0 : for( long nY = 0L; nY < nHeight; nY++ )
506 : {
507 0 : for( long nX = 0L; nX < nWidth; nX++ )
508 : {
509 0 : const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX );
510 : pWriteAcc->SetPixelIndex( nY, nX,
511 0 : (pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >> nShift) );
512 : }
513 : }
514 : }
515 16352 : else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR &&
516 8176 : pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
517 : {
518 8176 : nShift += 8;
519 :
520 856859 : for( long nY = 0L; nY < nHeight; nY++ )
521 : {
522 848683 : Scanline pReadScan = pReadAcc->GetScanline( nY );
523 848683 : Scanline pWriteScan = pWriteAcc->GetScanline( nY );
524 :
525 132393650 : for( long nX = 0L; nX < nWidth; nX++ )
526 : {
527 131544967 : const sal_uLong nB = *pReadScan++;
528 131544967 : const sal_uLong nG = *pReadScan++;
529 131544967 : const sal_uLong nR = *pReadScan++;
530 :
531 131544967 : *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
532 : }
533 : }
534 : }
535 0 : else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB &&
536 0 : pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
537 : {
538 0 : nShift += 8;
539 :
540 0 : for( long nY = 0L; nY < nHeight; nY++ )
541 : {
542 0 : Scanline pReadScan = pReadAcc->GetScanline( nY );
543 0 : Scanline pWriteScan = pWriteAcc->GetScanline( nY );
544 :
545 0 : for( long nX = 0L; nX < nWidth; nX++ )
546 : {
547 0 : const sal_uLong nR = *pReadScan++;
548 0 : const sal_uLong nG = *pReadScan++;
549 0 : const sal_uLong nB = *pReadScan++;
550 :
551 0 : *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
552 : }
553 : }
554 : }
555 : else
556 : {
557 0 : for( long nY = 0L; nY < nHeight; nY++ )
558 0 : for( long nX = 0L; nX < nWidth; nX++ )
559 0 : pWriteAcc->SetPixelIndex( nY, nX, (pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift );
560 : }
561 :
562 8176 : aNewBmp.ReleaseAccess( pWriteAcc );
563 8176 : bRet = true;
564 : }
565 :
566 8176 : ReleaseAccess( pReadAcc );
567 :
568 8176 : if( bRet )
569 : {
570 8176 : const MapMode aMap( maPrefMapMode );
571 8176 : const Size aSize( maPrefSize );
572 :
573 8176 : *this = aNewBmp;
574 :
575 8176 : maPrefMapMode = aMap;
576 8176 : maPrefSize = aSize;
577 8176 : }
578 : }
579 : else
580 : {
581 265994 : ReleaseAccess( pReadAcc );
582 265994 : bRet = true;
583 : }
584 : }
585 :
586 274170 : return bRet;
587 : }
588 :
589 26 : bool Bitmap::ImplConvertUp( sal_uInt16 nBitCount, Color* pExtColor )
590 : {
591 : DBG_ASSERT( nBitCount > GetBitCount(), "New BitCount must be greater!" );
592 :
593 26 : BitmapReadAccess* pReadAcc = AcquireReadAccess();
594 26 : bool bRet = false;
595 :
596 26 : if( pReadAcc )
597 : {
598 26 : BitmapPalette aPal;
599 52 : Bitmap aNewBmp( GetSizePixel(), nBitCount, pReadAcc->HasPalette() ? &pReadAcc->GetPalette() : &aPal );
600 26 : BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
601 :
602 26 : if( pWriteAcc )
603 : {
604 26 : const long nWidth = pWriteAcc->Width();
605 26 : const long nHeight = pWriteAcc->Height();
606 :
607 26 : if( pWriteAcc->HasPalette() )
608 : {
609 0 : const sal_uInt16 nOldCount = 1 << GetBitCount();
610 0 : const BitmapPalette& rOldPal = pReadAcc->GetPalette();
611 :
612 0 : aPal.SetEntryCount( 1 << nBitCount );
613 :
614 0 : for( sal_uInt16 i = 0; i < nOldCount; i++ )
615 0 : aPal[ i ] = rOldPal[ i ];
616 :
617 0 : if( pExtColor )
618 0 : aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
619 :
620 0 : pWriteAcc->SetPalette( aPal );
621 :
622 0 : for( long nY = 0L; nY < nHeight; nY++ )
623 0 : for( long nX = 0L; nX < nWidth; nX++ )
624 0 : pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
625 : }
626 : else
627 : {
628 26 : if( pReadAcc->HasPalette() )
629 : {
630 1890 : for( long nY = 0L; nY < nHeight; nY++ )
631 227732 : for( long nX = 0L; nX < nWidth; nX++ )
632 225868 : pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) );
633 : }
634 : else
635 : {
636 0 : for( long nY = 0L; nY < nHeight; nY++ )
637 0 : for( long nX = 0L; nX < nWidth; nX++ )
638 0 : pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
639 : }
640 : }
641 :
642 26 : aNewBmp.ReleaseAccess( pWriteAcc );
643 26 : bRet = true;
644 : }
645 :
646 26 : ReleaseAccess( pReadAcc );
647 :
648 26 : if( bRet )
649 : {
650 26 : const MapMode aMap( maPrefMapMode );
651 26 : const Size aSize( maPrefSize );
652 :
653 26 : *this = aNewBmp;
654 :
655 26 : maPrefMapMode = aMap;
656 26 : maPrefSize = aSize;
657 26 : }
658 : }
659 :
660 26 : return bRet;
661 : }
662 :
663 554 : bool Bitmap::ImplConvertDown( sal_uInt16 nBitCount, Color* pExtColor )
664 : {
665 : DBG_ASSERT( nBitCount <= GetBitCount(), "New BitCount must be lower ( or equal when pExtColor is set )!" );
666 :
667 554 : BitmapReadAccess* pReadAcc = AcquireReadAccess();
668 554 : bool bRet = false;
669 :
670 554 : if( pReadAcc )
671 : {
672 554 : BitmapPalette aPal;
673 1108 : Bitmap aNewBmp( GetSizePixel(), nBitCount, &aPal );
674 554 : BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
675 :
676 554 : if( pWriteAcc )
677 : {
678 554 : const sal_uInt16 nCount = 1 << nBitCount;
679 554 : const long nWidth = pWriteAcc->Width();
680 554 : const long nWidth1 = nWidth - 1L;
681 554 : const long nHeight = pWriteAcc->Height();
682 554 : Octree aOctree( *pReadAcc, pExtColor ? ( nCount - 1 ) : nCount );
683 1108 : InverseColorMap aColorMap( aPal = aOctree.GetPalette() );
684 1108 : BitmapColor aColor;
685 554 : ImpErrorQuad aErrQuad;
686 1108 : boost::scoped_array<ImpErrorQuad> pErrQuad1(new ImpErrorQuad[ nWidth ]);
687 1108 : boost::scoped_array<ImpErrorQuad> pErrQuad2(new ImpErrorQuad[ nWidth ]);
688 554 : ImpErrorQuad* pQLine1 = pErrQuad1.get();
689 554 : ImpErrorQuad* pQLine2 = 0;
690 554 : long nYTmp = 0L;
691 : sal_uInt8 cIndex;
692 554 : bool bQ1 = true;
693 :
694 554 : if( pExtColor )
695 : {
696 2 : aPal.SetEntryCount( aPal.GetEntryCount() + 1 );
697 2 : aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
698 : }
699 :
700 : // set Black/White always, if we have enough space
701 554 : if( aPal.GetEntryCount() < ( nCount - 1 ) )
702 : {
703 417 : aPal.SetEntryCount( aPal.GetEntryCount() + 2 );
704 417 : aPal[ aPal.GetEntryCount() - 2 ] = Color( COL_BLACK );
705 417 : aPal[ aPal.GetEntryCount() - 1 ] = Color( COL_WHITE );
706 : }
707 :
708 554 : pWriteAcc->SetPalette( aPal );
709 :
710 1662 : for( long nY = 0L; nY < std::min( nHeight, 2L ); nY++, nYTmp++ )
711 : {
712 1108 : pQLine2 = !nY ? pErrQuad1.get() : pErrQuad2.get();
713 110676 : for( long nX = 0L; nX < nWidth; nX++ )
714 : {
715 109568 : if( pReadAcc->HasPalette() )
716 64 : pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nYTmp, nX ) );
717 : else
718 109504 : pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
719 : }
720 : }
721 :
722 54841 : for( long nY = 0L; nY < nHeight; nY++, nYTmp++ )
723 : {
724 : // first pixel in the line
725 54287 : cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ 0 ].ImplGetColor() );
726 54287 : pWriteAcc->SetPixelIndex( nY, 0, cIndex );
727 :
728 : long nX;
729 8162077 : for( nX = 1L; nX < nWidth1; nX++ )
730 : {
731 8107790 : cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( aColor = pQLine1[ nX ].ImplGetColor() );
732 8107790 : aErrQuad = ( ImpErrorQuad( aColor ) -= pWriteAcc->GetPaletteColor( cIndex ) );
733 8107790 : pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
734 8107790 : pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
735 8107790 : pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
736 8107790 : pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
737 8107790 : pWriteAcc->SetPixelIndex( nY, nX, cIndex );
738 : }
739 :
740 : // Last RowPixel
741 54287 : if( nX < nWidth )
742 : {
743 54287 : cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ nWidth1 ].ImplGetColor() );
744 54287 : pWriteAcc->SetPixelIndex( nY, nX, cIndex );
745 : }
746 :
747 : // Refill/copy row buffer
748 54287 : pQLine1 = pQLine2;
749 54287 : pQLine2 = ( bQ1 = !bQ1 ) ? pErrQuad2.get() : pErrQuad1.get();
750 :
751 54287 : if( nYTmp < nHeight )
752 : {
753 8159975 : for( nX = 0L; nX < nWidth; nX++ )
754 : {
755 8106796 : if( pReadAcc->HasPalette() )
756 448 : pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nYTmp, nX ) );
757 : else
758 8106348 : pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
759 : }
760 : }
761 : }
762 :
763 554 : aNewBmp.ReleaseAccess( pWriteAcc );
764 1108 : bRet = true;
765 : }
766 :
767 554 : ReleaseAccess( pReadAcc );
768 :
769 554 : if( bRet )
770 : {
771 554 : const MapMode aMap( maPrefMapMode );
772 554 : const Size aSize( maPrefSize );
773 :
774 554 : *this = aNewBmp;
775 :
776 554 : maPrefMapMode = aMap;
777 554 : maPrefSize = aSize;
778 554 : }
779 : }
780 :
781 554 : return bRet;
782 : }
783 :
784 0 : bool Bitmap::ImplConvertGhosted()
785 : {
786 0 : Bitmap aNewBmp;
787 0 : BitmapReadAccess* pR = AcquireReadAccess();
788 0 : bool bRet = false;
789 :
790 0 : if( pR )
791 : {
792 0 : if( pR->HasPalette() )
793 : {
794 0 : BitmapPalette aNewPal( pR->GetPaletteEntryCount() );
795 :
796 0 : for( long i = 0, nCount = aNewPal.GetEntryCount(); i < nCount; i++ )
797 : {
798 0 : const BitmapColor& rOld = pR->GetPaletteColor( (sal_uInt16) i );
799 0 : aNewPal[ (sal_uInt16) i ] = BitmapColor( ( rOld.GetRed() >> 1 ) | 0x80,
800 0 : ( rOld.GetGreen() >> 1 ) | 0x80,
801 0 : ( rOld.GetBlue() >> 1 ) | 0x80 );
802 : }
803 :
804 0 : aNewBmp = Bitmap( GetSizePixel(), GetBitCount(), &aNewPal );
805 0 : BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
806 :
807 0 : if( pW )
808 : {
809 0 : pW->CopyBuffer( *pR );
810 0 : aNewBmp.ReleaseAccess( pW );
811 0 : bRet = true;
812 0 : }
813 : }
814 : else
815 : {
816 0 : aNewBmp = Bitmap( GetSizePixel(), 24 );
817 :
818 0 : BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
819 :
820 0 : if( pW )
821 : {
822 0 : const long nWidth = pR->Width(), nHeight = pR->Height();
823 :
824 0 : for( long nY = 0; nY < nHeight; nY++ )
825 : {
826 0 : for( long nX = 0; nX < nWidth; nX++ )
827 : {
828 0 : const BitmapColor aOld( pR->GetPixel( nY, nX ) );
829 0 : pW->SetPixel( nY, nX, BitmapColor( ( aOld.GetRed() >> 1 ) | 0x80,
830 0 : ( aOld.GetGreen() >> 1 ) | 0x80,
831 0 : ( aOld.GetBlue() >> 1 ) | 0x80 ) );
832 :
833 0 : }
834 : }
835 :
836 0 : aNewBmp.ReleaseAccess( pW );
837 0 : bRet = true;
838 : }
839 : }
840 :
841 0 : ReleaseAccess( pR );
842 : }
843 :
844 0 : if( bRet )
845 : {
846 0 : const MapMode aMap( maPrefMapMode );
847 0 : const Size aSize( maPrefSize );
848 :
849 0 : *this = aNewBmp;
850 :
851 0 : maPrefMapMode = aMap;
852 0 : maPrefSize = aSize;
853 : }
854 :
855 0 : return bRet;
856 : }
857 :
858 6839 : bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag )
859 : {
860 6839 : bool bRetval(false);
861 :
862 6839 : const sal_uInt16 nStartCount(GetBitCount());
863 :
864 6839 : if(basegfx::fTools::equalZero(rScaleX) || basegfx::fTools::equalZero(rScaleY))
865 : {
866 : // no scale
867 0 : bRetval = true;
868 : }
869 :
870 6839 : if(basegfx::fTools::equal(rScaleX, 1.0) && basegfx::fTools::equal(rScaleY, 1.0))
871 : {
872 : // no scale
873 0 : bRetval = true;
874 : }
875 :
876 : //fdo#33455
877 : //
878 : //If we start with a 1 bit image, then after scaling it in any mode except
879 : //BMP_SCALE_FAST we have a a 24bit image which is perfectly correct, but we
880 : //are going to down-shift it to mono again and Bitmap::ImplMakeMono just
881 : //has "Bitmap aNewBmp( GetSizePixel(), 1 );" to create a 1 bit bitmap which
882 : //will default to black/white and the colors mapped to which ever is closer
883 : //to black/white
884 : //
885 : //So the easiest thing to do to retain the colors of 1 bit bitmaps is to
886 : //just use the fast scale rather than attempting to count unique colors in
887 : //the other converters and pass all the info down through
888 : //Bitmap::ImplMakeMono
889 6839 : if (nStartCount == 1 && nScaleFlag != BMP_SCALE_NONE)
890 4 : nScaleFlag = BMP_SCALE_FAST;
891 :
892 6839 : switch(nScaleFlag)
893 : {
894 : case BMP_SCALE_NONE :
895 : {
896 0 : bRetval = false;
897 0 : break;
898 : }
899 : case BMP_SCALE_FAST :
900 : {
901 910 : bRetval = ImplScaleFast( rScaleX, rScaleY );
902 910 : break;
903 : }
904 : case BMP_SCALE_INTERPOLATE :
905 : {
906 86 : bRetval = ImplScaleInterpolate( rScaleX, rScaleY );
907 86 : break;
908 : }
909 : case BMP_SCALE_SUPER:
910 : {
911 4795 : if (GetSizePixel().Width() < 2 || GetSizePixel().Height() < 2)
912 : {
913 : // fallback to ImplScaleFast
914 3440 : bRetval = ImplScaleFast( rScaleX, rScaleY );
915 : }
916 : else
917 : {
918 1355 : BitmapScaleSuper aScaleSuper(rScaleX, rScaleY);
919 1355 : bRetval = aScaleSuper.filter(*this);
920 : }
921 4795 : break;
922 : }
923 : case BMP_SCALE_LANCZOS :
924 : {
925 1042 : const Lanczos3Kernel kernel;
926 :
927 1042 : bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel );
928 1042 : break;
929 : }
930 : case BMP_SCALE_BICUBIC :
931 : {
932 2 : const BicubicKernel kernel;
933 :
934 2 : bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel );
935 2 : break;
936 : }
937 : case BMP_SCALE_BILINEAR :
938 : {
939 2 : const BilinearKernel kernel;
940 :
941 2 : bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel );
942 2 : break;
943 : }
944 : case BMP_SCALE_BOX :
945 : {
946 2 : const BoxKernel kernel;
947 :
948 2 : bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel );
949 2 : break;
950 : }
951 : }
952 :
953 : OSL_ENSURE(!bRetval || nStartCount == GetBitCount(), "Bitmap::Scale has changed the ColorDepth, this should *not* happen (!)");
954 6839 : return bRetval;
955 : }
956 :
957 1223 : bool Bitmap::Scale( const Size& rNewSize, sal_uInt32 nScaleFlag )
958 : {
959 1223 : const Size aSize( GetSizePixel() );
960 : bool bRet;
961 :
962 1223 : if( aSize.Width() && aSize.Height() )
963 : {
964 1223 : bRet = Scale( (double) rNewSize.Width() / aSize.Width(),
965 1223 : (double) rNewSize.Height() / aSize.Height(),
966 2446 : nScaleFlag );
967 : }
968 : else
969 0 : bRet = true;
970 :
971 1223 : return bRet;
972 : }
973 :
974 1423 : void Bitmap::AdaptBitCount(Bitmap& rNew) const
975 : {
976 1423 : ImplAdaptBitCount(rNew);
977 1423 : }
978 :
979 2557 : void Bitmap::ImplAdaptBitCount(Bitmap& rNew) const
980 : {
981 : // aNew is the result of some operation; adapt it's BitCount to the original (this)
982 2557 : if(GetBitCount() != rNew.GetBitCount())
983 : {
984 557 : switch(GetBitCount())
985 : {
986 : case 1:
987 : {
988 0 : rNew.Convert(BMP_CONVERSION_1BIT_THRESHOLD);
989 0 : break;
990 : }
991 : case 4:
992 : {
993 4 : if(HasGreyPalette())
994 : {
995 0 : rNew.Convert(BMP_CONVERSION_4BIT_GREYS);
996 : }
997 : else
998 : {
999 4 : rNew.Convert(BMP_CONVERSION_4BIT_COLORS);
1000 : }
1001 4 : break;
1002 : }
1003 : case 8:
1004 : {
1005 553 : if(HasGreyPalette())
1006 : {
1007 541 : rNew.Convert(BMP_CONVERSION_8BIT_GREYS);
1008 : }
1009 : else
1010 : {
1011 12 : rNew.Convert(BMP_CONVERSION_8BIT_COLORS);
1012 : }
1013 553 : break;
1014 : }
1015 : case 24:
1016 : {
1017 0 : rNew.Convert(BMP_CONVERSION_24BIT);
1018 0 : break;
1019 : }
1020 : default:
1021 : {
1022 : OSL_ENSURE(false, "BitDepth adaption failed (!)");
1023 0 : break;
1024 : }
1025 : }
1026 : }
1027 2557 : }
1028 :
1029 4350 : bool Bitmap::ImplScaleFast( const double& rScaleX, const double& rScaleY )
1030 : {
1031 4350 : const Size aSizePix( GetSizePixel() );
1032 4350 : const long nNewWidth = FRound( aSizePix.Width() * rScaleX );
1033 4350 : const long nNewHeight = FRound( aSizePix.Height() * rScaleY );
1034 4350 : bool bRet = false;
1035 :
1036 4350 : if( nNewWidth && nNewHeight )
1037 : {
1038 4350 : BitmapReadAccess* pReadAcc = AcquireReadAccess();
1039 :
1040 4350 : if(pReadAcc)
1041 : {
1042 4350 : Bitmap aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() );
1043 4350 : BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1044 :
1045 4350 : if( pWriteAcc )
1046 : {
1047 4350 : const long nScanlineSize = pWriteAcc->GetScanlineSize();
1048 4350 : const long nNewWidth1 = nNewWidth - 1L;
1049 4350 : const long nNewHeight1 = nNewHeight - 1L;
1050 4350 : const long nWidth = pReadAcc->Width();
1051 4350 : const long nHeight = pReadAcc->Height();
1052 4350 : boost::scoped_array<long> pLutX(new long[ nNewWidth ]);
1053 8700 : boost::scoped_array<long> pLutY(new long[ nNewHeight ]);
1054 :
1055 4350 : if( nNewWidth1 && nNewHeight1 )
1056 : {
1057 637014 : for( long nX = 0L; nX < nNewWidth; nX++ )
1058 632664 : pLutX[ nX ] = nX * nWidth / nNewWidth;
1059 :
1060 828548 : for( long nY = 0L; nY < nNewHeight; nY++ )
1061 824198 : pLutY[ nY ] = nY * nHeight / nNewHeight;
1062 :
1063 4350 : long nActY = 0L;
1064 240426 : while( nActY < nNewHeight )
1065 : {
1066 231726 : long nMapY = pLutY[ nActY ];
1067 :
1068 6955470 : for( long nX = 0L; nX < nNewWidth; nX++ )
1069 6723744 : pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) );
1070 :
1071 1055924 : while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) )
1072 : {
1073 592472 : memcpy( pWriteAcc->GetScanline( nActY + 1L ),
1074 1184944 : pWriteAcc->GetScanline( nActY ), nScanlineSize );
1075 592472 : nActY++;
1076 : }
1077 231726 : nActY++;
1078 : }
1079 :
1080 4350 : bRet = true;
1081 4350 : aNewBmp.ReleaseAccess( pWriteAcc );
1082 4350 : }
1083 : }
1084 4350 : ReleaseAccess( pReadAcc );
1085 :
1086 4350 : if( bRet )
1087 4350 : ImplAssignWithSize( aNewBmp );
1088 : }
1089 : }
1090 :
1091 4350 : return bRet;
1092 : }
1093 :
1094 86 : bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY )
1095 : {
1096 86 : const Size aSizePix( GetSizePixel() );
1097 86 : const long nNewWidth = FRound( aSizePix.Width() * rScaleX );
1098 86 : const long nNewHeight = FRound( aSizePix.Height() * rScaleY );
1099 86 : bool bRet = false;
1100 :
1101 86 : if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) )
1102 : {
1103 86 : BitmapReadAccess* pReadAcc = AcquireReadAccess();
1104 86 : if( pReadAcc )
1105 : {
1106 86 : long nWidth = pReadAcc->Width();
1107 86 : long nHeight = pReadAcc->Height();
1108 86 : Bitmap aNewBmp( Size( nNewWidth, nHeight ), 24 );
1109 86 : BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1110 :
1111 86 : if( pWriteAcc )
1112 : {
1113 86 : const long nNewWidth1 = nNewWidth - 1L;
1114 86 : const long nWidth1 = pReadAcc->Width() - 1L;
1115 86 : const double fRevScaleX = (double) nWidth1 / nNewWidth1;
1116 :
1117 86 : boost::scoped_array<long> pLutInt(new long[ nNewWidth ]);
1118 172 : boost::scoped_array<long> pLutFrac(new long[ nNewWidth ]);
1119 :
1120 1170 : for( long nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ )
1121 : {
1122 1084 : double fTemp = nX * fRevScaleX;
1123 1084 : pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp );
1124 1084 : fTemp -= pLutInt[ nX ];
1125 1084 : pLutFrac[ nX ] = (long) ( fTemp * 1024. );
1126 : }
1127 :
1128 1576 : for( long nY = 0L; nY < nHeight; nY++ )
1129 : {
1130 1490 : if( 1 == nWidth )
1131 : {
1132 0 : BitmapColor aCol0;
1133 0 : if( pReadAcc->HasPalette() )
1134 : {
1135 0 : aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, 0 ) );
1136 : }
1137 : else
1138 : {
1139 0 : aCol0 = pReadAcc->GetPixel( nY, 0 );
1140 : }
1141 :
1142 0 : for( long nX = 0L; nX < nNewWidth; nX++ )
1143 : {
1144 0 : pWriteAcc->SetPixel( nY, nX, aCol0 );
1145 0 : }
1146 : }
1147 : else
1148 : {
1149 74322 : for( long nX = 0L; nX < nNewWidth; nX++ )
1150 : {
1151 72832 : long nTemp = pLutInt[ nX ];
1152 :
1153 145664 : BitmapColor aCol0, aCol1;
1154 72832 : if( pReadAcc->HasPalette() )
1155 : {
1156 0 : aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp++ ) );
1157 0 : aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp ) );
1158 : }
1159 : else
1160 : {
1161 72832 : aCol0 = pReadAcc->GetPixel( nY, nTemp++ );
1162 72832 : aCol1 = pReadAcc->GetPixel( nY, nTemp );
1163 : }
1164 :
1165 72832 : nTemp = pLutFrac[ nX ];
1166 :
1167 72832 : long lXR0 = aCol0.GetRed();
1168 72832 : long lXG0 = aCol0.GetGreen();
1169 72832 : long lXB0 = aCol0.GetBlue();
1170 72832 : long lXR1 = aCol1.GetRed() - lXR0;
1171 72832 : long lXG1 = aCol1.GetGreen() - lXG0;
1172 72832 : long lXB1 = aCol1.GetBlue() - lXB0;
1173 :
1174 72832 : aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1175 72832 : aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1176 72832 : aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1177 :
1178 72832 : pWriteAcc->SetPixel( nY, nX, aCol0 );
1179 72832 : }
1180 : }
1181 : }
1182 :
1183 172 : bRet = true;
1184 : }
1185 :
1186 86 : ReleaseAccess( pReadAcc );
1187 86 : aNewBmp.ReleaseAccess( pWriteAcc );
1188 :
1189 86 : if( bRet )
1190 : {
1191 86 : bRet = false;
1192 86 : const Bitmap aOriginal(*this);
1193 86 : *this = aNewBmp;
1194 86 : aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 );
1195 86 : pReadAcc = AcquireReadAccess();
1196 86 : pWriteAcc = aNewBmp.AcquireWriteAccess();
1197 :
1198 86 : if( pReadAcc && pWriteAcc )
1199 : {
1200 86 : const long nNewHeight1 = nNewHeight - 1L;
1201 86 : const long nHeight1 = pReadAcc->Height() - 1L;
1202 86 : const double fRevScaleY = (double) nHeight1 / nNewHeight1;
1203 :
1204 86 : boost::scoped_array<long> pLutInt(new long[ nNewHeight ]);
1205 172 : boost::scoped_array<long> pLutFrac(new long[ nNewHeight ]);
1206 :
1207 1252 : for( long nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ )
1208 : {
1209 1166 : double fTemp = nY * fRevScaleY;
1210 1166 : pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp );
1211 1166 : fTemp -= pLutInt[ nY ];
1212 1166 : pLutFrac[ nY ] = (long) ( fTemp * 1024. );
1213 : }
1214 :
1215 : // after 1st step, bitmap *is* 24bit format (see above)
1216 : OSL_ENSURE(!pReadAcc->HasPalette(), "OOps, somehow ImplScaleInterpolate in-between format has palette, should not happen (!)");
1217 :
1218 1170 : for( long nX = 0L; nX < nNewWidth; nX++ )
1219 : {
1220 1084 : if( 1 == nHeight )
1221 : {
1222 0 : BitmapColor aCol0 = pReadAcc->GetPixel( 0, nX );
1223 :
1224 0 : for( long nY = 0L; nY < nNewHeight; nY++ )
1225 : {
1226 0 : pWriteAcc->SetPixel( nY, nX, aCol0 );
1227 0 : }
1228 : }
1229 : else
1230 : {
1231 24812 : for( long nY = 0L; nY < nNewHeight; nY++ )
1232 : {
1233 23728 : long nTemp = pLutInt[ nY ];
1234 :
1235 23728 : BitmapColor aCol0 = pReadAcc->GetPixel( nTemp++, nX );
1236 47456 : BitmapColor aCol1 = pReadAcc->GetPixel( nTemp, nX );
1237 :
1238 23728 : nTemp = pLutFrac[ nY ];
1239 :
1240 23728 : long lXR0 = aCol0.GetRed();
1241 23728 : long lXG0 = aCol0.GetGreen();
1242 23728 : long lXB0 = aCol0.GetBlue();
1243 23728 : long lXR1 = aCol1.GetRed() - lXR0;
1244 23728 : long lXG1 = aCol1.GetGreen() - lXG0;
1245 23728 : long lXB1 = aCol1.GetBlue() - lXB0;
1246 :
1247 23728 : aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1248 23728 : aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1249 23728 : aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1250 :
1251 23728 : pWriteAcc->SetPixel( nY, nX, aCol0 );
1252 23728 : }
1253 : }
1254 : }
1255 :
1256 172 : bRet = true;
1257 : }
1258 :
1259 86 : ReleaseAccess( pReadAcc );
1260 86 : aNewBmp.ReleaseAccess( pWriteAcc );
1261 :
1262 86 : if( bRet )
1263 : {
1264 86 : aOriginal.ImplAdaptBitCount(aNewBmp);
1265 86 : *this = aNewBmp;
1266 86 : }
1267 86 : }
1268 : }
1269 : }
1270 :
1271 86 : if( !bRet )
1272 : {
1273 0 : bRet = ImplScaleFast( rScaleX, rScaleY );
1274 : }
1275 :
1276 86 : return bRet;
1277 : }
1278 :
1279 : namespace
1280 : {
1281 1990 : void ImplCalculateContributions(
1282 : const sal_uInt32 aSourceSize,
1283 : const sal_uInt32 aDestinationSize,
1284 : sal_uInt32& aNumberOfContributions,
1285 : double*& pWeights,
1286 : sal_uInt32*& pPixels,
1287 : sal_uInt32*& pCount,
1288 : const Kernel& aKernel)
1289 : {
1290 1990 : const double fSamplingRadius(aKernel.GetWidth());
1291 1990 : const double fScale(aDestinationSize / static_cast< double >(aSourceSize));
1292 1990 : const double fScaledRadius((fScale < 1.0) ? fSamplingRadius / fScale : fSamplingRadius);
1293 1990 : const double fFilterFactor((fScale < 1.0) ? fScale : 1.0);
1294 :
1295 1990 : aNumberOfContributions = (static_cast< sal_uInt32 >(fabs(ceil(fScaledRadius))) * 2) + 1;
1296 1990 : const sal_uInt32 nAllocSize(aDestinationSize * aNumberOfContributions);
1297 1990 : pWeights = new double[nAllocSize];
1298 1990 : pPixels = new sal_uInt32[nAllocSize];
1299 1990 : pCount = new sal_uInt32[aDestinationSize];
1300 :
1301 185708 : for(sal_uInt32 i(0); i < aDestinationSize; i++)
1302 : {
1303 183718 : const sal_uInt32 aIndex(i * aNumberOfContributions);
1304 183718 : const double aCenter(i / fScale);
1305 183718 : const sal_Int32 aLeft(static_cast< sal_Int32 >(floor(aCenter - fScaledRadius)));
1306 183718 : const sal_Int32 aRight(static_cast< sal_Int32 >(ceil(aCenter + fScaledRadius)));
1307 183718 : sal_uInt32 aCurrentCount(0);
1308 :
1309 4037538 : for(sal_Int32 j(aLeft); j <= aRight; j++)
1310 : {
1311 3853820 : const double aWeight(aKernel.Calculate(fFilterFactor * (aCenter - static_cast< double>(j))));
1312 :
1313 : // Reduce calculations with ignoring weights of 0.0
1314 3853820 : if(fabs(aWeight) < 0.0001)
1315 : {
1316 450318 : continue;
1317 : }
1318 :
1319 : // Handling on edges
1320 3403502 : const sal_uInt32 aPixelIndex(MinMax(j, 0, aSourceSize - 1));
1321 3403502 : const sal_uInt32 nIndex(aIndex + aCurrentCount);
1322 :
1323 3403502 : pWeights[nIndex] = aWeight;
1324 3403502 : pPixels[nIndex] = aPixelIndex;
1325 :
1326 3403502 : aCurrentCount++;
1327 : }
1328 :
1329 183718 : pCount[i] = aCurrentCount;
1330 : }
1331 1990 : }
1332 :
1333 1016 : bool ImplScaleConvolutionHor(
1334 : Bitmap& rSource,
1335 : Bitmap& rTarget,
1336 : const double& rScaleX,
1337 : const Kernel& aKernel)
1338 : {
1339 : // Do horizontal filtering
1340 : OSL_ENSURE(rScaleX > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
1341 1016 : const sal_uInt32 nWidth(rSource.GetSizePixel().Width());
1342 1016 : const sal_uInt32 nNewWidth(FRound(nWidth * rScaleX));
1343 :
1344 1016 : if(nWidth == nNewWidth)
1345 : {
1346 0 : return true;
1347 : }
1348 :
1349 1016 : BitmapReadAccess* pReadAcc = rSource.AcquireReadAccess();
1350 :
1351 1016 : if(pReadAcc)
1352 : {
1353 1016 : double* pWeights = 0;
1354 1016 : sal_uInt32* pPixels = 0;
1355 1016 : sal_uInt32* pCount = 0;
1356 1016 : sal_uInt32 aNumberOfContributions(0);
1357 :
1358 1016 : const sal_uInt32 nHeight(rSource.GetSizePixel().Height());
1359 1016 : ImplCalculateContributions(nWidth, nNewWidth, aNumberOfContributions, pWeights, pPixels, pCount, aKernel);
1360 1016 : rTarget = Bitmap(Size(nNewWidth, nHeight), 24);
1361 1016 : BitmapWriteAccess* pWriteAcc = rTarget.AcquireWriteAccess();
1362 1016 : bool bResult(0 != pWriteAcc);
1363 :
1364 1016 : if(bResult)
1365 : {
1366 166482 : for(sal_uInt32 y(0); y < nHeight; y++)
1367 : {
1368 19829296 : for(sal_uInt32 x(0); x < nNewWidth; x++)
1369 : {
1370 19663830 : const sal_uInt32 aBaseIndex(x * aNumberOfContributions);
1371 19663830 : double aSum(0.0);
1372 19663830 : double aValueRed(0.0);
1373 19663830 : double aValueGreen(0.0);
1374 19663830 : double aValueBlue(0.0);
1375 :
1376 349712236 : for(sal_uInt32 j(0); j < pCount[x]; j++)
1377 : {
1378 330048406 : const sal_uInt32 aIndex(aBaseIndex + j);
1379 330048406 : const double aWeight(pWeights[aIndex]);
1380 330048406 : BitmapColor aColor;
1381 :
1382 330048406 : aSum += aWeight;
1383 :
1384 330048406 : if(pReadAcc->HasPalette())
1385 : {
1386 113832237 : aColor = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(y, pPixels[aIndex]));
1387 : }
1388 : else
1389 : {
1390 216216169 : aColor = pReadAcc->GetPixel(y, pPixels[aIndex]);
1391 : }
1392 :
1393 330048406 : aValueRed += aWeight * aColor.GetRed();
1394 330048406 : aValueGreen += aWeight * aColor.GetGreen();
1395 330048406 : aValueBlue += aWeight * aColor.GetBlue();
1396 330048406 : }
1397 :
1398 : const BitmapColor aResultColor(
1399 19663830 : static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)),
1400 19663830 : static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)),
1401 58991490 : static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255)));
1402 :
1403 19663830 : pWriteAcc->SetPixel(y, x, aResultColor);
1404 19663830 : }
1405 : }
1406 :
1407 1016 : rTarget.ReleaseAccess(pWriteAcc);
1408 : }
1409 :
1410 1016 : rSource.ReleaseAccess(pReadAcc);
1411 1016 : delete[] pWeights;
1412 1016 : delete[] pCount;
1413 1016 : delete[] pPixels;
1414 :
1415 1016 : if(bResult)
1416 : {
1417 1016 : return true;
1418 : }
1419 : }
1420 :
1421 0 : return false;
1422 : }
1423 :
1424 974 : bool ImplScaleConvolutionVer(
1425 : Bitmap& rSource,
1426 : Bitmap& rTarget,
1427 : const double& rScaleY,
1428 : const Kernel& aKernel)
1429 : {
1430 : // Do vertical filtering
1431 : OSL_ENSURE(rScaleY > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
1432 974 : const sal_uInt32 nHeight(rSource.GetSizePixel().Height());
1433 974 : const sal_uInt32 nNewHeight(FRound(nHeight * rScaleY));
1434 :
1435 974 : if(nHeight == nNewHeight)
1436 : {
1437 0 : return true;
1438 : }
1439 :
1440 974 : BitmapReadAccess* pReadAcc = rSource.AcquireReadAccess();
1441 :
1442 974 : if(pReadAcc)
1443 : {
1444 974 : double* pWeights = 0;
1445 974 : sal_uInt32* pPixels = 0;
1446 974 : sal_uInt32* pCount = 0;
1447 974 : sal_uInt32 aNumberOfContributions(0);
1448 :
1449 974 : const sal_uInt32 nWidth(rSource.GetSizePixel().Width());
1450 974 : ImplCalculateContributions(nHeight, nNewHeight, aNumberOfContributions, pWeights, pPixels, pCount, aKernel);
1451 974 : rTarget = Bitmap(Size(nWidth, nNewHeight), 24);
1452 974 : BitmapWriteAccess* pWriteAcc = rTarget.AcquireWriteAccess();
1453 974 : bool bResult(0 != pWriteAcc);
1454 :
1455 974 : if(pWriteAcc)
1456 : {
1457 238242 : for(sal_uInt32 x(0); x < nWidth; x++)
1458 : {
1459 17626266 : for(sal_uInt32 y(0); y < nNewHeight; y++)
1460 : {
1461 17388998 : const sal_uInt32 aBaseIndex(y * aNumberOfContributions);
1462 17388998 : double aSum(0.0);
1463 17388998 : double aValueRed(0.0);
1464 17388998 : double aValueGreen(0.0);
1465 17388998 : double aValueBlue(0.0);
1466 :
1467 499897944 : for(sal_uInt32 j(0); j < pCount[y]; j++)
1468 : {
1469 482508946 : const sal_uInt32 aIndex(aBaseIndex + j);
1470 482508946 : const double aWeight(pWeights[aIndex]);
1471 482508946 : BitmapColor aColor;
1472 :
1473 482508946 : aSum += aWeight;
1474 :
1475 482508946 : if(pReadAcc->HasPalette())
1476 : {
1477 220089093 : aColor = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(pPixels[aIndex], x));
1478 : }
1479 : else
1480 : {
1481 262419853 : aColor = pReadAcc->GetPixel(pPixels[aIndex], x);
1482 : }
1483 :
1484 482508946 : aValueRed += aWeight * aColor.GetRed();
1485 482508946 : aValueGreen += aWeight * aColor.GetGreen();
1486 482508946 : aValueBlue += aWeight * aColor.GetBlue();
1487 482508946 : }
1488 :
1489 : const BitmapColor aResultColor(
1490 17388998 : static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)),
1491 17388998 : static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)),
1492 52166994 : static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255)));
1493 :
1494 17388998 : if(pWriteAcc->HasPalette())
1495 : {
1496 0 : pWriteAcc->SetPixelIndex(y, x, static_cast< sal_uInt8 >(pWriteAcc->GetBestPaletteIndex(aResultColor)));
1497 : }
1498 : else
1499 : {
1500 17388998 : pWriteAcc->SetPixel(y, x, aResultColor);
1501 : }
1502 17388998 : }
1503 : }
1504 : }
1505 :
1506 974 : rTarget.ReleaseAccess(pWriteAcc);
1507 974 : rSource.ReleaseAccess(pReadAcc);
1508 :
1509 974 : delete[] pWeights;
1510 974 : delete[] pCount;
1511 974 : delete[] pPixels;
1512 :
1513 974 : if(bResult)
1514 : {
1515 974 : return true;
1516 : }
1517 : }
1518 :
1519 0 : return false;
1520 : }
1521 : }
1522 :
1523 : // #i121233# Added BMP_SCALE_LANCZOS, BMP_SCALE_BICUBIC, BMP_SCALE_BILINEAR and
1524 : // BMP_SCALE_BOX derived from the original commit from Tomas Vajngerl (see
1525 : // bugzilla task for deitails) Thanks!
1526 1048 : bool Bitmap::ImplScaleConvolution(
1527 : const double& rScaleX,
1528 : const double& rScaleY,
1529 : const Kernel& aKernel)
1530 : {
1531 1048 : const bool bMirrorHor(rScaleX < 0.0);
1532 1048 : const bool bMirrorVer(rScaleY < 0.0);
1533 1048 : const double fScaleX(bMirrorHor ? -rScaleX : rScaleX);
1534 1048 : const double fScaleY(bMirrorVer ? -rScaleY : rScaleY);
1535 1048 : const sal_uInt32 nWidth(GetSizePixel().Width());
1536 1048 : const sal_uInt32 nHeight(GetSizePixel().Height());
1537 1048 : const sal_uInt32 nNewWidth(FRound(nWidth * fScaleX));
1538 1048 : const sal_uInt32 nNewHeight(FRound(nHeight * fScaleY));
1539 1048 : const bool bScaleHor(nWidth != nNewWidth);
1540 1048 : const bool bScaleVer(nHeight != nNewHeight);
1541 1048 : const bool bMirror(bMirrorHor || bMirrorVer);
1542 :
1543 1048 : if(!bMirror && !bScaleHor && !bScaleVer)
1544 : {
1545 0 : return true;
1546 : }
1547 :
1548 1048 : bool bResult(true);
1549 1048 : sal_uInt32 nMirrorFlags(BMP_MIRROR_NONE);
1550 1048 : bool bMirrorAfter(false);
1551 :
1552 1048 : if(bMirror)
1553 : {
1554 0 : if(bMirrorHor)
1555 : {
1556 0 : nMirrorFlags |= BMP_MIRROR_HORZ;
1557 : }
1558 :
1559 0 : if(bMirrorVer)
1560 : {
1561 0 : nMirrorFlags |= BMP_MIRROR_VERT;
1562 : }
1563 :
1564 0 : const sal_uInt32 nStartSize(nWidth * nHeight);
1565 0 : const sal_uInt32 nEndSize(nNewWidth * nNewHeight);
1566 :
1567 0 : bMirrorAfter = nStartSize > nEndSize;
1568 :
1569 0 : if(!bMirrorAfter)
1570 : {
1571 0 : bResult = Mirror(nMirrorFlags);
1572 : }
1573 : }
1574 :
1575 1048 : Bitmap aResult;
1576 :
1577 1048 : if(bResult)
1578 : {
1579 1048 : const sal_uInt32 nInBetweenSizeHorFirst(nHeight * nNewWidth);
1580 1048 : const sal_uInt32 nInBetweenSizeVerFirst(nNewHeight * nWidth);
1581 1048 : Bitmap aSource(*this);
1582 :
1583 1048 : if(nInBetweenSizeHorFirst < nInBetweenSizeVerFirst)
1584 : {
1585 322 : if(bScaleHor)
1586 : {
1587 322 : bResult = ImplScaleConvolutionHor(aSource, aResult, fScaleX, aKernel);
1588 : }
1589 :
1590 322 : if(bResult && bScaleVer)
1591 : {
1592 248 : if(bScaleHor)
1593 : {
1594 : // copy partial result, independent of color depth
1595 248 : aSource = aResult;
1596 : }
1597 :
1598 248 : bResult = ImplScaleConvolutionVer(aSource, aResult, fScaleY, aKernel);
1599 : }
1600 : }
1601 : else
1602 : {
1603 726 : if(bScaleVer)
1604 : {
1605 726 : bResult = ImplScaleConvolutionVer(aSource, aResult, fScaleY, aKernel);
1606 : }
1607 :
1608 726 : if(bResult && bScaleHor)
1609 : {
1610 694 : if(bScaleVer)
1611 : {
1612 : // copy partial result, independent of color depth
1613 694 : aSource = aResult;
1614 : }
1615 :
1616 694 : bResult = ImplScaleConvolutionHor(aSource, aResult, fScaleX, aKernel);
1617 : }
1618 1048 : }
1619 : }
1620 :
1621 1048 : if(bResult && bMirrorAfter)
1622 : {
1623 0 : bResult = aResult.Mirror(nMirrorFlags);
1624 : }
1625 :
1626 1048 : if(bResult)
1627 : {
1628 1048 : ImplAdaptBitCount(aResult);
1629 1048 : *this = aResult;
1630 : }
1631 :
1632 1048 : return bResult;
1633 : }
1634 :
1635 0 : bool Bitmap::Dither( sal_uLong nDitherFlags )
1636 : {
1637 0 : bool bRet = false;
1638 :
1639 0 : const Size aSizePix( GetSizePixel() );
1640 :
1641 0 : if( aSizePix.Width() == 1 || aSizePix.Height() == 1 )
1642 0 : bRet = true;
1643 0 : else if( nDitherFlags & BMP_DITHER_MATRIX )
1644 0 : bRet = ImplDitherMatrix();
1645 0 : else if( nDitherFlags & BMP_DITHER_FLOYD )
1646 0 : bRet = ImplDitherFloyd();
1647 0 : else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) )
1648 0 : bRet = ImplDitherFloyd16();
1649 :
1650 0 : return bRet;
1651 : }
1652 :
1653 0 : bool Bitmap::ImplDitherMatrix()
1654 : {
1655 0 : BitmapReadAccess* pReadAcc = AcquireReadAccess();
1656 0 : Bitmap aNewBmp( GetSizePixel(), 8 );
1657 0 : BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1658 0 : bool bRet = false;
1659 :
1660 0 : if( pReadAcc && pWriteAcc )
1661 : {
1662 0 : const sal_uLong nWidth = pReadAcc->Width();
1663 0 : const sal_uLong nHeight = pReadAcc->Height();
1664 0 : BitmapColor aIndex( (sal_uInt8) 0 );
1665 :
1666 0 : if( pReadAcc->HasPalette() )
1667 : {
1668 0 : for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
1669 : {
1670 0 : for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
1671 : {
1672 0 : const BitmapColor aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) );
1673 0 : const sal_uLong nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
1674 0 : const sal_uLong nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
1675 0 : const sal_uLong nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
1676 0 : const sal_uLong nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
1677 :
1678 0 : aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
1679 0 : pWriteAcc->SetPixel( nY, nX, aIndex );
1680 0 : }
1681 : }
1682 : }
1683 : else
1684 : {
1685 0 : for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
1686 : {
1687 0 : for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
1688 : {
1689 0 : const BitmapColor aCol( pReadAcc->GetPixel( nY, nX ) );
1690 0 : const sal_uLong nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
1691 0 : const sal_uLong nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
1692 0 : const sal_uLong nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
1693 0 : const sal_uLong nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
1694 :
1695 0 : aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
1696 0 : pWriteAcc->SetPixel( nY, nX, aIndex );
1697 0 : }
1698 : }
1699 : }
1700 :
1701 0 : bRet = true;
1702 : }
1703 :
1704 0 : ReleaseAccess( pReadAcc );
1705 0 : aNewBmp.ReleaseAccess( pWriteAcc );
1706 :
1707 0 : if( bRet )
1708 : {
1709 0 : const MapMode aMap( maPrefMapMode );
1710 0 : const Size aSize( maPrefSize );
1711 :
1712 0 : *this = aNewBmp;
1713 :
1714 0 : maPrefMapMode = aMap;
1715 0 : maPrefSize = aSize;
1716 : }
1717 :
1718 0 : return bRet;
1719 : }
1720 :
1721 0 : bool Bitmap::ImplDitherFloyd()
1722 : {
1723 0 : const Size aSize( GetSizePixel() );
1724 0 : bool bRet = false;
1725 :
1726 0 : if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) )
1727 : {
1728 0 : BitmapReadAccess* pReadAcc = AcquireReadAccess();
1729 0 : Bitmap aNewBmp( GetSizePixel(), 8 );
1730 0 : BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1731 :
1732 0 : if( pReadAcc && pWriteAcc )
1733 : {
1734 0 : BitmapColor aColor;
1735 0 : long nWidth = pReadAcc->Width();
1736 0 : long nWidth1 = nWidth - 1L;
1737 0 : long nHeight = pReadAcc->Height();
1738 : long nX;
1739 0 : long nW = nWidth * 3L;
1740 0 : long nW2 = nW - 3L;
1741 : long nRErr, nGErr, nBErr;
1742 : long nRC, nGC, nBC;
1743 0 : boost::scoped_array<long> p1(new long[ nW ]);
1744 0 : boost::scoped_array<long> p2(new long[ nW ]);
1745 0 : long* p1T = p1.get();
1746 0 : long* p2T = p2.get();
1747 : long* pTmp;
1748 0 : bool bPal = pReadAcc->HasPalette();
1749 :
1750 0 : pTmp = p2T;
1751 :
1752 0 : if( bPal )
1753 : {
1754 0 : for( long nZ = 0; nZ < nWidth; nZ++ )
1755 : {
1756 0 : aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( 0, nZ ) );
1757 :
1758 0 : *pTmp++ = (long) aColor.GetBlue() << 12;
1759 0 : *pTmp++ = (long) aColor.GetGreen() << 12;
1760 0 : *pTmp++ = (long) aColor.GetRed() << 12;
1761 : }
1762 : }
1763 : else
1764 : {
1765 0 : for( long nZ = 0; nZ < nWidth; nZ++ )
1766 : {
1767 0 : aColor = pReadAcc->GetPixel( 0, nZ );
1768 :
1769 0 : *pTmp++ = (long) aColor.GetBlue() << 12;
1770 0 : *pTmp++ = (long) aColor.GetGreen() << 12;
1771 0 : *pTmp++ = (long) aColor.GetRed() << 12;
1772 : }
1773 : }
1774 :
1775 0 : for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ )
1776 : {
1777 0 : pTmp = p1T;
1778 0 : p1T = p2T;
1779 0 : p2T = pTmp;
1780 :
1781 0 : if( nY < nHeight )
1782 : {
1783 0 : if( bPal )
1784 : {
1785 0 : for( long nZ = 0; nZ < nWidth; nZ++ )
1786 : {
1787 0 : aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nZ ) );
1788 :
1789 0 : *pTmp++ = (long) aColor.GetBlue() << 12;
1790 0 : *pTmp++ = (long) aColor.GetGreen() << 12;
1791 0 : *pTmp++ = (long) aColor.GetRed() << 12;
1792 : }
1793 : }
1794 : else
1795 : {
1796 0 : for( long nZ = 0; nZ < nWidth; nZ++ )
1797 : {
1798 0 : aColor = pReadAcc->GetPixel( nY, nZ );
1799 :
1800 0 : *pTmp++ = (long) aColor.GetBlue() << 12;
1801 0 : *pTmp++ = (long) aColor.GetGreen() << 12;
1802 0 : *pTmp++ = (long) aColor.GetRed() << 12;
1803 : }
1804 : }
1805 : }
1806 :
1807 : // Examine first Pixel separately
1808 0 : nX = 0;
1809 : long nTemp;
1810 0 : CALC_ERRORS;
1811 0 : CALC_TABLES7;
1812 0 : nX -= 5;
1813 0 : CALC_TABLES5;
1814 0 : pWriteAcc->SetPixelIndex( nYAcc, 0, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
1815 :
1816 : // Get middle Pixels using a loop
1817 : long nXAcc;
1818 0 : for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ )
1819 : {
1820 0 : CALC_ERRORS;
1821 0 : CALC_TABLES7;
1822 0 : nX -= 8;
1823 0 : CALC_TABLES3;
1824 0 : CALC_TABLES5;
1825 0 : pWriteAcc->SetPixelIndex( nYAcc, nXAcc, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
1826 : }
1827 :
1828 : // Treat last Pixel separately
1829 0 : CALC_ERRORS;
1830 0 : nX -= 5;
1831 0 : CALC_TABLES3;
1832 0 : CALC_TABLES5;
1833 0 : pWriteAcc->SetPixelIndex( nYAcc, nWidth1, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
1834 : }
1835 :
1836 0 : bRet = true;
1837 : }
1838 :
1839 0 : ReleaseAccess( pReadAcc );
1840 0 : aNewBmp.ReleaseAccess( pWriteAcc );
1841 :
1842 0 : if( bRet )
1843 : {
1844 0 : const MapMode aMap( maPrefMapMode );
1845 0 : const Size aPrefSize( maPrefSize );
1846 :
1847 0 : *this = aNewBmp;
1848 :
1849 0 : maPrefMapMode = aMap;
1850 0 : maPrefSize = aPrefSize;
1851 0 : }
1852 : }
1853 :
1854 0 : return bRet;
1855 : }
1856 :
1857 0 : bool Bitmap::ImplDitherFloyd16()
1858 : {
1859 0 : BitmapReadAccess* pReadAcc = AcquireReadAccess();
1860 0 : Bitmap aNewBmp( GetSizePixel(), 24 );
1861 0 : BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1862 0 : bool bRet = false;
1863 :
1864 0 : if( pReadAcc && pWriteAcc )
1865 : {
1866 0 : const long nWidth = pWriteAcc->Width();
1867 0 : const long nWidth1 = nWidth - 1L;
1868 0 : const long nHeight = pWriteAcc->Height();
1869 0 : BitmapColor aColor;
1870 0 : BitmapColor aBestCol;
1871 0 : ImpErrorQuad aErrQuad;
1872 0 : boost::scoped_array<ImpErrorQuad> pErrQuad1(new ImpErrorQuad[ nWidth ]);
1873 0 : boost::scoped_array<ImpErrorQuad> pErrQuad2(new ImpErrorQuad[ nWidth ]);
1874 0 : ImpErrorQuad* pQLine1 = pErrQuad1.get();
1875 0 : ImpErrorQuad* pQLine2 = 0;
1876 0 : long nYTmp = 0L;
1877 0 : bool bQ1 = true;
1878 :
1879 0 : for( long nY = 0L; nY < std::min( nHeight, 2L ); nY++, nYTmp++ )
1880 : {
1881 0 : pQLine2 = !nY ? pErrQuad1.get() : pErrQuad2.get();
1882 0 : for( long nX = 0L; nX < nWidth; nX++ )
1883 0 : pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
1884 : }
1885 :
1886 0 : for( long nY = 0L; nY < nHeight; nY++, nYTmp++ )
1887 : {
1888 : // First RowPixel
1889 0 : aBestCol = pQLine1[ 0 ].ImplGetColor();
1890 0 : aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
1891 0 : aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
1892 0 : aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
1893 0 : pWriteAcc->SetPixel( nY, 0, aBestCol );
1894 :
1895 : long nX;
1896 0 : for( nX = 1L; nX < nWidth1; nX++ )
1897 : {
1898 0 : aColor = pQLine1[ nX ].ImplGetColor();
1899 0 : aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 );
1900 0 : aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 );
1901 0 : aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 );
1902 0 : aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol );
1903 0 : pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
1904 0 : pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
1905 0 : pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
1906 0 : pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
1907 0 : pWriteAcc->SetPixel( nY, nX, aBestCol );
1908 : }
1909 :
1910 : // Last RowPixel
1911 0 : aBestCol = pQLine1[ nWidth1 ].ImplGetColor();
1912 0 : aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
1913 0 : aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
1914 0 : aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
1915 0 : pWriteAcc->SetPixel( nY, nX, aBestCol );
1916 :
1917 : // Refill/copy row buffer
1918 0 : pQLine1 = pQLine2;
1919 0 : pQLine2 = ( bQ1 = !bQ1 ) ? pErrQuad2.get() : pErrQuad1.get();
1920 :
1921 0 : if( nYTmp < nHeight )
1922 0 : for( nX = 0L; nX < nWidth; nX++ )
1923 0 : pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
1924 : }
1925 :
1926 0 : bRet = true;
1927 : }
1928 :
1929 0 : ReleaseAccess( pReadAcc );
1930 0 : aNewBmp.ReleaseAccess( pWriteAcc );
1931 :
1932 0 : if( bRet )
1933 : {
1934 0 : const MapMode aMap( maPrefMapMode );
1935 0 : const Size aSize( maPrefSize );
1936 :
1937 0 : *this = aNewBmp;
1938 :
1939 0 : maPrefMapMode = aMap;
1940 0 : maPrefSize = aSize;
1941 : }
1942 :
1943 0 : return bRet;
1944 : }
1945 :
1946 0 : bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce )
1947 : {
1948 : bool bRet;
1949 :
1950 0 : if( GetColorCount() <= (sal_uLong) nColorCount )
1951 0 : bRet = true;
1952 0 : else if( nColorCount )
1953 : {
1954 0 : if( BMP_REDUCE_SIMPLE == eReduce )
1955 0 : bRet = ImplReduceSimple( nColorCount );
1956 0 : else if( BMP_REDUCE_POPULAR == eReduce )
1957 0 : bRet = ImplReducePopular( nColorCount );
1958 : else
1959 0 : bRet = ImplReduceMedian( nColorCount );
1960 : }
1961 : else
1962 0 : bRet = false;
1963 :
1964 0 : return bRet;
1965 : }
1966 :
1967 0 : bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount )
1968 : {
1969 0 : Bitmap aNewBmp;
1970 0 : BitmapReadAccess* pRAcc = AcquireReadAccess();
1971 0 : const sal_uInt16 nColCount = std::min( nColorCount, (sal_uInt16) 256 );
1972 : sal_uInt16 nBitCount;
1973 0 : bool bRet = false;
1974 :
1975 0 : if( nColCount <= 2 )
1976 0 : nBitCount = 1;
1977 0 : else if( nColCount <= 16 )
1978 0 : nBitCount = 4;
1979 : else
1980 0 : nBitCount = 8;
1981 :
1982 0 : if( pRAcc )
1983 : {
1984 0 : Octree aOct( *pRAcc, nColCount );
1985 0 : const BitmapPalette& rPal = aOct.GetPalette();
1986 : BitmapWriteAccess* pWAcc;
1987 :
1988 0 : aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal );
1989 0 : pWAcc = aNewBmp.AcquireWriteAccess();
1990 :
1991 0 : if( pWAcc )
1992 : {
1993 0 : const long nWidth = pRAcc->Width();
1994 0 : const long nHeight = pRAcc->Height();
1995 :
1996 0 : if( pRAcc->HasPalette() )
1997 : {
1998 0 : for( long nY = 0L; nY < nHeight; nY++ )
1999 0 : for( long nX =0L; nX < nWidth; nX++ )
2000 0 : pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ))) );
2001 : }
2002 : else
2003 : {
2004 0 : for( long nY = 0L; nY < nHeight; nY++ )
2005 0 : for( long nX =0L; nX < nWidth; nX++ )
2006 0 : pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) )) );
2007 : }
2008 :
2009 0 : aNewBmp.ReleaseAccess( pWAcc );
2010 0 : bRet = true;
2011 : }
2012 :
2013 0 : ReleaseAccess( pRAcc );
2014 : }
2015 :
2016 0 : if( bRet )
2017 : {
2018 0 : const MapMode aMap( maPrefMapMode );
2019 0 : const Size aSize( maPrefSize );
2020 :
2021 0 : *this = aNewBmp;
2022 0 : maPrefMapMode = aMap;
2023 0 : maPrefSize = aSize;
2024 : }
2025 :
2026 0 : return bRet;
2027 : }
2028 :
2029 : struct PopularColorCount
2030 : {
2031 : sal_uInt32 mnIndex;
2032 : sal_uInt32 mnCount;
2033 : };
2034 :
2035 0 : extern "C" int SAL_CALL ImplPopularCmpFnc( const void* p1, const void* p2 )
2036 : {
2037 : int nRet;
2038 :
2039 0 : if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount )
2040 0 : nRet = 1;
2041 0 : else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount )
2042 0 : nRet = 0;
2043 : else
2044 0 : nRet = -1;
2045 :
2046 0 : return nRet;
2047 : }
2048 :
2049 0 : bool Bitmap::ImplReducePopular( sal_uInt16 nColCount )
2050 : {
2051 0 : BitmapReadAccess* pRAcc = AcquireReadAccess();
2052 : sal_uInt16 nBitCount;
2053 0 : bool bRet = false;
2054 :
2055 0 : if( nColCount > 256 )
2056 0 : nColCount = 256;
2057 :
2058 0 : if( nColCount < 17 )
2059 0 : nBitCount = 4;
2060 : else
2061 0 : nBitCount = 8;
2062 :
2063 0 : if( pRAcc )
2064 : {
2065 0 : const sal_uInt32 nValidBits = 4;
2066 0 : const sal_uInt32 nRightShiftBits = 8 - nValidBits;
2067 0 : const sal_uInt32 nLeftShiftBits1 = nValidBits;
2068 0 : const sal_uInt32 nLeftShiftBits2 = nValidBits << 1;
2069 0 : const sal_uInt32 nColorsPerComponent = 1 << nValidBits;
2070 0 : const sal_uInt32 nColorOffset = 256 / nColorsPerComponent;
2071 0 : const sal_uInt32 nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent;
2072 0 : const long nWidth = pRAcc->Width();
2073 0 : const long nHeight = pRAcc->Height();
2074 0 : boost::scoped_array<PopularColorCount> pCountTable(new PopularColorCount[ nTotalColors ]);
2075 :
2076 0 : memset( pCountTable.get(), 0, nTotalColors * sizeof( PopularColorCount ) );
2077 :
2078 0 : for( long nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
2079 : {
2080 0 : for( long nG = 0; nG < 256; nG += nColorOffset )
2081 : {
2082 0 : for( long nB = 0; nB < 256; nB += nColorOffset )
2083 : {
2084 0 : pCountTable[ nIndex ].mnIndex = nIndex;
2085 0 : nIndex++;
2086 : }
2087 : }
2088 : }
2089 :
2090 0 : if( pRAcc->HasPalette() )
2091 : {
2092 0 : for( long nY = 0L; nY < nHeight; nY++ )
2093 : {
2094 0 : for( long nX = 0L; nX < nWidth; nX++ )
2095 : {
2096 0 : const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
2097 0 : pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
2098 0 : ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
2099 0 : ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
2100 : }
2101 : }
2102 : }
2103 : else
2104 : {
2105 0 : for( long nY = 0L; nY < nHeight; nY++ )
2106 : {
2107 0 : for( long nX = 0L; nX < nWidth; nX++ )
2108 : {
2109 0 : const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
2110 0 : pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
2111 0 : ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
2112 0 : ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
2113 0 : }
2114 : }
2115 : }
2116 :
2117 0 : BitmapPalette aNewPal( nColCount );
2118 :
2119 0 : qsort( pCountTable.get(), nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc );
2120 :
2121 0 : for( sal_uInt16 n = 0; n < nColCount; n++ )
2122 : {
2123 0 : const PopularColorCount& rPop = pCountTable[ n ];
2124 0 : aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ),
2125 : (sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ),
2126 0 : (sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) );
2127 : }
2128 :
2129 0 : Bitmap aNewBmp( GetSizePixel(), nBitCount, &aNewPal );
2130 0 : BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess();
2131 :
2132 0 : if( pWAcc )
2133 : {
2134 0 : BitmapColor aDstCol( (sal_uInt8) 0 );
2135 0 : boost::scoped_array<sal_uInt8> pIndexMap(new sal_uInt8[ nTotalColors ]);
2136 :
2137 0 : for( long nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
2138 0 : for( long nG = 0; nG < 256; nG += nColorOffset )
2139 0 : for( long nB = 0; nB < 256; nB += nColorOffset )
2140 0 : pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) );
2141 :
2142 0 : if( pRAcc->HasPalette() )
2143 : {
2144 0 : for( long nY = 0L; nY < nHeight; nY++ )
2145 : {
2146 0 : for( long nX = 0L; nX < nWidth; nX++ )
2147 : {
2148 0 : const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
2149 0 : aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
2150 0 : ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
2151 0 : ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] );
2152 0 : pWAcc->SetPixel( nY, nX, aDstCol );
2153 : }
2154 : }
2155 : }
2156 : else
2157 : {
2158 0 : for( long nY = 0L; nY < nHeight; nY++ )
2159 : {
2160 0 : for( long nX = 0L; nX < nWidth; nX++ )
2161 : {
2162 0 : const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
2163 0 : aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
2164 0 : ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
2165 0 : ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] );
2166 0 : pWAcc->SetPixel( nY, nX, aDstCol );
2167 0 : }
2168 : }
2169 : }
2170 :
2171 0 : aNewBmp.ReleaseAccess( pWAcc );
2172 0 : bRet = true;
2173 : }
2174 :
2175 0 : pCountTable.reset();
2176 0 : ReleaseAccess( pRAcc );
2177 :
2178 0 : if( bRet )
2179 : {
2180 0 : const MapMode aMap( maPrefMapMode );
2181 0 : const Size aSize( maPrefSize );
2182 :
2183 0 : *this = aNewBmp;
2184 0 : maPrefMapMode = aMap;
2185 0 : maPrefSize = aSize;
2186 0 : }
2187 : }
2188 :
2189 0 : return bRet;
2190 : }
2191 :
2192 0 : bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount )
2193 : {
2194 0 : BitmapReadAccess* pRAcc = AcquireReadAccess();
2195 : sal_uInt16 nBitCount;
2196 0 : bool bRet = false;
2197 :
2198 0 : if( nColCount < 17 )
2199 0 : nBitCount = 4;
2200 0 : else if( nColCount < 257 )
2201 0 : nBitCount = 8;
2202 : else
2203 : {
2204 : OSL_FAIL( "Bitmap::ImplReduceMedian(): invalid color count!" );
2205 0 : nBitCount = 8;
2206 0 : nColCount = 256;
2207 : }
2208 :
2209 0 : if( pRAcc )
2210 : {
2211 0 : Bitmap aNewBmp( GetSizePixel(), nBitCount );
2212 0 : BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess();
2213 :
2214 0 : if( pWAcc )
2215 : {
2216 0 : const sal_uLong nSize = 32768UL * sizeof( sal_uLong );
2217 0 : sal_uLong* pColBuf = (sal_uLong*) rtl_allocateMemory( nSize );
2218 0 : const long nWidth = pWAcc->Width();
2219 0 : const long nHeight = pWAcc->Height();
2220 0 : long nIndex = 0L;
2221 :
2222 0 : memset( (HPBYTE) pColBuf, 0, nSize );
2223 :
2224 : // create Buffer
2225 0 : if( pRAcc->HasPalette() )
2226 : {
2227 0 : for( long nY = 0L; nY < nHeight; nY++ )
2228 : {
2229 0 : for( long nX = 0L; nX < nWidth; nX++ )
2230 : {
2231 0 : const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
2232 0 : pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++;
2233 : }
2234 : }
2235 : }
2236 : else
2237 : {
2238 0 : for( long nY = 0L; nY < nHeight; nY++ )
2239 : {
2240 0 : for( long nX = 0L; nX < nWidth; nX++ )
2241 : {
2242 0 : const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
2243 0 : pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++;
2244 0 : }
2245 : }
2246 : }
2247 :
2248 : // create palette via median cut
2249 0 : BitmapPalette aPal( pWAcc->GetPaletteEntryCount() );
2250 : ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31,
2251 0 : nColCount, nWidth * nHeight, nIndex );
2252 :
2253 : // do mapping of colors to palette
2254 0 : InverseColorMap aMap( aPal );
2255 0 : pWAcc->SetPalette( aPal );
2256 0 : for( long nY = 0L; nY < nHeight; nY++ )
2257 0 : for( long nX = 0L; nX < nWidth; nX++ )
2258 0 : pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>( aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) )) );
2259 :
2260 0 : rtl_freeMemory( pColBuf );
2261 0 : aNewBmp.ReleaseAccess( pWAcc );
2262 0 : bRet = true;
2263 : }
2264 :
2265 0 : ReleaseAccess( pRAcc );
2266 :
2267 0 : if( bRet )
2268 : {
2269 0 : const MapMode aMap( maPrefMapMode );
2270 0 : const Size aSize( maPrefSize );
2271 :
2272 0 : *this = aNewBmp;
2273 0 : maPrefMapMode = aMap;
2274 0 : maPrefSize = aSize;
2275 0 : }
2276 : }
2277 :
2278 0 : return bRet;
2279 : }
2280 :
2281 0 : void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal,
2282 : long nR1, long nR2, long nG1, long nG2, long nB1, long nB2,
2283 : long nColors, long nPixels, long& rIndex )
2284 : {
2285 0 : if( !nPixels )
2286 0 : return;
2287 :
2288 0 : BitmapColor aCol;
2289 0 : const long nRLen = nR2 - nR1;
2290 0 : const long nGLen = nG2 - nG1;
2291 0 : const long nBLen = nB2 - nB1;
2292 0 : sal_uLong* pBuf = pColBuf;
2293 :
2294 0 : if( !nRLen && !nGLen && !nBLen )
2295 : {
2296 0 : if( pBuf[ RGB15( nR1, nG1, nB1 ) ] )
2297 : {
2298 0 : aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) );
2299 0 : aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) );
2300 0 : aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) );
2301 0 : rPal[ (sal_uInt16) rIndex++ ] = aCol;
2302 : }
2303 : }
2304 : else
2305 : {
2306 0 : if( 1 == nColors || 1 == nPixels )
2307 : {
2308 0 : long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0;
2309 :
2310 0 : for( long nR = nR1; nR <= nR2; nR++ )
2311 : {
2312 0 : for( long nG = nG1; nG <= nG2; nG++ )
2313 : {
2314 0 : for( long nB = nB1; nB <= nB2; nB++ )
2315 : {
2316 0 : nPixSum = pBuf[ RGB15( nR, nG, nB ) ];
2317 :
2318 0 : if( nPixSum )
2319 : {
2320 0 : nRSum += nR * nPixSum;
2321 0 : nGSum += nG * nPixSum;
2322 0 : nBSum += nB * nPixSum;
2323 : }
2324 : }
2325 : }
2326 : }
2327 :
2328 0 : aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) );
2329 0 : aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) );
2330 0 : aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) );
2331 0 : rPal[ (sal_uInt16) rIndex++ ] = aCol;
2332 : }
2333 : else
2334 : {
2335 0 : const long nTest = ( nPixels >> 1 );
2336 0 : long nPixOld = 0;
2337 0 : long nPixNew = 0;
2338 :
2339 0 : if( nBLen > nGLen && nBLen > nRLen )
2340 : {
2341 0 : long nB = nB1 - 1;
2342 :
2343 0 : while( nPixNew < nTest )
2344 : {
2345 0 : nB++, nPixOld = nPixNew;
2346 0 : for( long nR = nR1; nR <= nR2; nR++ )
2347 0 : for( long nG = nG1; nG <= nG2; nG++ )
2348 0 : nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
2349 : }
2350 :
2351 0 : if( nB < nB2 )
2352 : {
2353 0 : ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex );
2354 0 : ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
2355 : }
2356 : else
2357 : {
2358 0 : ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex );
2359 0 : ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2360 0 : }
2361 : }
2362 0 : else if( nGLen > nRLen )
2363 : {
2364 0 : long nG = nG1 - 1;
2365 :
2366 0 : while( nPixNew < nTest )
2367 : {
2368 0 : nG++, nPixOld = nPixNew;
2369 0 : for( long nR = nR1; nR <= nR2; nR++ )
2370 0 : for( long nB = nB1; nB <= nB2; nB++ )
2371 0 : nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
2372 : }
2373 :
2374 0 : if( nG < nG2 )
2375 : {
2376 0 : ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex );
2377 0 : ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
2378 : }
2379 : else
2380 : {
2381 0 : ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex );
2382 0 : ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2383 : }
2384 : }
2385 : else
2386 : {
2387 0 : long nR = nR1 - 1;
2388 :
2389 0 : while( nPixNew < nTest )
2390 : {
2391 0 : nR++, nPixOld = nPixNew;
2392 0 : for( long nG = nG1; nG <= nG2; nG++ )
2393 0 : for( long nB = nB1; nB <= nB2; nB++ )
2394 0 : nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
2395 : }
2396 :
2397 0 : if( nR < nR2 )
2398 : {
2399 0 : ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex );
2400 0 : ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
2401 : }
2402 : else
2403 : {
2404 0 : ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex );
2405 0 : ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2406 : }
2407 : }
2408 : }
2409 0 : }
2410 : }
2411 :
2412 0 : bool Bitmap::Vectorize( tools::PolyPolygon& rPolyPoly, sal_uLong nFlags, const Link* pProgress )
2413 : {
2414 0 : return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress );
2415 : }
2416 :
2417 0 : bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress )
2418 : {
2419 0 : return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress );
2420 : }
2421 :
2422 6 : bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
2423 : short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
2424 : double fGamma, bool bInvert, bool msoBrightness )
2425 : {
2426 6 : bool bRet = false;
2427 :
2428 : // nothing to do => return quickly
2429 6 : if( !nLuminancePercent && !nContrastPercent &&
2430 0 : !nChannelRPercent && !nChannelGPercent && !nChannelBPercent &&
2431 0 : ( fGamma == 1.0 ) && !bInvert )
2432 : {
2433 0 : bRet = true;
2434 : }
2435 : else
2436 : {
2437 6 : BitmapWriteAccess* pAcc = AcquireWriteAccess();
2438 :
2439 6 : if( pAcc )
2440 : {
2441 6 : BitmapColor aCol;
2442 6 : const long nW = pAcc->Width();
2443 6 : const long nH = pAcc->Height();
2444 12 : boost::scoped_array<sal_uInt8> cMapR(new sal_uInt8[ 256 ]);
2445 12 : boost::scoped_array<sal_uInt8> cMapG(new sal_uInt8[ 256 ]);
2446 12 : boost::scoped_array<sal_uInt8> cMapB(new sal_uInt8[ 256 ]);
2447 : double fM, fROff, fGOff, fBOff, fOff;
2448 :
2449 : // calculate slope
2450 6 : if( nContrastPercent >= 0 )
2451 0 : fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
2452 : else
2453 6 : fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
2454 :
2455 6 : if(!msoBrightness)
2456 : // total offset = luminance offset + contrast offset
2457 0 : fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
2458 : else
2459 6 : fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55;
2460 :
2461 : // channel offset = channel offset + total offset
2462 6 : fROff = nChannelRPercent * 2.55 + fOff;
2463 6 : fGOff = nChannelGPercent * 2.55 + fOff;
2464 6 : fBOff = nChannelBPercent * 2.55 + fOff;
2465 :
2466 : // calculate gamma value
2467 6 : fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
2468 6 : const bool bGamma = ( fGamma != 1.0 );
2469 :
2470 : // create mapping table
2471 1542 : for( long nX = 0L; nX < 256L; nX++ )
2472 : {
2473 1536 : if(!msoBrightness)
2474 : {
2475 0 : cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
2476 0 : cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
2477 0 : cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
2478 : }
2479 : else
2480 : {
2481 : // LO simply uses (in a somewhat optimized form) "newcolor = (oldcolor-128)*contrast+brightness+128"
2482 : // as the formula, i.e. contrast first, brightness afterwards. MSOffice, for whatever weird reason,
2483 : // use neither first, but apparently it applies half of brightness before contrast and half afterwards.
2484 1536 : cMapR[ nX ] = (sal_uInt8) MinMax( FRound( (nX+fROff/2-128) * fM + 128 + fROff/2 ), 0L, 255L );
2485 1536 : cMapG[ nX ] = (sal_uInt8) MinMax( FRound( (nX+fGOff/2-128) * fM + 128 + fGOff/2 ), 0L, 255L );
2486 1536 : cMapB[ nX ] = (sal_uInt8) MinMax( FRound( (nX+fBOff/2-128) * fM + 128 + fBOff/2 ), 0L, 255L );
2487 : }
2488 1536 : if( bGamma )
2489 : {
2490 0 : cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma );
2491 0 : cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma );
2492 0 : cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma );
2493 : }
2494 :
2495 1536 : if( bInvert )
2496 : {
2497 0 : cMapR[ nX ] = ~cMapR[ nX ];
2498 0 : cMapG[ nX ] = ~cMapG[ nX ];
2499 0 : cMapB[ nX ] = ~cMapB[ nX ];
2500 : }
2501 : }
2502 :
2503 : // do modifying
2504 6 : if( pAcc->HasPalette() )
2505 : {
2506 0 : BitmapColor aNewCol;
2507 :
2508 0 : for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
2509 : {
2510 0 : const BitmapColor& rCol = pAcc->GetPaletteColor( i );
2511 0 : aNewCol.SetRed( cMapR[ rCol.GetRed() ] );
2512 0 : aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] );
2513 0 : aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] );
2514 0 : pAcc->SetPaletteColor( i, aNewCol );
2515 0 : }
2516 : }
2517 6 : else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
2518 : {
2519 2540 : for( long nY = 0L; nY < nH; nY++ )
2520 : {
2521 2534 : Scanline pScan = pAcc->GetScanline( nY );
2522 :
2523 2676316 : for( long nX = 0L; nX < nW; nX++ )
2524 : {
2525 2673782 : *pScan = cMapB[ *pScan ]; pScan++;
2526 2673782 : *pScan = cMapG[ *pScan ]; pScan++;
2527 2673782 : *pScan = cMapR[ *pScan ]; pScan++;
2528 : }
2529 : }
2530 : }
2531 0 : else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
2532 : {
2533 0 : for( long nY = 0L; nY < nH; nY++ )
2534 : {
2535 0 : Scanline pScan = pAcc->GetScanline( nY );
2536 :
2537 0 : for( long nX = 0L; nX < nW; nX++ )
2538 : {
2539 0 : *pScan = cMapR[ *pScan ]; pScan++;
2540 0 : *pScan = cMapG[ *pScan ]; pScan++;
2541 0 : *pScan = cMapB[ *pScan ]; pScan++;
2542 : }
2543 : }
2544 : }
2545 : else
2546 : {
2547 0 : for( long nY = 0L; nY < nH; nY++ )
2548 : {
2549 0 : for( long nX = 0L; nX < nW; nX++ )
2550 : {
2551 0 : aCol = pAcc->GetPixel( nY, nX );
2552 0 : aCol.SetRed( cMapR[ aCol.GetRed() ] );
2553 0 : aCol.SetGreen( cMapG[ aCol.GetGreen() ] );
2554 0 : aCol.SetBlue( cMapB[ aCol.GetBlue() ] );
2555 0 : pAcc->SetPixel( nY, nX, aCol );
2556 : }
2557 : }
2558 : }
2559 :
2560 6 : ReleaseAccess( pAcc );
2561 12 : bRet = true;
2562 : }
2563 : }
2564 :
2565 6 : return bRet;
2566 : }
2567 :
2568 0 : bool Bitmap::ImplConvolutionPass(Bitmap& aNewBitmap, const int nNewSize, BitmapReadAccess* pReadAcc, int aNumberOfContributions, double* pWeights, int* pPixels, int* pCount)
2569 : {
2570 0 : BitmapWriteAccess* pWriteAcc = aNewBitmap.AcquireWriteAccess();
2571 :
2572 0 : if (!pReadAcc || !pWriteAcc)
2573 0 : return false;
2574 :
2575 0 : const int nHeight = GetSizePixel().Height();
2576 :
2577 0 : BitmapColor aColor;
2578 : double aValueRed, aValueGreen, aValueBlue;
2579 : double aSum, aWeight;
2580 : int aBaseIndex, aIndex;
2581 :
2582 0 : for ( int y = 0; y < nHeight; y++ )
2583 : {
2584 0 : for ( int x = 0; x < nNewSize; x++ )
2585 : {
2586 0 : aBaseIndex = x * aNumberOfContributions;
2587 0 : aSum = aValueRed = aValueGreen = aValueBlue = 0.0;
2588 :
2589 0 : for ( int j=0; j < pCount[x]; j++ )
2590 : {
2591 0 : aIndex = aBaseIndex + j;
2592 0 : aSum += aWeight = pWeights[ aIndex ];
2593 :
2594 0 : aColor = pReadAcc->GetColor( y, pPixels[ aIndex ] );
2595 :
2596 0 : aValueRed += aWeight * aColor.GetRed();
2597 0 : aValueGreen += aWeight * aColor.GetGreen();
2598 0 : aValueBlue += aWeight * aColor.GetBlue();
2599 : }
2600 :
2601 : BitmapColor aResultColor(
2602 0 : (sal_uInt8) MinMax( aValueRed / aSum, 0, 255 ),
2603 0 : (sal_uInt8) MinMax( aValueGreen / aSum, 0, 255 ),
2604 0 : (sal_uInt8) MinMax( aValueBlue / aSum, 0, 255 ) );
2605 0 : pWriteAcc->SetPixel( y, x, aResultColor );
2606 0 : }
2607 : }
2608 0 : aNewBitmap.ReleaseAccess( pWriteAcc );
2609 0 : return true;
2610 1233 : }
2611 :
2612 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|