1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26
27 #include <stdlib.h>
28
29 #include <vcl/bmpacc.hxx>
30 #include <vcl/octree.hxx>
31 #include <vcl/bitmapex.hxx>
32 #include <vcl/bitmap.hxx>
33
34 #include <impoct.hxx>
35 #include <impvect.hxx>
36
37 // -----------
38 // - Defines -
39 // -----------
40
41 #define RGB15( _def_cR, _def_cG, _def_cB ) (((sal_uLong)(_def_cR)<<10UL)|((sal_uLong)(_def_cG)<<5UL)|(sal_uLong)(_def_cB))
42 #define GAMMA( _def_cVal, _def_InvGamma ) ((sal_uInt8)MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0L,255L))
43 #define MAP( cVal0, cVal1, nFrac ) ((sal_uInt8)((((long)(cVal0)<<7L)+nFrac*((long)(cVal1)-(cVal0)))>>7L))
44
45 #define CALC_ERRORS \
46 nTemp = p1T[nX++] >> 12; \
47 nBErr = MinMax( nTemp, 0, 255 ); \
48 nBErr = nBErr - FloydIndexMap[ nBC = FloydMap[nBErr] ]; \
49 nTemp = p1T[nX++] >> 12; \
50 nGErr = MinMax( nTemp, 0, 255 ); \
51 nGErr = nGErr - FloydIndexMap[ nGC = FloydMap[nGErr] ]; \
52 nTemp = p1T[nX] >> 12; \
53 nRErr = MinMax( nTemp, 0, 255 ); \
54 nRErr = nRErr - FloydIndexMap[ nRC = FloydMap[nRErr] ];
55
56 #define CALC_TABLES3 \
57 p2T[nX++] += FloydError3[nBErr]; \
58 p2T[nX++] += FloydError3[nGErr]; \
59 p2T[nX++] += FloydError3[nRErr];
60
61 #define CALC_TABLES5 \
62 p2T[nX++] += FloydError5[nBErr]; \
63 p2T[nX++] += FloydError5[nGErr]; \
64 p2T[nX++] += FloydError5[nRErr];
65
66 #define CALC_TABLES7 \
67 p1T[++nX] += FloydError7[nBErr]; \
68 p2T[nX++] += FloydError1[nBErr]; \
69 p1T[nX] += FloydError7[nGErr]; \
70 p2T[nX++] += FloydError1[nGErr]; \
71 p1T[nX] += FloydError7[nRErr]; \
72 p2T[nX] += FloydError1[nRErr];
73
74 // -----------
75 // - Statics -
76 // -----------
77
78 sal_uLong nVCLRLut[ 6 ] = { 16, 17, 18, 19, 20, 21 };
79 sal_uLong nVCLGLut[ 6 ] = { 0, 6, 12, 18, 24, 30 };
80 sal_uLong nVCLBLut[ 6 ] = { 0, 36, 72, 108, 144, 180 };
81
82 // ------------------------------------------------------------------------
83
84 sal_uLong nVCLDitherLut[ 256 ] =
85 {
86 0, 49152, 12288, 61440, 3072, 52224, 15360, 64512, 768, 49920, 13056,
87 62208, 3840, 52992, 16128, 65280, 32768, 16384, 45056, 28672, 35840, 19456,
88 48128, 31744, 33536, 17152, 45824, 29440, 36608, 20224, 48896, 32512, 8192,
89 57344, 4096, 53248, 11264, 60416, 7168, 56320, 8960, 58112, 4864, 54016,
90 12032, 61184, 7936, 57088, 40960, 24576, 36864, 20480, 44032, 27648, 39936,
91 23552, 41728, 25344, 37632, 21248, 44800, 28416, 40704, 24320, 2048, 51200,
92 14336, 63488, 1024, 50176, 13312, 62464, 2816, 51968, 15104, 64256, 1792,
93 50944, 14080, 63232, 34816, 18432, 47104, 30720, 33792, 17408, 46080, 29696,
94 35584, 19200, 47872, 31488, 34560, 18176, 46848, 30464, 10240, 59392, 6144,
95 55296, 9216, 58368, 5120, 54272, 11008, 60160, 6912, 56064, 9984, 59136,
96 5888, 55040, 43008, 26624, 38912, 22528, 41984, 25600, 37888, 21504, 43776,
97 27392, 39680, 23296, 42752, 26368, 38656, 22272, 512, 49664, 12800, 61952,
98 3584, 52736, 15872, 65024, 256, 49408, 12544, 61696, 3328, 52480, 15616,
99 64768, 33280, 16896, 45568, 29184, 36352, 19968, 48640, 32256, 33024, 16640,
100 45312, 28928, 36096, 19712, 48384, 32000, 8704, 57856, 4608, 53760, 11776,
101 60928, 7680, 56832, 8448, 57600, 4352, 53504, 11520, 60672, 7424, 56576,
102 41472, 25088, 37376, 20992, 44544, 28160, 40448, 24064, 41216, 24832, 37120,
103 20736, 44288, 27904, 40192, 23808, 2560, 51712, 14848, 64000, 1536, 50688,
104 13824, 62976, 2304, 51456, 14592, 63744, 1280, 50432, 13568, 62720, 35328,
105 18944, 47616, 31232, 34304, 17920, 46592, 30208, 35072, 18688, 47360, 30976,
106 34048, 17664, 46336, 29952, 10752, 59904, 6656, 55808, 9728, 58880, 5632,
107 54784, 10496, 59648, 6400, 55552, 9472, 58624, 5376, 54528, 43520, 27136,
108 39424, 23040, 42496, 26112, 38400, 22016, 43264, 26880, 39168, 22784, 42240,
109 25856, 38144, 21760
110 };
111
112 // ------------------------------------------------------------------------
113
114 sal_uLong nVCLLut[ 256 ] =
115 {
116 0, 1286, 2572, 3858, 5144, 6430, 7716, 9002,
117 10288, 11574, 12860, 14146, 15432, 16718, 18004, 19290,
118 20576, 21862, 23148, 24434, 25720, 27006, 28292, 29578,
119 30864, 32150, 33436, 34722, 36008, 37294, 38580, 39866,
120 41152, 42438, 43724, 45010, 46296, 47582, 48868, 50154,
121 51440, 52726, 54012, 55298, 56584, 57870, 59156, 60442,
122 61728, 63014, 64300, 65586, 66872, 68158, 69444, 70730,
123 72016, 73302, 74588, 75874, 77160, 78446, 79732, 81018,
124 82304, 83590, 84876, 86162, 87448, 88734, 90020, 91306,
125 92592, 93878, 95164, 96450, 97736, 99022,100308,101594,
126 102880,104166,105452,106738,108024,109310,110596,111882,
127 113168,114454,115740,117026,118312,119598,120884,122170,
128 123456,124742,126028,127314,128600,129886,131172,132458,
129 133744,135030,136316,137602,138888,140174,141460,142746,
130 144032,145318,146604,147890,149176,150462,151748,153034,
131 154320,155606,156892,158178,159464,160750,162036,163322,
132 164608,165894,167180,168466,169752,171038,172324,173610,
133 174896,176182,177468,178754,180040,181326,182612,183898,
134 185184,186470,187756,189042,190328,191614,192900,194186,
135 195472,196758,198044,199330,200616,201902,203188,204474,
136 205760,207046,208332,209618,210904,212190,213476,214762,
137 216048,217334,218620,219906,221192,222478,223764,225050,
138 226336,227622,228908,230194,231480,232766,234052,235338,
139 236624,237910,239196,240482,241768,243054,244340,245626,
140 246912,248198,249484,250770,252056,253342,254628,255914,
141 257200,258486,259772,261058,262344,263630,264916,266202,
142 267488,268774,270060,271346,272632,273918,275204,276490,
143 277776,279062,280348,281634,282920,284206,285492,286778,
144 288064,289350,290636,291922,293208,294494,295780,297066,
145 298352,299638,300924,302210,303496,304782,306068,307354,
146 308640,309926,311212,312498,313784,315070,316356,317642,
147 318928,320214,321500,322786,324072,325358,326644,327930
148 };
149
150 // ------------------------------------------------------------------------
151
152 long FloydMap[256] =
153 {
154 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
155 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
156 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
157 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
158 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
159 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
160 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
161 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
162 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
163 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
164 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
165 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
166 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
167 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
168 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
169 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
170 };
171
172 // ------------------------------------------------------------------------
173
174 long FloydError1[61] =
175 {
176 -7680, -7424, -7168, -6912, -6656, -6400, -6144,
177 -5888, -5632, -5376, -5120, -4864, -4608, -4352,
178 -4096, -3840, -3584, -3328, -3072, -2816, -2560,
179 -2304, -2048, -1792, -1536, -1280, -1024, -768,
180 -512, -256, 0, 256, 512, 768, 1024, 1280, 1536,
181 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
182 3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632,
183 5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680
184 };
185
186 // ------------------------------------------------------------------------
187
188 long FloydError3[61] =
189 {
190 -23040, -22272, -21504, -20736, -19968, -19200,
191 -18432, -17664, -16896, -16128, -15360, -14592,
192 -13824, -13056, -12288, -11520, -10752, -9984,
193 -9216, -8448, -7680, -6912, -6144, -5376, -4608,
194 -3840, -3072, -2304, -1536, -768, 0, 768, 1536,
195 2304, 3072, 3840, 4608, 5376, 6144, 6912, 7680,
196 8448, 9216, 9984, 10752, 11520, 12288, 13056,
197 13824, 14592, 15360, 16128, 16896, 17664, 18432,
198 19200, 19968, 20736, 21504, 22272, 23040
199 };
200
201 // ------------------------------------------------------------------------
202
203 long FloydError5[61] =
204 {
205 -38400, -37120, -35840, -34560, -33280, -32000,
206 -30720, -29440, -28160, -26880, -25600, -24320,
207 -23040, -21760, -20480, -19200, -17920, -16640,
208 -15360, -14080, -12800, -11520, -10240, -8960,
209 -7680, -6400, -5120, -3840, -2560, -1280, 0,
210 1280, 2560, 3840, 5120, 6400, 7680, 8960, 10240,
211 11520, 12800, 14080, 15360, 16640, 17920, 19200,
212 20480, 21760, 23040, 24320, 25600, 26880, 28160,
213 29440, 30720, 32000, 33280, 34560, 35840, 37120,
214 38400
215 };
216
217 // ------------------------------------------------------------------------
218
219 long FloydError7[61] =
220 {
221 -53760, -51968, -50176, -48384, -46592, -44800,
222 -43008, -41216, -39424, -37632, -35840, -34048,
223 -32256, -30464, -28672, -26880, -25088, -23296,
224 -21504, -19712, -17920, -16128, -14336, -12544,
225 -10752, -8960, -7168, -5376, -3584, -1792, 0,
226 1792, 3584, 5376, 7168, 8960, 10752, 12544, 14336,
227 16128, 17920, 19712, 21504, 23296, 25088, 26880,
228 28672, 30464, 32256, 34048, 35840, 37632, 39424,
229 41216, 43008, 44800, 46592, 48384, 50176, 51968,
230 53760
231 };
232
233 // ------------------------------------------------------------------------
234
235 long FloydIndexMap[6] =
236 {
237 -30, 21, 72, 123, 174, 225
238 };
239
240 // --------------------------
241 // - ImplCreateDitherMatrix -
242 // --------------------------
243
ImplCreateDitherMatrix(sal_uInt8 (* pDitherMatrix)[16][16])244 void ImplCreateDitherMatrix( sal_uInt8 (*pDitherMatrix)[16][16] )
245 {
246 double fVal = 3.125;
247 const double fVal16 = fVal / 16.;
248 long i, j, k, l;
249 sal_uInt16 pMtx[ 16 ][ 16 ];
250 sal_uInt16 nMax = 0;
251 static sal_uInt8 pMagic[4][4] = { { 0, 14, 3, 13, },
252 {11, 5, 8, 6, },
253 {12, 2, 15, 1, },
254 {7, 9, 4, 10 } };
255
256 // MagicSquare aufbauen
257 for ( i = 0; i < 4; i++ )
258 for ( j = 0; j < 4; j++ )
259 for ( k = 0; k < 4; k++ )
260 for ( l = 0; l < 4; l++ )
261 nMax = Max ( pMtx[ (k<<2) + i][(l<<2 ) + j] =
262 (sal_uInt16) ( 0.5 + pMagic[i][j]*fVal + pMagic[k][l]*fVal16 ), nMax );
263
264 // auf Intervall [0;254] skalieren
265 for ( i = 0, fVal = 254. / nMax; i < 16; i++ )
266 for( j = 0; j < 16; j++ )
267 (*pDitherMatrix)[i][j] = (sal_uInt8) ( fVal * pMtx[i][j] );
268 }
269
270 // ----------
271 // - Bitmap -
272 // ----------
273
Convert(BmpConversion eConversion)274 sal_Bool Bitmap::Convert( BmpConversion eConversion )
275 {
276 const sal_uInt16 nBitCount = GetBitCount();
277 sal_Bool bRet = sal_False;
278
279 switch( eConversion )
280 {
281 case( BMP_CONVERSION_1BIT_THRESHOLD ):
282 bRet = ImplMakeMono( 128 );
283 break;
284
285 case( BMP_CONVERSION_1BIT_MATRIX ):
286 bRet = ImplMakeMonoDither();
287 break;
288
289 case( BMP_CONVERSION_4BIT_GREYS ):
290 bRet = ImplMakeGreyscales( 16 );
291 break;
292
293 case( BMP_CONVERSION_4BIT_COLORS ):
294 {
295 if( nBitCount < 4 )
296 bRet = ImplConvertUp( 4, NULL );
297 else if( nBitCount > 4 )
298 bRet = ImplConvertDown( 4, NULL );
299 else
300 bRet = sal_True;
301 }
302 break;
303
304 case( BMP_CONVERSION_4BIT_TRANS ):
305 {
306 Color aTrans( BMP_COL_TRANS );
307
308 if( nBitCount < 4 )
309 bRet = ImplConvertUp( 4, &aTrans );
310 else
311 bRet = ImplConvertDown( 4, &aTrans );
312 }
313 break;
314
315 case( BMP_CONVERSION_8BIT_GREYS ):
316 bRet = ImplMakeGreyscales( 256 );
317 break;
318
319 case( BMP_CONVERSION_8BIT_COLORS ):
320 {
321 if( nBitCount < 8 )
322 bRet = ImplConvertUp( 8 );
323 else if( nBitCount > 8 )
324 bRet = ImplConvertDown( 8 );
325 else
326 bRet = sal_True;
327 }
328 break;
329
330 case( BMP_CONVERSION_8BIT_TRANS ):
331 {
332 Color aTrans( BMP_COL_TRANS );
333
334 if( nBitCount < 8 )
335 bRet = ImplConvertUp( 8, &aTrans );
336 else
337 bRet = ImplConvertDown( 8, &aTrans );
338 }
339 break;
340
341 case( BMP_CONVERSION_24BIT ):
342 {
343 if( nBitCount < 24 )
344 bRet = ImplConvertUp( 24, NULL );
345 else
346 bRet = sal_True;
347 }
348 break;
349
350 case( BMP_CONVERSION_GHOSTED ):
351 bRet = ImplConvertGhosted();
352 break;
353
354 default:
355 DBG_ERROR( "Bitmap::Convert(): Unsupported conversion" );
356 break;
357 }
358
359 return bRet;
360 }
361
362 // ------------------------------------------------------------------------
363
ImplMakeMono(sal_uInt8 cThreshold)364 sal_Bool Bitmap::ImplMakeMono( sal_uInt8 cThreshold )
365 {
366 BitmapReadAccess* pReadAcc = AcquireReadAccess();
367 sal_Bool bRet = sal_False;
368
369 if( pReadAcc )
370 {
371 Bitmap aNewBmp( GetSizePixel(), 1 );
372 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
373
374 if( pWriteAcc )
375 {
376 const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
377 const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
378 const long nWidth = pWriteAcc->Width();
379 const long nHeight = pWriteAcc->Height();
380
381 if( pReadAcc->HasPalette() )
382 {
383 for( long nY = 0L; nY < nHeight; nY++ )
384 {
385 for( long nX = 0L; nX < nWidth; nX++ )
386 {
387 const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX );
388 if( pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >=
389 cThreshold )
390 {
391 pWriteAcc->SetPixel( nY, nX, aWhite );
392 }
393 else
394 pWriteAcc->SetPixel( nY, nX, aBlack );
395 }
396 }
397 }
398 else
399 {
400 for( long nY = 0L; nY < nHeight; nY++ )
401 {
402 for( long nX = 0L; nX < nWidth; nX++ )
403 {
404 if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >=
405 cThreshold )
406 {
407 pWriteAcc->SetPixel( nY, nX, aWhite );
408 }
409 else
410 pWriteAcc->SetPixel( nY, nX, aBlack );
411 }
412 }
413 }
414
415 aNewBmp.ReleaseAccess( pWriteAcc );
416 bRet = sal_True;
417 }
418
419 ReleaseAccess( pReadAcc );
420
421 if( bRet )
422 {
423 const MapMode aMap( maPrefMapMode );
424 const Size aSize( maPrefSize );
425
426 *this = aNewBmp;
427
428 maPrefMapMode = aMap;
429 maPrefSize = aSize;
430 }
431 }
432
433 return bRet;
434 }
435
436 // ------------------------------------------------------------------------
437
ImplMakeMonoDither()438 sal_Bool Bitmap::ImplMakeMonoDither()
439 {
440 BitmapReadAccess* pReadAcc = AcquireReadAccess();
441 sal_Bool bRet = sal_False;
442
443 if( pReadAcc )
444 {
445 Bitmap aNewBmp( GetSizePixel(), 1 );
446 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
447
448 if( pWriteAcc )
449 {
450 const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
451 const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
452 const long nWidth = pWriteAcc->Width();
453 const long nHeight = pWriteAcc->Height();
454 sal_uInt8 pDitherMatrix[ 16 ][ 16 ];
455
456 ImplCreateDitherMatrix( &pDitherMatrix );
457
458 if( pReadAcc->HasPalette() )
459 {
460 for( long nY = 0L; nY < nHeight; nY++ )
461 {
462 for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
463 {
464 const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX );
465 if( pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >
466 pDitherMatrix[ nModY ][ nX % 16 ] )
467 {
468 pWriteAcc->SetPixel( nY, nX, aWhite );
469 }
470 else
471 pWriteAcc->SetPixel( nY, nX, aBlack );
472 }
473 }
474 }
475 else
476 {
477 for( long nY = 0L; nY < nHeight; nY++ )
478 {
479 for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
480 {
481 if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >
482 pDitherMatrix[ nModY ][ nX % 16 ] )
483 {
484 pWriteAcc->SetPixel( nY, nX, aWhite );
485 }
486 else
487 pWriteAcc->SetPixel( nY, nX, aBlack );
488 }
489 }
490 }
491
492 aNewBmp.ReleaseAccess( pWriteAcc );
493 bRet = sal_True;
494 }
495
496 ReleaseAccess( pReadAcc );
497
498 if( bRet )
499 {
500 const MapMode aMap( maPrefMapMode );
501 const Size aSize( maPrefSize );
502
503 *this = aNewBmp;
504
505 maPrefMapMode = aMap;
506 maPrefSize = aSize;
507 }
508 }
509
510 return bRet;
511 }
512
513 // ------------------------------------------------------------------------
514
ImplMakeGreyscales(sal_uInt16 nGreys)515 sal_Bool Bitmap::ImplMakeGreyscales( sal_uInt16 nGreys )
516 {
517 DBG_ASSERT( nGreys == 16 || nGreys == 256, "Only 16 or 256 greyscales are supported!" );
518
519 BitmapReadAccess* pReadAcc = AcquireReadAccess();
520 sal_Bool bRet = sal_False;
521
522 if( pReadAcc )
523 {
524 const BitmapPalette& rPal = GetGreyPalette( nGreys );
525 sal_uLong nShift = ( ( nGreys == 16 ) ? 4UL : 0UL );
526 sal_Bool bPalDiffers = !pReadAcc->HasPalette() || ( rPal.GetEntryCount() != pReadAcc->GetPaletteEntryCount() );
527
528 if( !bPalDiffers )
529 bPalDiffers = ( (BitmapPalette&) rPal != pReadAcc->GetPalette() );
530
531 if( bPalDiffers )
532 {
533 Bitmap aNewBmp( GetSizePixel(), ( nGreys == 16 ) ? 4 : 8, &rPal );
534 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
535
536 if( pWriteAcc )
537 {
538 const long nWidth = pWriteAcc->Width();
539 const long nHeight = pWriteAcc->Height();
540
541 if( pReadAcc->HasPalette() )
542 {
543 for( long nY = 0L; nY < nHeight; nY++ )
544 {
545 for( long nX = 0L; nX < nWidth; nX++ )
546 {
547 const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX );
548 pWriteAcc->SetPixelIndex( nY, nX,
549 (pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >> nShift) );
550 }
551 }
552 }
553 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR &&
554 pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
555 {
556 nShift += 8;
557
558 for( long nY = 0L; nY < nHeight; nY++ )
559 {
560 Scanline pReadScan = pReadAcc->GetScanline( nY );
561 Scanline pWriteScan = pWriteAcc->GetScanline( nY );
562
563 for( long nX = 0L; nX < nWidth; nX++ )
564 {
565 const sal_uLong nB = *pReadScan++;
566 const sal_uLong nG = *pReadScan++;
567 const sal_uLong nR = *pReadScan++;
568
569 *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
570 }
571 }
572 }
573 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB &&
574 pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
575 {
576 nShift += 8;
577
578 for( long nY = 0L; nY < nHeight; nY++ )
579 {
580 Scanline pReadScan = pReadAcc->GetScanline( nY );
581 Scanline pWriteScan = pWriteAcc->GetScanline( nY );
582
583 for( long nX = 0L; nX < nWidth; nX++ )
584 {
585 const sal_uLong nR = *pReadScan++;
586 const sal_uLong nG = *pReadScan++;
587 const sal_uLong nB = *pReadScan++;
588
589 *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
590 }
591 }
592 }
593 else
594 {
595 for( long nY = 0L; nY < nHeight; nY++ )
596 for( long nX = 0L; nX < nWidth; nX++ )
597 pWriteAcc->SetPixelIndex( nY, nX, (pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift );
598 }
599
600 aNewBmp.ReleaseAccess( pWriteAcc );
601 bRet = sal_True;
602 }
603
604 ReleaseAccess( pReadAcc );
605
606 if( bRet )
607 {
608 const MapMode aMap( maPrefMapMode );
609 const Size aSize( maPrefSize );
610
611 *this = aNewBmp;
612
613 maPrefMapMode = aMap;
614 maPrefSize = aSize;
615 }
616 }
617 else
618 {
619 ReleaseAccess( pReadAcc );
620 bRet = sal_True;
621 }
622 }
623
624 return bRet;
625 }
626
627 // ------------------------------------------------------------------------
628
ImplConvertUp(sal_uInt16 nBitCount,Color * pExtColor)629 sal_Bool Bitmap::ImplConvertUp( sal_uInt16 nBitCount, Color* pExtColor )
630 {
631 DBG_ASSERT( nBitCount > GetBitCount(), "New BitCount must be greater!" );
632
633 BitmapReadAccess* pReadAcc = AcquireReadAccess();
634 sal_Bool bRet = sal_False;
635
636 if( pReadAcc )
637 {
638 BitmapPalette aPal;
639 Bitmap aNewBmp( GetSizePixel(), nBitCount, pReadAcc->HasPalette() ? &pReadAcc->GetPalette() : &aPal );
640 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
641
642 if( pWriteAcc )
643 {
644 const long nWidth = pWriteAcc->Width();
645 const long nHeight = pWriteAcc->Height();
646
647 if( pWriteAcc->HasPalette() )
648 {
649 const sal_uInt16 nOldCount = 1 << GetBitCount();
650 const BitmapPalette& rOldPal = pReadAcc->GetPalette();
651
652 aPal.SetEntryCount( 1 << nBitCount );
653
654 for( sal_uInt16 i = 0; i < nOldCount; i++ )
655 aPal[ i ] = rOldPal[ i ];
656
657 if( pExtColor )
658 aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
659
660 pWriteAcc->SetPalette( aPal );
661
662 for( long nY = 0L; nY < nHeight; nY++ )
663 for( long nX = 0L; nX < nWidth; nX++ )
664 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
665 }
666 else
667 {
668 if( pReadAcc->HasPalette() )
669 {
670 for( long nY = 0L; nY < nHeight; nY++ )
671 for( long nX = 0L; nX < nWidth; nX++ )
672 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) );
673 }
674 else
675 {
676 for( long nY = 0L; nY < nHeight; nY++ )
677 for( long nX = 0L; nX < nWidth; nX++ )
678 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
679 }
680 }
681
682 aNewBmp.ReleaseAccess( pWriteAcc );
683 bRet = sal_True;
684 }
685
686 ReleaseAccess( pReadAcc );
687
688 if( bRet )
689 {
690 const MapMode aMap( maPrefMapMode );
691 const Size aSize( maPrefSize );
692
693 *this = aNewBmp;
694
695 maPrefMapMode = aMap;
696 maPrefSize = aSize;
697 }
698 }
699
700 return bRet;
701 }
702
703 // ------------------------------------------------------------------------
704
ImplConvertDown(sal_uInt16 nBitCount,Color * pExtColor)705 sal_Bool Bitmap::ImplConvertDown( sal_uInt16 nBitCount, Color* pExtColor )
706 {
707 DBG_ASSERT( nBitCount <= GetBitCount(), "New BitCount must be lower ( or equal when pExtColor is set )!" );
708
709 BitmapReadAccess* pReadAcc = AcquireReadAccess();
710 sal_Bool bRet = sal_False;
711
712 if( pReadAcc )
713 {
714 BitmapPalette aPal;
715 Bitmap aNewBmp( GetSizePixel(), nBitCount, &aPal );
716 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
717
718 if( pWriteAcc )
719 {
720 const sal_uInt16 nCount = 1 << nBitCount;
721 const long nWidth = pWriteAcc->Width();
722 const long nWidth1 = nWidth - 1L;
723 const long nHeight = pWriteAcc->Height();
724 Octree aOctree( *pReadAcc, pExtColor ? ( nCount - 1 ) : nCount );
725 InverseColorMap aColorMap( aPal = aOctree.GetPalette() );
726 BitmapColor aColor;
727 ImpErrorQuad aErrQuad;
728 ImpErrorQuad* pErrQuad1 = new ImpErrorQuad[ nWidth ];
729 ImpErrorQuad* pErrQuad2 = new ImpErrorQuad[ nWidth ];
730 ImpErrorQuad* pQLine1 = pErrQuad1;
731 ImpErrorQuad* pQLine2 = 0;
732 long nX, nY;
733 long nYTmp = 0L;
734 sal_uInt8 cIndex;
735 sal_Bool bQ1 = sal_True;
736
737 if( pExtColor )
738 {
739 aPal.SetEntryCount( aPal.GetEntryCount() + 1 );
740 aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
741 }
742
743 // set Black/White always, if we have enough space
744 if( aPal.GetEntryCount() < ( nCount - 1 ) )
745 {
746 aPal.SetEntryCount( aPal.GetEntryCount() + 2 );
747 aPal[ aPal.GetEntryCount() - 2 ] = Color( COL_BLACK );
748 aPal[ aPal.GetEntryCount() - 1 ] = Color( COL_WHITE );
749 }
750
751 pWriteAcc->SetPalette( aPal );
752
753 for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
754 {
755 for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
756 {
757 if( pReadAcc->HasPalette() )
758 pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nYTmp, nX ) );
759 else
760 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
761 }
762 }
763
764 for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
765 {
766 // first pixel in the line
767 cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ 0 ].ImplGetColor() );
768 pWriteAcc->SetPixelIndex( nY, 0, cIndex );
769
770 for( nX = 1L; nX < nWidth1; nX++ )
771 {
772 cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( aColor = pQLine1[ nX ].ImplGetColor() );
773 aErrQuad = ( ImpErrorQuad( aColor ) -= pWriteAcc->GetPaletteColor( cIndex ) );
774 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
775 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
776 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
777 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
778 pWriteAcc->SetPixelIndex( nY, nX, cIndex );
779 }
780
781 // letztes ZeilenPixel
782 if( nX < nWidth )
783 {
784 cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ nWidth1 ].ImplGetColor() );
785 pWriteAcc->SetPixelIndex( nY, nX, cIndex );
786 }
787
788 // Zeilenpuffer neu fuellen/kopieren
789 pQLine1 = pQLine2;
790 pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
791
792 if( nYTmp < nHeight )
793 {
794 for( nX = 0L; nX < nWidth; nX++ )
795 {
796 if( pReadAcc->HasPalette() )
797 pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nYTmp, nX ) );
798 else
799 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
800 }
801 }
802 }
803
804 // Zeilenpuffer zerstoeren
805 delete[] pErrQuad1;
806 delete[] pErrQuad2;
807
808 aNewBmp.ReleaseAccess( pWriteAcc );
809 bRet = sal_True;
810 }
811
812 ReleaseAccess( pReadAcc );
813
814 if( bRet )
815 {
816 const MapMode aMap( maPrefMapMode );
817 const Size aSize( maPrefSize );
818
819 *this = aNewBmp;
820
821 maPrefMapMode = aMap;
822 maPrefSize = aSize;
823 }
824 }
825
826 return bRet;
827 }
828
829 // ------------------------------------------------------------------------
830
ImplConvertGhosted()831 sal_Bool Bitmap::ImplConvertGhosted()
832 {
833 Bitmap aNewBmp;
834 BitmapReadAccess* pR = AcquireReadAccess();
835 sal_Bool bRet = sal_False;
836
837 if( pR )
838 {
839 if( pR->HasPalette() )
840 {
841 BitmapPalette aNewPal( pR->GetPaletteEntryCount() );
842
843 for( long i = 0, nCount = aNewPal.GetEntryCount(); i < nCount; i++ )
844 {
845 const BitmapColor& rOld = pR->GetPaletteColor( (sal_uInt16) i );
846 aNewPal[ (sal_uInt16) i ] = BitmapColor( ( rOld.GetRed() >> 1 ) | 0x80,
847 ( rOld.GetGreen() >> 1 ) | 0x80,
848 ( rOld.GetBlue() >> 1 ) | 0x80 );
849 }
850
851 aNewBmp = Bitmap( GetSizePixel(), GetBitCount(), &aNewPal );
852 BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
853
854 if( pW )
855 {
856 pW->CopyBuffer( *pR );
857 aNewBmp.ReleaseAccess( pW );
858 bRet = sal_True;
859 }
860 }
861 else
862 {
863 aNewBmp = Bitmap( GetSizePixel(), 24 );
864
865 BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
866
867 if( pW )
868 {
869 const long nWidth = pR->Width(), nHeight = pR->Height();
870
871 for( long nY = 0; nY < nHeight; nY++ )
872 {
873 for( long nX = 0; nX < nWidth; nX++ )
874 {
875 const BitmapColor aOld( pR->GetPixel( nY, nX ) );
876 pW->SetPixel( nY, nX, BitmapColor( ( aOld.GetRed() >> 1 ) | 0x80,
877 ( aOld.GetGreen() >> 1 ) | 0x80,
878 ( aOld.GetBlue() >> 1 ) | 0x80 ) );
879
880 }
881 }
882
883 aNewBmp.ReleaseAccess( pW );
884 bRet = sal_True;
885 }
886 }
887
888 ReleaseAccess( pR );
889 }
890
891 if( bRet )
892 {
893 const MapMode aMap( maPrefMapMode );
894 const Size aSize( maPrefSize );
895
896 *this = aNewBmp;
897
898 maPrefMapMode = aMap;
899 maPrefSize = aSize;
900 }
901
902 return bRet;
903 }
904
905 // ------------------------------------------------------------------------
906
Scale(const double & rScaleX,const double & rScaleY,sal_uInt32 nScaleFlag)907 sal_Bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag )
908 {
909 if(basegfx::fTools::equalZero(rScaleX) || basegfx::fTools::equalZero(rScaleY))
910 {
911 // no scale
912 return true;
913 }
914
915 if(basegfx::fTools::equal(rScaleX, 1.0) && basegfx::fTools::equal(rScaleY, 1.0))
916 {
917 // no scale
918 return true;
919 }
920
921 #ifdef DBG_UTIL
922 // #121233# allow to test the different scalers in debug build with source
923 // level debugger (change nNumber to desired action)
924 static sal_uInt16 nNumber(0);
925 const sal_uInt16 nStartCount(GetBitCount());
926
927 switch(nNumber)
928 {
929 case 0 : break;
930 case 1: nScaleFlag = BMP_SCALE_FAST; break;
931 case 2: nScaleFlag = BMP_SCALE_INTERPOLATE; break;
932 case 3: nScaleFlag = BMP_SCALE_SUPER; break;
933 case 4: nScaleFlag = BMP_SCALE_LANCZOS; break;
934 case 5: nScaleFlag = BMP_SCALE_BICUBIC; break;
935 case 6: nScaleFlag = BMP_SCALE_BILINEAR; break;
936 case 7: nScaleFlag = BMP_SCALE_BOX; break;
937 case 8: nScaleFlag = BMP_SCALE_BESTQUALITY; break;
938 case 9: nScaleFlag = BMP_SCALE_FASTESTINTERPOLATE; break;
939 }
940 #endif // DBG_UTIL
941
942 bool bRetval(false);
943
944 if(BMP_SCALE_BESTQUALITY == nScaleFlag)
945 {
946 // Use LANCZOS when best quality is requested
947 nScaleFlag = BMP_SCALE_LANCZOS;
948 }
949 else if(BMP_SCALE_FASTESTINTERPOLATE == nScaleFlag)
950 {
951 // Use BMP_SCALE_SUPER when speed is requested, but not worst quality
952 nScaleFlag = BMP_SCALE_SUPER;
953 }
954
955 switch(nScaleFlag)
956 {
957 default:
958 case BMP_SCALE_NONE :
959 {
960 bRetval = false;
961 break;
962 }
963 case BMP_SCALE_FAST :
964 {
965 bRetval = ImplScaleFast( rScaleX, rScaleY );
966 break;
967 }
968 case BMP_SCALE_INTERPOLATE :
969 {
970 bRetval = ImplScaleInterpolate( rScaleX, rScaleY );
971 break;
972 }
973 case BMP_SCALE_SUPER :
974 {
975 if(GetSizePixel().Width() < 2 || GetSizePixel().Height() < 2)
976 {
977 // fallback to ImplScaleFast
978 bRetval = ImplScaleFast( rScaleX, rScaleY );
979 }
980 else
981 {
982 // #121233# use method from symphony
983 bRetval = ImplScaleSuper( rScaleX, rScaleY );
984 }
985 break;
986 }
987 case BMP_SCALE_LANCZOS :
988 {
989 const Lanczos3Kernel kernel;
990
991 bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel);
992 break;
993 }
994 case BMP_SCALE_BICUBIC :
995 {
996 const BicubicKernel kernel;
997
998 bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel );
999 break;
1000 }
1001 case BMP_SCALE_BILINEAR :
1002 {
1003 const BilinearKernel kernel;
1004
1005 bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel );
1006 break;
1007 }
1008 case BMP_SCALE_BOX :
1009 {
1010 const BoxKernel kernel;
1011
1012 bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel );
1013 break;
1014 }
1015 }
1016
1017 #ifdef DBG_UTIL
1018 if(bRetval && nStartCount != GetBitCount())
1019 {
1020 OSL_ENSURE(false, "Bitmap::Scale has changed the ColorDepth, this should *not* happen (!)");
1021 }
1022 #endif
1023
1024 return bRetval;
1025 }
1026
1027 // ------------------------------------------------------------------------
1028
Scale(const Size & rNewSize,sal_uInt32 nScaleFlag)1029 sal_Bool Bitmap::Scale( const Size& rNewSize, sal_uInt32 nScaleFlag )
1030 {
1031 const Size aSize( GetSizePixel() );
1032 sal_Bool bRet;
1033
1034 if( aSize.Width() && aSize.Height() )
1035 {
1036 bRet = Scale( (double) rNewSize.Width() / aSize.Width(),
1037 (double) rNewSize.Height() / aSize.Height(),
1038 nScaleFlag );
1039 }
1040 else
1041 bRet = sal_True;
1042
1043 return bRet;
1044 }
1045
1046 // ------------------------------------------------------------------------
1047
AdaptBitCount(Bitmap & rNew) const1048 void Bitmap::AdaptBitCount(Bitmap& rNew) const
1049 {
1050 ImplAdaptBitCount(rNew);
1051 }
1052
1053 // ------------------------------------------------------------------------
1054
ImplAdaptBitCount(Bitmap & rNew) const1055 void Bitmap::ImplAdaptBitCount(Bitmap& rNew) const
1056 {
1057 // aNew is the result of some operation; adapt it's BitCount to the original (this)
1058 if(GetBitCount() != rNew.GetBitCount())
1059 {
1060 switch(GetBitCount())
1061 {
1062 case 1:
1063 {
1064 rNew.Convert(BMP_CONVERSION_1BIT_THRESHOLD);
1065 break;
1066 }
1067 case 4:
1068 {
1069 if(HasGreyPalette())
1070 {
1071 rNew.Convert(BMP_CONVERSION_4BIT_GREYS);
1072 }
1073 else
1074 {
1075 rNew.Convert(BMP_CONVERSION_4BIT_COLORS);
1076 }
1077 break;
1078 }
1079 case 8:
1080 {
1081 if(HasGreyPalette())
1082 {
1083 rNew.Convert(BMP_CONVERSION_8BIT_GREYS);
1084 }
1085 else
1086 {
1087 rNew.Convert(BMP_CONVERSION_8BIT_COLORS);
1088 }
1089 break;
1090 }
1091 case 24:
1092 {
1093 rNew.Convert(BMP_CONVERSION_24BIT);
1094 break;
1095 }
1096 default:
1097 {
1098 OSL_ENSURE(false, "BitDepth adaption failed (!)");
1099 break;
1100 }
1101 }
1102 }
1103 }
1104
1105 // ------------------------------------------------------------------------
1106
ImplScaleFast(const double & rScaleX,const double & rScaleY)1107 sal_Bool Bitmap::ImplScaleFast( const double& rScaleX, const double& rScaleY )
1108 {
1109 const Size aSizePix( GetSizePixel() );
1110 const long nNewWidth = FRound( aSizePix.Width() * rScaleX );
1111 const long nNewHeight = FRound( aSizePix.Height() * rScaleY );
1112 sal_Bool bRet = sal_False;
1113
1114 if( nNewWidth && nNewHeight )
1115 {
1116 BitmapReadAccess* pReadAcc = AcquireReadAccess();
1117 if ( !pReadAcc )
1118 return sal_False;
1119
1120 Bitmap aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() );
1121 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1122
1123 if( pWriteAcc )
1124 {
1125 const long nScanlineSize = pWriteAcc->GetScanlineSize();
1126 const long nNewWidth1 = nNewWidth - 1L;
1127 const long nNewHeight1 = nNewHeight - 1L;
1128 const long nWidth = pReadAcc->Width();
1129 const long nHeight = pReadAcc->Height();
1130 long* pLutX = new long[ nNewWidth ];
1131 long* pLutY = new long[ nNewHeight ];
1132 long nX, nY, nMapY, nActY = 0L;
1133
1134 if( nNewWidth1 && nNewHeight1 )
1135 {
1136 for( nX = 0L; nX < nNewWidth; nX++ )
1137 pLutX[ nX ] = nX * nWidth / nNewWidth;
1138
1139 for( nY = 0L; nY < nNewHeight; nY++ )
1140 pLutY[ nY ] = nY * nHeight / nNewHeight;
1141
1142 while( nActY < nNewHeight )
1143 {
1144 nMapY = pLutY[ nActY ];
1145
1146 for( nX = 0L; nX < nNewWidth; nX++ )
1147 pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) );
1148
1149 while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) )
1150 {
1151 memcpy( pWriteAcc->GetScanline( nActY + 1L ),
1152 pWriteAcc->GetScanline( nActY ), nScanlineSize );
1153 nActY++;
1154 }
1155
1156 nActY++;
1157 }
1158
1159 bRet = sal_True;
1160 }
1161
1162 delete[] pLutX;
1163 delete[] pLutY;
1164 }
1165
1166 ReleaseAccess( pReadAcc );
1167 aNewBmp.ReleaseAccess( pWriteAcc );
1168
1169 if( bRet )
1170 ImplAssignWithSize( aNewBmp );
1171 }
1172
1173 return bRet;
1174 }
1175
1176 // ------------------------------------------------------------------------
1177
ImplScaleInterpolate(const double & rScaleX,const double & rScaleY)1178 sal_Bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY )
1179 {
1180 const Size aSizePix( GetSizePixel() );
1181 const long nNewWidth = FRound( aSizePix.Width() * rScaleX );
1182 const long nNewHeight = FRound( aSizePix.Height() * rScaleY );
1183 sal_Bool bRet = sal_False;
1184
1185 if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) )
1186 {
1187 BitmapColor aCol0;
1188 BitmapColor aCol1;
1189 BitmapReadAccess* pReadAcc = AcquireReadAccess();
1190 long nWidth = pReadAcc->Width();
1191 long nHeight = pReadAcc->Height();
1192 Bitmap aNewBmp( Size( nNewWidth, nHeight ), 24 );
1193 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1194 long* pLutInt;
1195 long* pLutFrac;
1196 long nX, nY;
1197 long lXB0, lXB1, lXG0, lXG1, lXR0, lXR1;
1198 double fTemp;
1199 long nTemp;
1200
1201 if( pReadAcc && pWriteAcc )
1202 {
1203 const long nNewWidth1 = nNewWidth - 1L;
1204 const long nWidth1 = pReadAcc->Width() - 1L;
1205 const double fRevScaleX = (double) nWidth1 / nNewWidth1;
1206
1207 pLutInt = new long[ nNewWidth ];
1208 pLutFrac = new long[ nNewWidth ];
1209
1210 for( nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ )
1211 {
1212 fTemp = nX * fRevScaleX;
1213 pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp );
1214 fTemp -= pLutInt[ nX ];
1215 pLutFrac[ nX ] = (long) ( fTemp * 1024. );
1216 }
1217
1218 for( nY = 0L; nY < nHeight; nY++ )
1219 {
1220 if( 1 == nWidth )
1221 {
1222 if( pReadAcc->HasPalette() )
1223 {
1224 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, 0 ) );
1225 }
1226 else
1227 {
1228 aCol0 = pReadAcc->GetPixel( nY, 0 );
1229 }
1230
1231 for( nX = 0L; nX < nNewWidth; nX++ )
1232 {
1233 pWriteAcc->SetPixel( nY, nX, aCol0 );
1234 }
1235 }
1236 else
1237 {
1238 for( nX = 0L; nX < nNewWidth; nX++ )
1239 {
1240 nTemp = pLutInt[ nX ];
1241
1242 if( pReadAcc->HasPalette() )
1243 {
1244 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp++ ) );
1245 aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp ) );
1246 }
1247 else
1248 {
1249 aCol0 = pReadAcc->GetPixel( nY, nTemp++ );
1250 aCol1 = pReadAcc->GetPixel( nY, nTemp );
1251 }
1252
1253 nTemp = pLutFrac[ nX ];
1254
1255 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1256 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1257 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1258
1259 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1260 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1261 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1262
1263 pWriteAcc->SetPixel( nY, nX, aCol0 );
1264 }
1265 }
1266 }
1267
1268 delete[] pLutInt;
1269 delete[] pLutFrac;
1270 bRet = sal_True;
1271 }
1272
1273 ReleaseAccess( pReadAcc );
1274 aNewBmp.ReleaseAccess( pWriteAcc );
1275
1276 if( bRet )
1277 {
1278 bRet = sal_False;
1279 const Bitmap aOriginal(*this);
1280 *this = aNewBmp;
1281 aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 );
1282 pReadAcc = AcquireReadAccess();
1283 pWriteAcc = aNewBmp.AcquireWriteAccess();
1284
1285 if( pReadAcc && pWriteAcc )
1286 {
1287 const long nNewHeight1 = nNewHeight - 1L;
1288 const long nHeight1 = pReadAcc->Height() - 1L;
1289 const double fRevScaleY = (double) nHeight1 / nNewHeight1;
1290
1291 pLutInt = new long[ nNewHeight ];
1292 pLutFrac = new long[ nNewHeight ];
1293
1294 for( nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ )
1295 {
1296 fTemp = nY * fRevScaleY;
1297 pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp );
1298 fTemp -= pLutInt[ nY ];
1299 pLutFrac[ nY ] = (long) ( fTemp * 1024. );
1300 }
1301
1302 // after 1st step, bitmap *is* 24bit format (see above)
1303 OSL_ENSURE(!pReadAcc->HasPalette(), "OOps, somehow ImplScaleInterpolate in-between format has palette, should not happen (!)");
1304
1305 for( nX = 0L; nX < nNewWidth; nX++ )
1306 {
1307 if( 1 == nHeight )
1308 {
1309 aCol0 = pReadAcc->GetPixel( 0, nX );
1310
1311 for( nY = 0L; nY < nNewHeight; nY++ )
1312 {
1313 pWriteAcc->SetPixel( nY, nX, aCol0 );
1314 }
1315 }
1316 else
1317 {
1318 for( nY = 0L; nY < nNewHeight; nY++ )
1319 {
1320 nTemp = pLutInt[ nY ];
1321
1322 aCol0 = pReadAcc->GetPixel( nTemp++, nX );
1323 aCol1 = pReadAcc->GetPixel( nTemp, nX );
1324
1325 nTemp = pLutFrac[ nY ];
1326
1327 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1328 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1329 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1330
1331 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1332 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1333 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1334
1335 pWriteAcc->SetPixel( nY, nX, aCol0 );
1336 }
1337 }
1338 }
1339
1340 delete[] pLutInt;
1341 delete[] pLutFrac;
1342 bRet = sal_True;
1343 }
1344
1345 ReleaseAccess( pReadAcc );
1346 aNewBmp.ReleaseAccess( pWriteAcc );
1347
1348 if( bRet )
1349 {
1350 aOriginal.ImplAdaptBitCount(aNewBmp);
1351 *this = aNewBmp;
1352 }
1353 }
1354 }
1355
1356 if( !bRet )
1357 {
1358 bRet = ImplScaleFast( rScaleX, rScaleY );
1359 }
1360
1361 return bRet;
1362 }
1363
1364 // ------------------------------------------------------------------------
1365 // #121233# Added BMP_SCALE_SUPER from symphony code
1366
ImplScaleSuper(const double & rScaleX,const double & rScaleY)1367 sal_Bool Bitmap::ImplScaleSuper(
1368 const double& rScaleX,
1369 const double& rScaleY )
1370 {
1371 const Size aSizePix( GetSizePixel() );
1372 bool bHMirr = ( rScaleX < 0 );
1373 bool bVMirr = ( rScaleY < 0 );
1374 double scaleX = bHMirr ? -rScaleX : rScaleX;
1375 double scaleY = bVMirr ? -rScaleY : rScaleY;
1376 const long nDstW = FRound( aSizePix.Width() * scaleX );
1377 const long nDstH = FRound( aSizePix.Height() * scaleY );
1378 const double fScaleThresh = 0.6;
1379 bool bRet = false;
1380
1381 if( ( nDstW > 1L ) && ( nDstH > 1L ) )
1382 {
1383 BitmapColor aCol0, aCol1, aColRes;
1384 BitmapReadAccess* pAcc = AcquireReadAccess();
1385 long nW = pAcc->Width() ;
1386 long nH = pAcc->Height() ;
1387 Bitmap aOutBmp( Size( nDstW, nDstH ), 24 );
1388 BitmapWriteAccess* pWAcc = aOutBmp.AcquireWriteAccess();
1389 long* pMapIX = new long[ nDstW ];
1390 long* pMapIY = new long[ nDstH ];
1391 long* pMapFX = new long[ nDstW ];
1392 long* pMapFY = new long[ nDstH ];
1393 long nX, nY, nXDst, nYDst;;
1394 double fTemp;
1395 long nTemp , nTempX, nTempY, nTempFX, nTempFY;
1396 sal_uInt8 cR0, cG0, cB0, cR1, cG1, cB1;
1397 long nStartX = 0 , nStartY = 0;
1398 long nEndX = nDstW - 1L;
1399 long nEndY = nDstH - 1L;
1400 long nMax = 1 << 7L;
1401
1402 if( pAcc && pWAcc )
1403 {
1404 const double fRevScaleX = ( nDstW > 1L ) ? ( (double) ( nW - 1 ) / ( nDstW - 1 ) ) : 0.0;
1405 const double fRevScaleY = ( nDstH > 1L ) ? ( (double) ( nH - 1 ) / ( nDstH - 1 ) ) : 0.0;
1406
1407 // create horizontal mapping table
1408 for( nX = 0L, nTempX = nW - 1L, nTemp = nW - 2L; nX < nDstW; nX++ )
1409 {
1410 fTemp = nX * fRevScaleX;
1411
1412 if( bHMirr )
1413 fTemp = nTempX - fTemp;
1414
1415 pMapFX[ nX ] = (long) ( ( fTemp - ( pMapIX[ nX ] = MinMax( (long) fTemp, 0, nTemp ) ) ) * 128. );
1416 }
1417
1418 // create vertical mapping table
1419 for( nY = 0L, nTempY = nH - 1L, nTemp = nH - 2L; nY < nDstH; nY++ )
1420 {
1421 fTemp = nY * fRevScaleY;
1422
1423 if( bVMirr )
1424 fTemp = nTempY - fTemp;
1425
1426 pMapFY[ nY ] = (long) ( ( fTemp - ( pMapIY[ nY ] = MinMax( (long) fTemp, 0, nTemp ) ) ) * 128. );
1427 }
1428
1429 if( pAcc->HasPalette() )
1430 {
1431 if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
1432 {
1433 if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
1434 {
1435 Scanline pLine0, pLine1;
1436
1437 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1438 {
1439 nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ];
1440 pLine0 = pAcc->GetScanline( nTempY );
1441 pLine1 = pAcc->GetScanline( ++nTempY );
1442
1443 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1444 {
1445 nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ];
1446
1447 const BitmapColor& rCol0 = pAcc->GetPaletteColor( pLine0[ nTempX ] );
1448 const BitmapColor& rCol2 = pAcc->GetPaletteColor( pLine1[ nTempX ] );
1449 const BitmapColor& rCol1 = pAcc->GetPaletteColor( pLine0[ ++nTempX ] );
1450 const BitmapColor& rCol3 = pAcc->GetPaletteColor( pLine1[ nTempX ] );
1451
1452 cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTempFX );
1453 cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTempFX );
1454 cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTempFX );
1455
1456 cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTempFX );
1457 cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTempFX );
1458 cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTempFX );
1459
1460 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
1461 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
1462 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
1463 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1464 }
1465 }
1466 }
1467 else
1468 {
1469 Scanline pTmpY;
1470 long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
1471 long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
1472 long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
1473
1474 for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1475 {
1476 nTop = bVMirr ? ( nY + 1 ) : nY;
1477 nBottom = bVMirr ? nY : ( nY + 1 ) ;
1478
1479 if( nY ==nEndY )
1480 {
1481 nLineStart = pMapIY[ nY ];
1482 nLineRange = 0;
1483 }
1484 else
1485 {
1486 nLineStart = pMapIY[ nTop ] ;
1487 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
1488 }
1489
1490 for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
1491 {
1492 nLeft = bHMirr ? ( nX + 1 ) : nX;
1493 nRight = bHMirr ? nX : ( nX + 1 ) ;
1494
1495 if( nX == nEndX )
1496 {
1497 nRowStart = pMapIX[ nX ];
1498 nRowRange = 0;
1499 }
1500 else
1501 {
1502 nRowStart = pMapIX[ nLeft ];
1503 nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
1504 }
1505
1506 nSumR = nSumG = nSumB = 0;
1507 nTotalWeightY = 0;
1508
1509 for(int i = 0; i<= nLineRange; i++)
1510 {
1511 pTmpY = pAcc->GetScanline( nLineStart + i );
1512 nSumRowR = nSumRowG = nSumRowB = 0;
1513 nTotalWeightX = 0;
1514
1515 for(int j = 0; j <= nRowRange; j++)
1516 {
1517 const BitmapColor& rCol = pAcc->GetPaletteColor( pTmpY[ nRowStart + j ] );
1518
1519 if(nX == nEndX )
1520 {
1521 nSumRowB += rCol.GetBlue() << 7L;
1522 nSumRowG += rCol.GetGreen() << 7L;
1523 nSumRowR += rCol.GetRed() << 7L;
1524 nTotalWeightX += 1 << 7L;
1525 }
1526 else if( j == 0 )
1527 {
1528 nWeightX = (nMax- pMapFX[ nLeft ]) ;
1529 nSumRowB += ( nWeightX *rCol.GetBlue()) ;
1530 nSumRowG += ( nWeightX *rCol.GetGreen()) ;
1531 nSumRowR += ( nWeightX *rCol.GetRed()) ;
1532 nTotalWeightX += nWeightX;
1533 }
1534 else if ( nRowRange == j )
1535 {
1536 nWeightX = pMapFX[ nRight ] ;
1537 nSumRowB += ( nWeightX *rCol.GetBlue() );
1538 nSumRowG += ( nWeightX *rCol.GetGreen() );
1539 nSumRowR += ( nWeightX *rCol.GetRed() );
1540 nTotalWeightX += nWeightX;
1541 }
1542 else
1543 {
1544 nSumRowB += rCol.GetBlue() << 7L;
1545 nSumRowG += rCol.GetGreen() << 7L;
1546 nSumRowR += rCol.GetRed() << 7L;
1547 nTotalWeightX += 1 << 7L;
1548 }
1549 }
1550
1551 if( nY == nEndY )
1552 nWeightY = nMax;
1553 else if( i == 0 )
1554 nWeightY = nMax - pMapFY[ nTop ];
1555 else if( nLineRange == 1 )
1556 nWeightY = pMapFY[ nTop ];
1557 else if ( nLineRange == i )
1558 nWeightY = pMapFY[ nBottom ];
1559 else
1560 nWeightY = nMax;
1561
1562 nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
1563 nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
1564 nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
1565 nTotalWeightY += nWeightY;
1566 }
1567
1568 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
1569 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
1570 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
1571 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1572
1573 }
1574 }
1575 }
1576 }
1577 else
1578 {
1579 if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
1580 {
1581 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1582 {
1583 nTempY = pMapIY[ nY ], nTempFY = pMapFY[ nY ];
1584
1585 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1586 {
1587 nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ];
1588
1589 aCol0 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY, nTempX ) );
1590 aCol1 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY, ++nTempX ) );
1591 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
1592 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
1593 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
1594
1595 aCol1 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( ++nTempY, nTempX ) );
1596 aCol0 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY--, --nTempX ) );
1597 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
1598 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
1599 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
1600
1601 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
1602 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
1603 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
1604 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1605 }
1606 }
1607
1608 }
1609 else
1610 {
1611 long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
1612 long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
1613 long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
1614
1615 for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1616 {
1617 nTop = bVMirr ? ( nY + 1 ) : nY;
1618 nBottom = bVMirr ? nY : ( nY + 1 ) ;
1619
1620 if( nY ==nEndY )
1621 {
1622 nLineStart = pMapIY[ nY ];
1623 nLineRange = 0;
1624 }
1625 else
1626 {
1627 nLineStart = pMapIY[ nTop ] ;
1628 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
1629 }
1630
1631 for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
1632 {
1633 nLeft = bHMirr ? ( nX + 1 ) : nX;
1634 nRight = bHMirr ? nX : ( nX + 1 ) ;
1635
1636 if( nX == nEndX )
1637 {
1638 nRowStart = pMapIX[ nX ];
1639 nRowRange = 0;
1640 }
1641 else
1642 {
1643 nRowStart = pMapIX[ nLeft ];
1644 nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
1645 }
1646
1647 nSumR = nSumG = nSumB = 0;
1648 nTotalWeightY = 0;
1649
1650 for(int i = 0; i<= nLineRange; i++)
1651 {
1652 nSumRowR = nSumRowG = nSumRowB = 0;
1653 nTotalWeightX = 0;
1654
1655 for(int j = 0; j <= nRowRange; j++)
1656 {
1657 aCol0 = pAcc->GetPaletteColor ( pAcc->GetPixelIndex( nLineStart + i, nRowStart + j ) );
1658
1659 if(nX == nEndX )
1660 {
1661
1662 nSumRowB += aCol0.GetBlue() << 7L;
1663 nSumRowG += aCol0.GetGreen() << 7L;
1664 nSumRowR += aCol0.GetRed() << 7L;
1665 nTotalWeightX += 1 << 7L;
1666 }
1667 else if( j == 0 )
1668 {
1669
1670 nWeightX = (nMax- pMapFX[ nLeft ]) ;
1671 nSumRowB += ( nWeightX *aCol0.GetBlue()) ;
1672 nSumRowG += ( nWeightX *aCol0.GetGreen()) ;
1673 nSumRowR += ( nWeightX *aCol0.GetRed()) ;
1674 nTotalWeightX += nWeightX;
1675 }
1676 else if ( nRowRange == j )
1677 {
1678
1679 nWeightX = pMapFX[ nRight ] ;
1680 nSumRowB += ( nWeightX *aCol0.GetBlue() );
1681 nSumRowG += ( nWeightX *aCol0.GetGreen() );
1682 nSumRowR += ( nWeightX *aCol0.GetRed() );
1683 nTotalWeightX += nWeightX;
1684 }
1685 else
1686 {
1687
1688 nSumRowB += aCol0.GetBlue() << 7L;
1689 nSumRowG += aCol0.GetGreen() << 7L;
1690 nSumRowR += aCol0.GetRed() << 7L;
1691 nTotalWeightX += 1 << 7L;
1692 }
1693 }
1694
1695 if( nY == nEndY )
1696 nWeightY = nMax;
1697 else if( i == 0 )
1698 nWeightY = nMax - pMapFY[ nTop ];
1699 else if( nLineRange == 1 )
1700 nWeightY = pMapFY[ nTop ];
1701 else if ( nLineRange == i )
1702 nWeightY = pMapFY[ nBottom ];
1703 else
1704 nWeightY = nMax;
1705
1706 nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
1707 nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
1708 nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
1709 nTotalWeightY += nWeightY;
1710 }
1711
1712 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
1713 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
1714 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
1715 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1716 }
1717 }
1718 }
1719 }
1720 }
1721 else
1722 {
1723 if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
1724 {
1725 if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
1726 {
1727 Scanline pLine0, pLine1, pTmp0, pTmp1;
1728 long nOff;
1729
1730 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1731 {
1732 nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ];
1733 pLine0 = pAcc->GetScanline( nTempY );
1734 pLine1 = pAcc->GetScanline( ++nTempY );
1735
1736 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1737 {
1738 nOff = 3L * ( nTempX = pMapIX[ nX ] );
1739 nTempFX = pMapFX[ nX ];
1740
1741 pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L;
1742 cB0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1743 cG0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1744 cR0 = MAP( *pTmp0, *pTmp1, nTempFX );
1745
1746 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L;
1747 cB1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1748 cG1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1749 cR1 = MAP( *pTmp0, *pTmp1, nTempFX );
1750
1751 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
1752 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
1753 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
1754 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1755 }
1756 }
1757 }
1758 else
1759 {
1760 Scanline pTmpY, pTmpX;
1761 long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
1762 long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
1763 long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
1764
1765 for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1766 {
1767 nTop = bVMirr ? ( nY + 1 ) : nY;
1768 nBottom = bVMirr ? nY : ( nY + 1 ) ;
1769
1770 if( nY ==nEndY )
1771 {
1772 nLineStart = pMapIY[ nY ];
1773 nLineRange = 0;
1774 }
1775 else
1776 {
1777 nLineStart = pMapIY[ nTop ] ;
1778 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
1779 }
1780
1781 for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
1782 {
1783 nLeft = bHMirr ? ( nX + 1 ) : nX;
1784 nRight = bHMirr ? nX : ( nX + 1 ) ;
1785
1786 if( nX == nEndX )
1787 {
1788 nRowStart = pMapIX[ nX ];
1789 nRowRange = 0;
1790 }
1791 else
1792 {
1793 nRowStart = pMapIX[ nLeft ];
1794 nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
1795 }
1796
1797 nSumR = nSumG = nSumB = 0;
1798 nTotalWeightY = 0;
1799
1800 for(int i = 0; i<= nLineRange; i++)
1801 {
1802 pTmpY = pAcc->GetScanline( nLineStart + i );
1803 pTmpX = pTmpY + 3L * nRowStart;
1804 nSumRowR = nSumRowG = nSumRowB = 0;
1805 nTotalWeightX = 0;
1806
1807 for(int j = 0; j <= nRowRange; j++)
1808 {
1809 if(nX == nEndX )
1810 {
1811 nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
1812 nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
1813 nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
1814 nTotalWeightX += 1 << 7L;
1815 }
1816 else if( j == 0 )
1817 {
1818 nWeightX = (nMax- pMapFX[ nLeft ]) ;
1819 nSumRowB += ( nWeightX *( *pTmpX )) ;pTmpX++;
1820 nSumRowG += ( nWeightX *( *pTmpX )) ;pTmpX++;
1821 nSumRowR += ( nWeightX *( *pTmpX )) ;pTmpX++;
1822 nTotalWeightX += nWeightX;
1823 }
1824 else if ( nRowRange == j )
1825 {
1826 nWeightX = pMapFX[ nRight ] ;
1827 nSumRowB += ( nWeightX *( *pTmpX ) );pTmpX++;
1828 nSumRowG += ( nWeightX *( *pTmpX ) );pTmpX++;
1829 nSumRowR += ( nWeightX *( *pTmpX ) );pTmpX++;
1830 nTotalWeightX += nWeightX;
1831 }
1832 else
1833 {
1834 nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
1835 nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
1836 nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
1837 nTotalWeightX += 1 << 7L;
1838 }
1839 }
1840
1841 if( nY == nEndY )
1842 nWeightY = nMax;
1843 else if( i == 0 )
1844 nWeightY = nMax - pMapFY[ nTop ];
1845 else if( nLineRange == 1 )
1846 nWeightY = pMapFY[ nTop ];
1847 else if ( nLineRange == i )
1848 nWeightY = pMapFY[ nBottom ];
1849 else
1850 nWeightY = nMax;
1851
1852 nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
1853 nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
1854 nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
1855 nTotalWeightY += nWeightY;
1856 }
1857
1858 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
1859 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
1860 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
1861 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1862
1863 }
1864 }
1865 }
1866 }
1867 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
1868 {
1869 if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
1870 {
1871 Scanline pLine0, pLine1, pTmp0, pTmp1;
1872 long nOff;
1873
1874 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1875 {
1876 nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ];
1877 pLine0 = pAcc->GetScanline( nTempY );
1878 pLine1 = pAcc->GetScanline( ++nTempY );
1879
1880 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1881 {
1882 nOff = 3L * ( nTempX = pMapIX[ nX ] );
1883 nTempFX = pMapFX[ nX ];
1884
1885 pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L;
1886 cR0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1887 cG0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1888 cB0 = MAP( *pTmp0, *pTmp1, nTempFX );
1889
1890 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L;
1891 cR1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1892 cG1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++;
1893 cB1 = MAP( *pTmp0, *pTmp1, nTempFX );
1894
1895 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
1896 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
1897 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
1898 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1899 }
1900 }
1901 }
1902 else
1903 {
1904 Scanline pTmpY, pTmpX;
1905 long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
1906 long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
1907 long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
1908
1909 for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1910 {
1911 nTop = bVMirr ? ( nY + 1 ) : nY;
1912 nBottom = bVMirr ? nY : ( nY + 1 ) ;
1913
1914 if( nY ==nEndY )
1915 {
1916 nLineStart = pMapIY[ nY ];
1917 nLineRange = 0;
1918 }
1919 else
1920 {
1921 nLineStart = pMapIY[ nTop ] ;
1922 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
1923 }
1924
1925 for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
1926 {
1927 nLeft = bHMirr ? ( nX + 1 ) : nX;
1928 nRight = bHMirr ? nX : ( nX + 1 ) ;
1929
1930 if( nX == nEndX )
1931 {
1932 nRowStart = pMapIX[ nX ];
1933 nRowRange = 0;
1934 }
1935 else
1936 {
1937 nRowStart = pMapIX[ nLeft ];
1938 nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
1939 }
1940
1941 nSumR = nSumG = nSumB = 0;
1942 nTotalWeightY = 0;
1943
1944 for(int i = 0; i<= nLineRange; i++)
1945 {
1946 pTmpY = pAcc->GetScanline( nLineStart + i );
1947 pTmpX = pTmpY + 3L * nRowStart;
1948 nSumRowR = nSumRowG = nSumRowB = 0;
1949 nTotalWeightX = 0;
1950
1951 for(int j = 0; j <= nRowRange; j++)
1952 {
1953 if(nX == nEndX )
1954 {
1955 nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
1956 nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
1957 nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
1958 nTotalWeightX += 1 << 7L;
1959 }
1960 else if( j == 0 )
1961 {
1962 nWeightX = (nMax- pMapFX[ nLeft ]) ;
1963 nSumRowR += ( nWeightX *( *pTmpX )) ;pTmpX++;
1964 nSumRowG += ( nWeightX *( *pTmpX )) ;pTmpX++;
1965 nSumRowB += ( nWeightX *( *pTmpX )) ;pTmpX++;
1966 nTotalWeightX += nWeightX;
1967 }
1968 else if ( nRowRange == j )
1969 {
1970 nWeightX = pMapFX[ nRight ] ;
1971 nSumRowR += ( nWeightX *( *pTmpX ) );pTmpX++;
1972 nSumRowG += ( nWeightX *( *pTmpX ) );pTmpX++;
1973 nSumRowB += ( nWeightX *( *pTmpX ) );pTmpX++;
1974 nTotalWeightX += nWeightX;
1975 }
1976 else
1977 {
1978 nSumRowR += ( *pTmpX ) << 7L;pTmpX++;
1979 nSumRowG += ( *pTmpX ) << 7L;pTmpX++;
1980 nSumRowB += ( *pTmpX ) << 7L;pTmpX++;
1981 nTotalWeightX += 1 << 7L;
1982 }
1983 }
1984
1985 if( nY == nEndY )
1986 nWeightY = nMax;
1987 else if( i == 0 )
1988 nWeightY = nMax - pMapFY[ nTop ];
1989 else if( nLineRange == 1 )
1990 nWeightY = pMapFY[ nTop ];
1991 else if ( nLineRange == i )
1992 nWeightY = pMapFY[ nBottom ];
1993 else
1994 nWeightY = nMax;
1995
1996 nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
1997 nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
1998 nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
1999 nTotalWeightY += nWeightY;
2000 }
2001
2002 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
2003 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
2004 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
2005 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
2006
2007 }
2008 }
2009 }
2010 }
2011 else
2012 {
2013 if( scaleX >= fScaleThresh && scaleY >= fScaleThresh )
2014 {
2015 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
2016 {
2017 nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ];
2018
2019 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
2020 {
2021 nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ];
2022
2023 aCol0 = pAcc->GetPixel( nTempY, nTempX );
2024 aCol1 = pAcc->GetPixel( nTempY, ++nTempX );
2025 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
2026 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
2027 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
2028
2029 aCol1 = pAcc->GetPixel( ++nTempY, nTempX );
2030 aCol0 = pAcc->GetPixel( nTempY--, --nTempX );
2031 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX );
2032 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX );
2033 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX );
2034
2035 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) );
2036 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) );
2037 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) );
2038 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
2039 }
2040 }
2041 }
2042 else
2043 {
2044 long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ;
2045 long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ;
2046 long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY;
2047
2048 for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
2049 {
2050 nTop = bVMirr ? ( nY + 1 ) : nY;
2051 nBottom = bVMirr ? nY : ( nY + 1 ) ;
2052
2053 if( nY ==nEndY )
2054 {
2055 nLineStart = pMapIY[ nY ];
2056 nLineRange = 0;
2057 }
2058 else
2059 {
2060 nLineStart = pMapIY[ nTop ] ;
2061 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] );
2062 }
2063
2064 for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ )
2065 {
2066 nLeft = bHMirr ? ( nX + 1 ) : nX;
2067 nRight = bHMirr ? nX : ( nX + 1 ) ;
2068
2069 if( nX == nEndX )
2070 {
2071 nRowStart = pMapIX[ nX ];
2072 nRowRange = 0;
2073 }
2074 else
2075 {
2076 nRowStart = pMapIX[ nLeft ];
2077 nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] );
2078 }
2079
2080 nSumR = nSumG = nSumB = 0;
2081 nTotalWeightY = 0;
2082
2083 for(int i = 0; i<= nLineRange; i++)
2084 {
2085 nSumRowR = nSumRowG = nSumRowB = 0;
2086 nTotalWeightX = 0;
2087
2088 for(int j = 0; j <= nRowRange; j++)
2089 {
2090 aCol0 = pAcc->GetPixel( nLineStart + i, nRowStart + j );
2091
2092 if(nX == nEndX )
2093 {
2094
2095 nSumRowB += aCol0.GetBlue() << 7L;
2096 nSumRowG += aCol0.GetGreen() << 7L;
2097 nSumRowR += aCol0.GetRed() << 7L;
2098 nTotalWeightX += 1 << 7L;
2099 }
2100 else if( j == 0 )
2101 {
2102
2103 nWeightX = (nMax- pMapFX[ nLeft ]) ;
2104 nSumRowB += ( nWeightX *aCol0.GetBlue()) ;
2105 nSumRowG += ( nWeightX *aCol0.GetGreen()) ;
2106 nSumRowR += ( nWeightX *aCol0.GetRed()) ;
2107 nTotalWeightX += nWeightX;
2108 }
2109 else if ( nRowRange == j )
2110 {
2111
2112 nWeightX = pMapFX[ nRight ] ;
2113 nSumRowB += ( nWeightX *aCol0.GetBlue() );
2114 nSumRowG += ( nWeightX *aCol0.GetGreen() );
2115 nSumRowR += ( nWeightX *aCol0.GetRed() );
2116 nTotalWeightX += nWeightX;
2117 }
2118 else
2119 {
2120 nSumRowB += aCol0.GetBlue() << 7L;
2121 nSumRowG += aCol0.GetGreen() << 7L;
2122 nSumRowR += aCol0.GetRed() << 7L;
2123 nTotalWeightX += 1 << 7L;
2124 }
2125 }
2126
2127 if( nY == nEndY )
2128 nWeightY = nMax;
2129 else if( i == 0 )
2130 nWeightY = nMax - pMapFY[ nTop ];
2131 else if( nLineRange == 1 )
2132 nWeightY = pMapFY[ nTop ];
2133 else if ( nLineRange == i )
2134 nWeightY = pMapFY[ nBottom ];
2135 else
2136 nWeightY = nMax;
2137
2138 nSumB += nWeightY * ( nSumRowB / nTotalWeightX );
2139 nSumG += nWeightY * ( nSumRowG / nTotalWeightX );
2140 nSumR += nWeightY * ( nSumRowR / nTotalWeightX );
2141 nTotalWeightY += nWeightY;
2142 }
2143
2144 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) ));
2145 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) ));
2146 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) ));
2147 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
2148
2149 }
2150 }
2151 }
2152 }
2153 }
2154
2155 bRet = true;
2156 }
2157
2158 delete[] pMapIX;
2159 delete[] pMapIY;
2160 delete[] pMapFX;
2161 delete[] pMapFY;
2162
2163 ReleaseAccess( pAcc );
2164 aOutBmp.ReleaseAccess( pWAcc );
2165
2166 if( bRet )
2167 {
2168 ImplAdaptBitCount(aOutBmp);
2169 ImplAssignWithSize(aOutBmp);
2170 }
2171
2172 if( !bRet )
2173 bRet = ImplScaleFast( scaleX, scaleY );
2174 }
2175
2176 return bRet;
2177 }
2178
2179 //-----------------------------------------------------------------------------------
2180
2181 namespace
2182 {
ImplCalculateContributions(const sal_uInt32 aSourceSize,const sal_uInt32 aDestinationSize,sal_uInt32 & aNumberOfContributions,double * & pWeights,sal_uInt32 * & pPixels,sal_uInt32 * & pCount,const Kernel & aKernel)2183 void ImplCalculateContributions(
2184 const sal_uInt32 aSourceSize,
2185 const sal_uInt32 aDestinationSize,
2186 sal_uInt32& aNumberOfContributions,
2187 double*& pWeights,
2188 sal_uInt32*& pPixels,
2189 sal_uInt32*& pCount,
2190 const Kernel& aKernel)
2191 {
2192 const double fSamplingRadius(aKernel.GetWidth());
2193 const double fScale(aDestinationSize / static_cast< double >(aSourceSize));
2194 const double fScaledRadius((fScale < 1.0) ? fSamplingRadius / fScale : fSamplingRadius);
2195 const double fFilterFactor((fScale < 1.0) ? fScale : 1.0);
2196
2197 aNumberOfContributions = (static_cast< sal_uInt32 >(fabs(ceil(fScaledRadius))) * 2) + 1;
2198 const sal_uInt32 nAllocSize(aDestinationSize * aNumberOfContributions);
2199 pWeights = new double[nAllocSize];
2200 pPixels = new sal_uInt32[nAllocSize];
2201 pCount = new sal_uInt32[aDestinationSize];
2202
2203 for(sal_uInt32 i(0); i < aDestinationSize; i++)
2204 {
2205 const sal_uInt32 aIndex(i * aNumberOfContributions);
2206 const double aCenter(i / fScale);
2207 const sal_Int32 aLeft(static_cast< sal_Int32 >(floor(aCenter - fScaledRadius)));
2208 const sal_Int32 aRight(static_cast< sal_Int32 >(ceil(aCenter + fScaledRadius)));
2209 sal_uInt32 aCurrentCount(0);
2210
2211 for(sal_Int32 j(aLeft); j <= aRight; j++)
2212 {
2213 const double aWeight(aKernel.Calculate(fFilterFactor * (aCenter - static_cast< double>(j))));
2214
2215 // Reduce calculations with ignoring weights of 0.0
2216 if(fabs(aWeight) < 0.0001)
2217 {
2218 continue;
2219 }
2220
2221 // Handling on edges
2222 const sal_uInt32 aPixelIndex(MinMax(j, 0, aSourceSize - 1));
2223 const sal_uInt32 nIndex(aIndex + aCurrentCount);
2224
2225 pWeights[nIndex] = aWeight;
2226 pPixels[nIndex] = aPixelIndex;
2227
2228 aCurrentCount++;
2229 }
2230
2231 pCount[i] = aCurrentCount;
2232 }
2233 }
2234
ImplScaleConvolutionHor(Bitmap & rSource,Bitmap & rTarget,const double & rScaleX,const Kernel & aKernel)2235 sal_Bool ImplScaleConvolutionHor(
2236 Bitmap& rSource,
2237 Bitmap& rTarget,
2238 const double& rScaleX,
2239 const Kernel& aKernel)
2240 {
2241 // Do horizontal filtering
2242 OSL_ENSURE(rScaleX > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
2243 const sal_uInt32 nWidth(rSource.GetSizePixel().Width());
2244 const sal_uInt32 nNewWidth(FRound(nWidth * rScaleX));
2245
2246 if(nWidth == nNewWidth)
2247 {
2248 return true;
2249 }
2250
2251 BitmapReadAccess* pReadAcc = rSource.AcquireReadAccess();
2252
2253 if(pReadAcc)
2254 {
2255 double* pWeights = 0;
2256 sal_uInt32* pPixels = 0;
2257 sal_uInt32* pCount = 0;
2258 sal_uInt32 aNumberOfContributions(0);
2259
2260 const sal_uInt32 nHeight(rSource.GetSizePixel().Height());
2261 ImplCalculateContributions(nWidth, nNewWidth, aNumberOfContributions, pWeights, pPixels, pCount, aKernel);
2262 rTarget = Bitmap(Size(nNewWidth, nHeight), 24);
2263 BitmapWriteAccess* pWriteAcc = rTarget.AcquireWriteAccess();
2264 bool bResult(0 != pWriteAcc);
2265
2266 if(bResult)
2267 {
2268 for(sal_uInt32 y(0); y < nHeight; y++)
2269 {
2270 for(sal_uInt32 x(0); x < nNewWidth; x++)
2271 {
2272 const sal_uInt32 aBaseIndex(x * aNumberOfContributions);
2273 double aSum(0.0);
2274 double aValueRed(0.0);
2275 double aValueGreen(0.0);
2276 double aValueBlue(0.0);
2277
2278 for(sal_uInt32 j(0); j < pCount[x]; j++)
2279 {
2280 const sal_uInt32 aIndex(aBaseIndex + j);
2281 const double aWeight(pWeights[aIndex]);
2282 BitmapColor aColor;
2283
2284 aSum += aWeight;
2285
2286 if(pReadAcc->HasPalette())
2287 {
2288 aColor = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(y, pPixels[aIndex]));
2289 }
2290 else
2291 {
2292 aColor = pReadAcc->GetPixel(y, pPixels[aIndex]);
2293 }
2294
2295 aValueRed += aWeight * aColor.GetRed();
2296 aValueGreen += aWeight * aColor.GetGreen();
2297 aValueBlue += aWeight * aColor.GetBlue();
2298 }
2299
2300 const BitmapColor aResultColor(
2301 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)),
2302 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)),
2303 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255)));
2304
2305 pWriteAcc->SetPixel(y, x, aResultColor);
2306 }
2307 }
2308
2309 rTarget.ReleaseAccess(pWriteAcc);
2310 }
2311
2312 rSource.ReleaseAccess(pReadAcc);
2313 delete[] pWeights;
2314 delete[] pCount;
2315 delete[] pPixels;
2316
2317 if(bResult)
2318 {
2319 return true;
2320 }
2321 }
2322
2323 return false;
2324 }
2325
ImplScaleConvolutionVer(Bitmap & rSource,Bitmap & rTarget,const double & rScaleY,const Kernel & aKernel)2326 bool ImplScaleConvolutionVer(
2327 Bitmap& rSource,
2328 Bitmap& rTarget,
2329 const double& rScaleY,
2330 const Kernel& aKernel)
2331 {
2332 // Do vertical filtering
2333 OSL_ENSURE(rScaleY > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
2334 const sal_uInt32 nHeight(rSource.GetSizePixel().Height());
2335 const sal_uInt32 nNewHeight(FRound(nHeight * rScaleY));
2336
2337 if(nHeight == nNewHeight)
2338 {
2339 return true;
2340 }
2341
2342 BitmapReadAccess* pReadAcc = rSource.AcquireReadAccess();
2343
2344 if(pReadAcc)
2345 {
2346 double* pWeights = 0;
2347 sal_uInt32* pPixels = 0;
2348 sal_uInt32* pCount = 0;
2349 sal_uInt32 aNumberOfContributions(0);
2350
2351 const sal_uInt32 nWidth(rSource.GetSizePixel().Width());
2352 ImplCalculateContributions(nHeight, nNewHeight, aNumberOfContributions, pWeights, pPixels, pCount, aKernel);
2353 rTarget = Bitmap(Size(nWidth, nNewHeight), 24);
2354 BitmapWriteAccess* pWriteAcc = rTarget.AcquireWriteAccess();
2355 bool bResult(0 != pWriteAcc);
2356
2357 if(pWriteAcc)
2358 {
2359 for(sal_uInt32 x(0); x < nWidth; x++)
2360 {
2361 for(sal_uInt32 y(0); y < nNewHeight; y++)
2362 {
2363 const sal_uInt32 aBaseIndex(y * aNumberOfContributions);
2364 double aSum(0.0);
2365 double aValueRed(0.0);
2366 double aValueGreen(0.0);
2367 double aValueBlue(0.0);
2368
2369 for(sal_uInt32 j(0); j < pCount[y]; j++)
2370 {
2371 const sal_uInt32 aIndex(aBaseIndex + j);
2372 const double aWeight(pWeights[aIndex]);
2373 BitmapColor aColor;
2374
2375 aSum += aWeight;
2376
2377 if(pReadAcc->HasPalette())
2378 {
2379 aColor = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(pPixels[aIndex], x));
2380 }
2381 else
2382 {
2383 aColor = pReadAcc->GetPixel(pPixels[aIndex], x);
2384 }
2385
2386 aValueRed += aWeight * aColor.GetRed();
2387 aValueGreen += aWeight * aColor.GetGreen();
2388 aValueBlue += aWeight * aColor.GetBlue();
2389 }
2390
2391 const BitmapColor aResultColor(
2392 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)),
2393 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)),
2394 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255)));
2395
2396 if(pWriteAcc->HasPalette())
2397 {
2398 pWriteAcc->SetPixelIndex(y, x, static_cast< sal_uInt8 >(pWriteAcc->GetBestPaletteIndex(aResultColor)));
2399 }
2400 else
2401 {
2402 pWriteAcc->SetPixel(y, x, aResultColor);
2403 }
2404 }
2405 }
2406 }
2407
2408 rTarget.ReleaseAccess(pWriteAcc);
2409 rSource.ReleaseAccess(pReadAcc);
2410
2411 delete[] pWeights;
2412 delete[] pCount;
2413 delete[] pPixels;
2414
2415 if(bResult)
2416 {
2417 return true;
2418 }
2419 }
2420
2421 return false;
2422 }
2423 }
2424
2425 // #121233# Added BMP_SCALE_LANCZOS, BMP_SCALE_BICUBIC, BMP_SCALE_BILINEAR and
2426 // BMP_SCALE_BOX derived from the original commit from Toma� Vajngerl (see
2427 // bugzilla task for deitails) Thanks!
ImplScaleConvolution(const double & rScaleX,const double & rScaleY,const Kernel & aKernel)2428 sal_Bool Bitmap::ImplScaleConvolution(
2429 const double& rScaleX,
2430 const double& rScaleY,
2431 const Kernel& aKernel)
2432 {
2433 const bool bMirrorHor(rScaleX < 0.0);
2434 const bool bMirrorVer(rScaleY < 0.0);
2435 const double fScaleX(bMirrorHor ? -rScaleX : rScaleX);
2436 const double fScaleY(bMirrorVer ? -rScaleY : rScaleY);
2437 const sal_uInt32 nWidth(GetSizePixel().Width());
2438 const sal_uInt32 nHeight(GetSizePixel().Height());
2439 const sal_uInt32 nNewWidth(FRound(nWidth * fScaleX));
2440 const sal_uInt32 nNewHeight(FRound(nHeight * fScaleY));
2441 const bool bScaleHor(nWidth != nNewWidth);
2442 const bool bScaleVer(nHeight != nNewHeight);
2443 const bool bMirror(bMirrorHor || bMirrorVer);
2444
2445 if(!bMirror && !bScaleHor && !bScaleVer)
2446 {
2447 return true;
2448 }
2449
2450 bool bResult(true);
2451 sal_uInt32 nMirrorFlags(BMP_MIRROR_NONE);
2452 bool bMirrorAfter(false);
2453
2454 if(bMirror)
2455 {
2456 if(bMirrorHor)
2457 {
2458 nMirrorFlags |= BMP_MIRROR_HORZ;
2459 }
2460
2461 if(bMirrorVer)
2462 {
2463 nMirrorFlags |= BMP_MIRROR_VERT;
2464 }
2465
2466 const sal_uInt32 nStartSize(nWidth * nHeight);
2467 const sal_uInt32 nEndSize(nNewWidth * nNewHeight);
2468
2469 bMirrorAfter = nStartSize > nEndSize;
2470
2471 if(!bMirrorAfter)
2472 {
2473 bResult = Mirror(nMirrorFlags);
2474 }
2475 }
2476
2477 Bitmap aResult;
2478
2479 if(bResult)
2480 {
2481 const sal_uInt32 nInBetweenSizeHorFirst(nHeight * nNewWidth);
2482 const sal_uInt32 nInBetweenSizeVerFirst(nNewHeight * nWidth);
2483 Bitmap aSource(*this);
2484
2485 if(nInBetweenSizeHorFirst < nInBetweenSizeVerFirst)
2486 {
2487 if(bScaleHor)
2488 {
2489 bResult = ImplScaleConvolutionHor(aSource, aResult, fScaleX, aKernel);
2490 }
2491
2492 if(bResult && bScaleVer)
2493 {
2494 if(bScaleHor)
2495 {
2496 // copy partial result, independent of color depth
2497 aSource = aResult;
2498 }
2499
2500 bResult = ImplScaleConvolutionVer(aSource, aResult, fScaleY, aKernel);
2501 }
2502 }
2503 else
2504 {
2505 if(bScaleVer)
2506 {
2507 bResult = ImplScaleConvolutionVer(aSource, aResult, fScaleY, aKernel);
2508 }
2509
2510 if(bResult && bScaleHor)
2511 {
2512 if(bScaleVer)
2513 {
2514 // copy partial result, independent of color depth
2515 aSource = aResult;
2516 }
2517
2518 bResult = ImplScaleConvolutionHor(aSource, aResult, fScaleX, aKernel);
2519 }
2520 }
2521 }
2522
2523 if(bResult && bMirrorAfter)
2524 {
2525 bResult = aResult.Mirror(nMirrorFlags);
2526 }
2527
2528 if(bResult)
2529 {
2530 ImplAdaptBitCount(aResult);
2531 *this = aResult;
2532 }
2533
2534 return bResult;
2535 }
2536
2537 // ------------------------------------------------------------------------
2538
Dither(sal_uLong nDitherFlags)2539 sal_Bool Bitmap::Dither( sal_uLong nDitherFlags )
2540 {
2541 sal_Bool bRet = sal_False;
2542
2543 const Size aSizePix( GetSizePixel() );
2544
2545 if( aSizePix.Width() == 1 || aSizePix.Height() == 1 )
2546 bRet = sal_True;
2547 else if( nDitherFlags & BMP_DITHER_MATRIX )
2548 bRet = ImplDitherMatrix();
2549 else if( nDitherFlags & BMP_DITHER_FLOYD )
2550 bRet = ImplDitherFloyd();
2551 else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) )
2552 bRet = ImplDitherFloyd16();
2553
2554 return bRet;
2555 }
2556
2557 // ------------------------------------------------------------------------
2558
ImplDitherMatrix()2559 sal_Bool Bitmap::ImplDitherMatrix()
2560 {
2561 BitmapReadAccess* pReadAcc = AcquireReadAccess();
2562 Bitmap aNewBmp( GetSizePixel(), 8 );
2563 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
2564 sal_Bool bRet = sal_False;
2565
2566 if( pReadAcc && pWriteAcc )
2567 {
2568 const sal_uLong nWidth = pReadAcc->Width();
2569 const sal_uLong nHeight = pReadAcc->Height();
2570 BitmapColor aIndex( (sal_uInt8) 0 );
2571
2572 if( pReadAcc->HasPalette() )
2573 {
2574 for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
2575 {
2576 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
2577 {
2578 const BitmapColor aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) );
2579 const sal_uLong nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
2580 const sal_uLong nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
2581 const sal_uLong nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
2582 const sal_uLong nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
2583
2584 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
2585 pWriteAcc->SetPixel( nY, nX, aIndex );
2586 }
2587 }
2588 }
2589 else
2590 {
2591 for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
2592 {
2593 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
2594 {
2595 const BitmapColor aCol( pReadAcc->GetPixel( nY, nX ) );
2596 const sal_uLong nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
2597 const sal_uLong nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
2598 const sal_uLong nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
2599 const sal_uLong nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
2600
2601 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
2602 pWriteAcc->SetPixel( nY, nX, aIndex );
2603 }
2604 }
2605 }
2606
2607 bRet = sal_True;
2608 }
2609
2610 ReleaseAccess( pReadAcc );
2611 aNewBmp.ReleaseAccess( pWriteAcc );
2612
2613 if( bRet )
2614 {
2615 const MapMode aMap( maPrefMapMode );
2616 const Size aSize( maPrefSize );
2617
2618 *this = aNewBmp;
2619
2620 maPrefMapMode = aMap;
2621 maPrefSize = aSize;
2622 }
2623
2624 return bRet;
2625 }
2626
2627 // ------------------------------------------------------------------------
2628
ImplDitherFloyd()2629 sal_Bool Bitmap::ImplDitherFloyd()
2630 {
2631 const Size aSize( GetSizePixel() );
2632 sal_Bool bRet = sal_False;
2633
2634 if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) )
2635 {
2636 BitmapReadAccess* pReadAcc = AcquireReadAccess();
2637 Bitmap aNewBmp( GetSizePixel(), 8 );
2638 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
2639
2640 if( pReadAcc && pWriteAcc )
2641 {
2642 BitmapColor aColor;
2643 long nWidth = pReadAcc->Width();
2644 long nWidth1 = nWidth - 1L;
2645 long nHeight = pReadAcc->Height();
2646 long nX;
2647 long nW = nWidth * 3L;
2648 long nW2 = nW - 3L;
2649 long nRErr, nGErr, nBErr;
2650 long nRC, nGC, nBC;
2651 long nTemp;
2652 long nZ;
2653 long* p1 = new long[ nW ];
2654 long* p2 = new long[ nW ];
2655 long* p1T = p1;
2656 long* p2T = p2;
2657 long* pTmp;
2658 sal_Bool bPal = pReadAcc->HasPalette();
2659
2660 pTmp = p2T;
2661
2662 if( bPal )
2663 {
2664 for( nZ = 0; nZ < nWidth; nZ++ )
2665 {
2666 aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( 0, nZ ) );
2667
2668 *pTmp++ = (long) aColor.GetBlue() << 12;
2669 *pTmp++ = (long) aColor.GetGreen() << 12;
2670 *pTmp++ = (long) aColor.GetRed() << 12;
2671 }
2672 }
2673 else
2674 {
2675 for( nZ = 0; nZ < nWidth; nZ++ )
2676 {
2677 aColor = pReadAcc->GetPixel( 0, nZ );
2678
2679 *pTmp++ = (long) aColor.GetBlue() << 12;
2680 *pTmp++ = (long) aColor.GetGreen() << 12;
2681 *pTmp++ = (long) aColor.GetRed() << 12;
2682 }
2683 }
2684
2685 for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ )
2686 {
2687 pTmp = p1T;
2688 p1T = p2T;
2689 p2T = pTmp;
2690
2691 if( nY < nHeight )
2692 {
2693 if( bPal )
2694 {
2695 for( nZ = 0; nZ < nWidth; nZ++ )
2696 {
2697 aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nZ ) );
2698
2699 *pTmp++ = (long) aColor.GetBlue() << 12;
2700 *pTmp++ = (long) aColor.GetGreen() << 12;
2701 *pTmp++ = (long) aColor.GetRed() << 12;
2702 }
2703 }
2704 else
2705 {
2706 for( nZ = 0; nZ < nWidth; nZ++ )
2707 {
2708 aColor = pReadAcc->GetPixel( nY, nZ );
2709
2710 *pTmp++ = (long) aColor.GetBlue() << 12;
2711 *pTmp++ = (long) aColor.GetGreen() << 12;
2712 *pTmp++ = (long) aColor.GetRed() << 12;
2713 }
2714 }
2715 }
2716
2717 // erstes Pixel gesondert betrachten
2718 nX = 0;
2719 CALC_ERRORS;
2720 CALC_TABLES7;
2721 nX -= 5;
2722 CALC_TABLES5;
2723 pWriteAcc->SetPixelIndex( nYAcc, 0, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
2724
2725 // mittlere Pixel ueber Schleife
2726 long nXAcc;
2727 for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ )
2728 {
2729 CALC_ERRORS;
2730 CALC_TABLES7;
2731 nX -= 8;
2732 CALC_TABLES3;
2733 CALC_TABLES5;
2734 pWriteAcc->SetPixelIndex( nYAcc, nXAcc, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
2735 }
2736
2737 // letztes Pixel gesondert betrachten
2738 CALC_ERRORS;
2739 nX -= 5;
2740 CALC_TABLES3;
2741 CALC_TABLES5;
2742 pWriteAcc->SetPixelIndex( nYAcc, nWidth1, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
2743 }
2744
2745 delete[] p1;
2746 delete[] p2;
2747 bRet = sal_True;
2748 }
2749
2750 ReleaseAccess( pReadAcc );
2751 aNewBmp.ReleaseAccess( pWriteAcc );
2752
2753 if( bRet )
2754 {
2755 const MapMode aMap( maPrefMapMode );
2756 const Size aPrefSize( maPrefSize );
2757
2758 *this = aNewBmp;
2759
2760 maPrefMapMode = aMap;
2761 maPrefSize = aPrefSize;
2762 }
2763 }
2764
2765 return bRet;
2766 }
2767
2768 // ------------------------------------------------------------------------
2769
ImplDitherFloyd16()2770 sal_Bool Bitmap::ImplDitherFloyd16()
2771 {
2772 BitmapReadAccess* pReadAcc = AcquireReadAccess();
2773 Bitmap aNewBmp( GetSizePixel(), 24 );
2774 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
2775 sal_Bool bRet = sal_False;
2776
2777 if( pReadAcc && pWriteAcc )
2778 {
2779 const long nWidth = pWriteAcc->Width();
2780 const long nWidth1 = nWidth - 1L;
2781 const long nHeight = pWriteAcc->Height();
2782 BitmapColor aColor;
2783 BitmapColor aBestCol;
2784 ImpErrorQuad aErrQuad;
2785 ImpErrorQuad* pErrQuad1 = new ImpErrorQuad[ nWidth ];
2786 ImpErrorQuad* pErrQuad2 = new ImpErrorQuad[ nWidth ];
2787 ImpErrorQuad* pQLine1 = pErrQuad1;
2788 ImpErrorQuad* pQLine2 = 0;
2789 long nX, nY;
2790 long nYTmp = 0L;
2791 sal_Bool bQ1 = sal_True;
2792
2793 for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
2794 for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
2795 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
2796
2797 for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
2798 {
2799 // erstes ZeilenPixel
2800 aBestCol = pQLine1[ 0 ].ImplGetColor();
2801 aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
2802 aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
2803 aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
2804 pWriteAcc->SetPixel( nY, 0, aBestCol );
2805
2806 for( nX = 1L; nX < nWidth1; nX++ )
2807 {
2808 aColor = pQLine1[ nX ].ImplGetColor();
2809 aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 );
2810 aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 );
2811 aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 );
2812 aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol );
2813 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
2814 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
2815 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
2816 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
2817 pWriteAcc->SetPixel( nY, nX, aBestCol );
2818 }
2819
2820 // letztes ZeilenPixel
2821 aBestCol = pQLine1[ nWidth1 ].ImplGetColor();
2822 aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
2823 aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
2824 aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
2825 pWriteAcc->SetPixel( nY, nX, aBestCol );
2826
2827 // Zeilenpuffer neu fuellen/kopieren
2828 pQLine1 = pQLine2;
2829 pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
2830
2831 if( nYTmp < nHeight )
2832 for( nX = 0L; nX < nWidth; nX++ )
2833 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
2834 }
2835
2836 // Zeilenpuffer zerstoeren
2837 delete[] pErrQuad1;
2838 delete[] pErrQuad2;
2839 bRet = sal_True;
2840 }
2841
2842 ReleaseAccess( pReadAcc );
2843 aNewBmp.ReleaseAccess( pWriteAcc );
2844
2845 if( bRet )
2846 {
2847 const MapMode aMap( maPrefMapMode );
2848 const Size aSize( maPrefSize );
2849
2850 *this = aNewBmp;
2851
2852 maPrefMapMode = aMap;
2853 maPrefSize = aSize;
2854 }
2855
2856 return bRet;
2857 }
2858
2859 // ------------------------------------------------------------------------
2860
ReduceColors(sal_uInt16 nColorCount,BmpReduce eReduce)2861 sal_Bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce )
2862 {
2863 sal_Bool bRet;
2864
2865 if( GetColorCount() <= (sal_uLong) nColorCount )
2866 bRet = sal_True;
2867 else if( nColorCount )
2868 {
2869 if( BMP_REDUCE_SIMPLE == eReduce )
2870 bRet = ImplReduceSimple( nColorCount );
2871 else if( BMP_REDUCE_POPULAR == eReduce )
2872 bRet = ImplReducePopular( nColorCount );
2873 else
2874 bRet = ImplReduceMedian( nColorCount );
2875 }
2876 else
2877 bRet = sal_False;
2878
2879 return bRet;
2880 }
2881
2882 // ------------------------------------------------------------------------
2883
ImplReduceSimple(sal_uInt16 nColorCount)2884 sal_Bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount )
2885 {
2886 Bitmap aNewBmp;
2887 BitmapReadAccess* pRAcc = AcquireReadAccess();
2888 const sal_uInt16 nColCount = Min( nColorCount, (sal_uInt16) 256 );
2889 sal_uInt16 nBitCount;
2890 sal_Bool bRet = sal_False;
2891
2892 if( nColCount <= 2 )
2893 nBitCount = 1;
2894 else if( nColCount <= 16 )
2895 nBitCount = 4;
2896 else
2897 nBitCount = 8;
2898
2899 if( pRAcc )
2900 {
2901 Octree aOct( *pRAcc, nColCount );
2902 const BitmapPalette& rPal = aOct.GetPalette();
2903 BitmapWriteAccess* pWAcc;
2904
2905 aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal );
2906 pWAcc = aNewBmp.AcquireWriteAccess();
2907
2908 if( pWAcc )
2909 {
2910 const long nWidth = pRAcc->Width();
2911 const long nHeight = pRAcc->Height();
2912
2913 if( pRAcc->HasPalette() )
2914 {
2915 for( long nY = 0L; nY < nHeight; nY++ )
2916 for( long nX =0L; nX < nWidth; nX++ )
2917 pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ))) );
2918 }
2919 else
2920 {
2921 for( long nY = 0L; nY < nHeight; nY++ )
2922 for( long nX =0L; nX < nWidth; nX++ )
2923 pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) )) );
2924 }
2925
2926 aNewBmp.ReleaseAccess( pWAcc );
2927 bRet = sal_True;
2928 }
2929
2930 ReleaseAccess( pRAcc );
2931 }
2932
2933 if( bRet )
2934 {
2935 const MapMode aMap( maPrefMapMode );
2936 const Size aSize( maPrefSize );
2937
2938 *this = aNewBmp;
2939 maPrefMapMode = aMap;
2940 maPrefSize = aSize;
2941 }
2942
2943 return bRet;
2944 }
2945
2946 // ------------------------------------------------------------------------
2947
2948 struct PopularColorCount
2949 {
2950 sal_uInt32 mnIndex;
2951 sal_uInt32 mnCount;
2952 };
2953
2954 // ------------------------------------------------------------------------
2955
ImplPopularCmpFnc(const void * p1,const void * p2)2956 extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 )
2957 {
2958 int nRet;
2959
2960 if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount )
2961 nRet = 1;
2962 else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount )
2963 nRet = 0;
2964 else
2965 nRet = -1;
2966
2967 return nRet;
2968 }
2969
2970 // ------------------------------------------------------------------------
2971
ImplReducePopular(sal_uInt16 nColCount)2972 sal_Bool Bitmap::ImplReducePopular( sal_uInt16 nColCount )
2973 {
2974 BitmapReadAccess* pRAcc = AcquireReadAccess();
2975 sal_uInt16 nBitCount;
2976 sal_Bool bRet = sal_False;
2977
2978 if( nColCount > 256 )
2979 nColCount = 256;
2980
2981 if( nColCount < 17 )
2982 nBitCount = 4;
2983 else
2984 nBitCount = 8;
2985
2986 if( pRAcc )
2987 {
2988 const sal_uInt32 nValidBits = 4;
2989 const sal_uInt32 nRightShiftBits = 8 - nValidBits;
2990 const sal_uInt32 nLeftShiftBits1 = nValidBits;
2991 const sal_uInt32 nLeftShiftBits2 = nValidBits << 1;
2992 const sal_uInt32 nColorsPerComponent = 1 << nValidBits;
2993 const sal_uInt32 nColorOffset = 256 / nColorsPerComponent;
2994 const sal_uInt32 nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent;
2995 const long nWidth = pRAcc->Width();
2996 const long nHeight = pRAcc->Height();
2997 PopularColorCount* pCountTable = new PopularColorCount[ nTotalColors ];
2998 long nX, nY, nR, nG, nB, nIndex;
2999
3000 rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) );
3001
3002 for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
3003 {
3004 for( nG = 0; nG < 256; nG += nColorOffset )
3005 {
3006 for( nB = 0; nB < 256; nB += nColorOffset )
3007 {
3008 pCountTable[ nIndex ].mnIndex = nIndex;
3009 nIndex++;
3010 }
3011 }
3012 }
3013
3014 if( pRAcc->HasPalette() )
3015 {
3016 for( nY = 0L; nY < nHeight; nY++ )
3017 {
3018 for( nX = 0L; nX < nWidth; nX++ )
3019 {
3020 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
3021 pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3022 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3023 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
3024 }
3025 }
3026 }
3027 else
3028 {
3029 for( nY = 0L; nY < nHeight; nY++ )
3030 {
3031 for( nX = 0L; nX < nWidth; nX++ )
3032 {
3033 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
3034 pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3035 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3036 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
3037 }
3038 }
3039 }
3040
3041 BitmapPalette aNewPal( nColCount );
3042
3043 qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc );
3044
3045 for( sal_uInt16 n = 0; n < nColCount; n++ )
3046 {
3047 const PopularColorCount& rPop = pCountTable[ n ];
3048 aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ),
3049 (sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ),
3050 (sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) );
3051 }
3052
3053 Bitmap aNewBmp( GetSizePixel(), nBitCount, &aNewPal );
3054 BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess();
3055
3056 if( pWAcc )
3057 {
3058 BitmapColor aDstCol( (sal_uInt8) 0 );
3059 sal_uInt8* pIndexMap = new sal_uInt8[ nTotalColors ];
3060
3061 for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
3062 for( nG = 0; nG < 256; nG += nColorOffset )
3063 for( nB = 0; nB < 256; nB += nColorOffset )
3064 pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) );
3065
3066 if( pRAcc->HasPalette() )
3067 {
3068 for( nY = 0L; nY < nHeight; nY++ )
3069 {
3070 for( nX = 0L; nX < nWidth; nX++ )
3071 {
3072 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
3073 aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3074 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3075 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] );
3076 pWAcc->SetPixel( nY, nX, aDstCol );
3077 }
3078 }
3079 }
3080 else
3081 {
3082 for( nY = 0L; nY < nHeight; nY++ )
3083 {
3084 for( nX = 0L; nX < nWidth; nX++ )
3085 {
3086 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
3087 aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
3088 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
3089 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] );
3090 pWAcc->SetPixel( nY, nX, aDstCol );
3091 }
3092 }
3093 }
3094
3095 delete[] pIndexMap;
3096 aNewBmp.ReleaseAccess( pWAcc );
3097 bRet = sal_True;
3098 }
3099
3100 delete[] pCountTable;
3101 ReleaseAccess( pRAcc );
3102
3103 if( bRet )
3104 {
3105 const MapMode aMap( maPrefMapMode );
3106 const Size aSize( maPrefSize );
3107
3108 *this = aNewBmp;
3109 maPrefMapMode = aMap;
3110 maPrefSize = aSize;
3111 }
3112 }
3113
3114 return bRet;
3115 }
3116
3117 // ------------------------------------------------------------------------
3118
ImplReduceMedian(sal_uInt16 nColCount)3119 sal_Bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount )
3120 {
3121 BitmapReadAccess* pRAcc = AcquireReadAccess();
3122 sal_uInt16 nBitCount;
3123 sal_Bool bRet = sal_False;
3124
3125 if( nColCount < 17 )
3126 nBitCount = 4;
3127 else if( nColCount < 257 )
3128 nBitCount = 8;
3129 else
3130 {
3131 DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" );
3132 nBitCount = 8;
3133 nColCount = 256;
3134 }
3135
3136 if( pRAcc )
3137 {
3138 Bitmap aNewBmp( GetSizePixel(), nBitCount );
3139 BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess();
3140
3141 if( pWAcc )
3142 {
3143 const sal_uLong nSize = 32768UL * sizeof( sal_uLong );
3144 sal_uLong* pColBuf = (sal_uLong*) rtl_allocateMemory( nSize );
3145 const long nWidth = pWAcc->Width();
3146 const long nHeight = pWAcc->Height();
3147 long nIndex = 0L;
3148
3149 memset( (HPBYTE) pColBuf, 0, nSize );
3150
3151 // create Buffer
3152 if( pRAcc->HasPalette() )
3153 {
3154 for( long nY = 0L; nY < nHeight; nY++ )
3155 {
3156 for( long nX = 0L; nX < nWidth; nX++ )
3157 {
3158 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
3159 pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++;
3160 }
3161 }
3162 }
3163 else
3164 {
3165 for( long nY = 0L; nY < nHeight; nY++ )
3166 {
3167 for( long nX = 0L; nX < nWidth; nX++ )
3168 {
3169 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
3170 pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++;
3171 }
3172 }
3173 }
3174
3175 // create palette via median cut
3176 BitmapPalette aPal( pWAcc->GetPaletteEntryCount() );
3177 ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31,
3178 nColCount, nWidth * nHeight, nIndex );
3179
3180 // do mapping of colors to palette
3181 InverseColorMap aMap( aPal );
3182 pWAcc->SetPalette( aPal );
3183 for( long nY = 0L; nY < nHeight; nY++ )
3184 for( long nX = 0L; nX < nWidth; nX++ )
3185 pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>( aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) )) );
3186
3187 rtl_freeMemory( pColBuf );
3188 aNewBmp.ReleaseAccess( pWAcc );
3189 bRet = sal_True;
3190 }
3191
3192 ReleaseAccess( pRAcc );
3193
3194 if( bRet )
3195 {
3196 const MapMode aMap( maPrefMapMode );
3197 const Size aSize( maPrefSize );
3198
3199 *this = aNewBmp;
3200 maPrefMapMode = aMap;
3201 maPrefSize = aSize;
3202 }
3203 }
3204
3205 return bRet;
3206 }
3207
3208 // ------------------------------------------------------------------------
3209
ImplMedianCut(sal_uLong * pColBuf,BitmapPalette & rPal,long nR1,long nR2,long nG1,long nG2,long nB1,long nB2,long nColors,long nPixels,long & rIndex)3210 void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal,
3211 long nR1, long nR2, long nG1, long nG2, long nB1, long nB2,
3212 long nColors, long nPixels, long& rIndex )
3213 {
3214 if( !nPixels )
3215 return;
3216
3217 BitmapColor aCol;
3218 const long nRLen = nR2 - nR1;
3219 const long nGLen = nG2 - nG1;
3220 const long nBLen = nB2 - nB1;
3221 long nR, nG, nB;
3222 sal_uLong* pBuf = pColBuf;
3223
3224 if( !nRLen && !nGLen && !nBLen )
3225 {
3226 if( pBuf[ RGB15( nR1, nG1, nB1 ) ] )
3227 {
3228 aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) );
3229 aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) );
3230 aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) );
3231 rPal[ (sal_uInt16) rIndex++ ] = aCol;
3232 }
3233 }
3234 else
3235 {
3236 if( 1 == nColors || 1 == nPixels )
3237 {
3238 long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0;
3239
3240 for( nR = nR1; nR <= nR2; nR++ )
3241 {
3242 for( nG = nG1; nG <= nG2; nG++ )
3243 {
3244 for( nB = nB1; nB <= nB2; nB++ )
3245 {
3246 nPixSum = pBuf[ RGB15( nR, nG, nB ) ];
3247
3248 if( nPixSum )
3249 {
3250 nRSum += nR * nPixSum;
3251 nGSum += nG * nPixSum;
3252 nBSum += nB * nPixSum;
3253 }
3254 }
3255 }
3256 }
3257
3258 aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) );
3259 aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) );
3260 aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) );
3261 rPal[ (sal_uInt16) rIndex++ ] = aCol;
3262 }
3263 else
3264 {
3265 const long nTest = ( nPixels >> 1 );
3266 long nPixOld = 0;
3267 long nPixNew = 0;
3268
3269 if( nBLen > nGLen && nBLen > nRLen )
3270 {
3271 nB = nB1 - 1;
3272
3273 while( nPixNew < nTest )
3274 {
3275 nB++, nPixOld = nPixNew;
3276 for( nR = nR1; nR <= nR2; nR++ )
3277 for( nG = nG1; nG <= nG2; nG++ )
3278 nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
3279 }
3280
3281 if( nB < nB2 )
3282 {
3283 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex );
3284 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
3285 }
3286 else
3287 {
3288 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex );
3289 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
3290 }
3291 }
3292 else if( nGLen > nRLen )
3293 {
3294 nG = nG1 - 1;
3295
3296 while( nPixNew < nTest )
3297 {
3298 nG++, nPixOld = nPixNew;
3299 for( nR = nR1; nR <= nR2; nR++ )
3300 for( nB = nB1; nB <= nB2; nB++ )
3301 nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
3302 }
3303
3304 if( nG < nG2 )
3305 {
3306 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex );
3307 ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
3308 }
3309 else
3310 {
3311 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex );
3312 ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
3313 }
3314 }
3315 else
3316 {
3317 nR = nR1 - 1;
3318
3319 while( nPixNew < nTest )
3320 {
3321 nR++, nPixOld = nPixNew;
3322 for( nG = nG1; nG <= nG2; nG++ )
3323 for( nB = nB1; nB <= nB2; nB++ )
3324 nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
3325 }
3326
3327 if( nR < nR2 )
3328 {
3329 ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex );
3330 ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
3331 }
3332 else
3333 {
3334 ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex );
3335 ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
3336 }
3337 }
3338 }
3339 }
3340 }
3341
3342 // ------------------------------------------------------------------------
3343
Vectorize(PolyPolygon & rPolyPoly,sal_uLong nFlags,const Link * pProgress)3344 sal_Bool Bitmap::Vectorize( PolyPolygon& rPolyPoly, sal_uLong nFlags, const Link* pProgress )
3345 {
3346 return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress );
3347 }
3348
3349 // ------------------------------------------------------------------------
3350
Vectorize(GDIMetaFile & rMtf,sal_uInt8 cReduce,sal_uLong nFlags,const Link * pProgress)3351 sal_Bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress )
3352 {
3353 return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress );
3354 }
3355
3356 // ------------------------------------------------------------------------
3357
Adjust(short nLuminancePercent,short nContrastPercent,short nChannelRPercent,short nChannelGPercent,short nChannelBPercent,double fGamma,sal_Bool bInvert)3358 sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
3359 short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
3360 double fGamma, sal_Bool bInvert )
3361 {
3362 sal_Bool bRet = sal_False;
3363
3364 // nothing to do => return quickly
3365 if( !nLuminancePercent && !nContrastPercent &&
3366 !nChannelRPercent && !nChannelGPercent && !nChannelBPercent &&
3367 ( fGamma == 1.0 ) && !bInvert )
3368 {
3369 bRet = sal_True;
3370 }
3371 else
3372 {
3373 BitmapWriteAccess* pAcc = AcquireWriteAccess();
3374
3375 if( pAcc )
3376 {
3377 BitmapColor aCol;
3378 const long nW = pAcc->Width();
3379 const long nH = pAcc->Height();
3380 sal_uInt8* cMapR = new sal_uInt8[ 256 ];
3381 sal_uInt8* cMapG = new sal_uInt8[ 256 ];
3382 sal_uInt8* cMapB = new sal_uInt8[ 256 ];
3383 long nX, nY;
3384 double fM, fROff, fGOff, fBOff, fOff;
3385
3386 // calculate slope
3387 if( nContrastPercent >= 0 )
3388 fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
3389 else
3390 fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
3391
3392 // total offset = luminance offset + contrast offset
3393 fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
3394
3395 // channel offset = channel offset + total offset
3396 fROff = nChannelRPercent * 2.55 + fOff;
3397 fGOff = nChannelGPercent * 2.55 + fOff;
3398 fBOff = nChannelBPercent * 2.55 + fOff;
3399
3400 // calculate gamma value
3401 fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
3402 const sal_Bool bGamma = ( fGamma != 1.0 );
3403
3404 // create mapping table
3405 for( nX = 0L; nX < 256L; nX++ )
3406 {
3407 cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
3408 cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
3409 cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
3410
3411 if( bGamma )
3412 {
3413 cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma );
3414 cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma );
3415 cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma );
3416 }
3417
3418 if( bInvert )
3419 {
3420 cMapR[ nX ] = ~cMapR[ nX ];
3421 cMapG[ nX ] = ~cMapG[ nX ];
3422 cMapB[ nX ] = ~cMapB[ nX ];
3423 }
3424 }
3425
3426 // do modifying
3427 if( pAcc->HasPalette() )
3428 {
3429 BitmapColor aNewCol;
3430
3431 for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
3432 {
3433 const BitmapColor& rCol = pAcc->GetPaletteColor( i );
3434 aNewCol.SetRed( cMapR[ rCol.GetRed() ] );
3435 aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] );
3436 aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] );
3437 pAcc->SetPaletteColor( i, aNewCol );
3438 }
3439 }
3440 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
3441 {
3442 for( nY = 0L; nY < nH; nY++ )
3443 {
3444 Scanline pScan = pAcc->GetScanline( nY );
3445
3446 for( nX = 0L; nX < nW; nX++ )
3447 {
3448 *pScan = cMapB[ *pScan ]; pScan++;
3449 *pScan = cMapG[ *pScan ]; pScan++;
3450 *pScan = cMapR[ *pScan ]; pScan++;
3451 }
3452 }
3453 }
3454 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
3455 {
3456 for( nY = 0L; nY < nH; nY++ )
3457 {
3458 Scanline pScan = pAcc->GetScanline( nY );
3459
3460 for( nX = 0L; nX < nW; nX++ )
3461 {
3462 *pScan = cMapR[ *pScan ]; pScan++;
3463 *pScan = cMapG[ *pScan ]; pScan++;
3464 *pScan = cMapB[ *pScan ]; pScan++;
3465 }
3466 }
3467 }
3468 else
3469 {
3470 for( nY = 0L; nY < nH; nY++ )
3471 {
3472 for( nX = 0L; nX < nW; nX++ )
3473 {
3474 aCol = pAcc->GetPixel( nY, nX );
3475 aCol.SetRed( cMapR[ aCol.GetRed() ] );
3476 aCol.SetGreen( cMapG[ aCol.GetGreen() ] );
3477 aCol.SetBlue( cMapB[ aCol.GetBlue() ] );
3478 pAcc->SetPixel( nY, nX, aCol );
3479 }
3480 }
3481 }
3482
3483 delete[] cMapR;
3484 delete[] cMapG;
3485 delete[] cMapB;
3486 ReleaseAccess( pAcc );
3487 bRet = sal_True;
3488 }
3489 }
3490
3491 return bRet;
3492 }
3493