1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
23 #include <vcl/bmpacc.hxx>
24 #include <vcl/bitmapex.hxx>
25 #include <vcl/bitmap.hxx>
26 #include <vcl/bitmapscalesuper.hxx>
27 #include <vcl/opengl/OpenGLHelper.hxx>
29 #include <boost/scoped_array.hpp>
33 #include <impvect.hxx>
37 #define RGB15( _def_cR, _def_cG, _def_cB ) (((sal_uLong)(_def_cR)<<10UL)|((sal_uLong)(_def_cG)<<5UL)|(sal_uLong)(_def_cB))
38 #define GAMMA( _def_cVal, _def_InvGamma ) ((sal_uInt8)MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0L,255L))
41 nTemp = p1T[nX++] >> 12; \
42 nBErr = MinMax( nTemp, 0, 255 ); \
43 nBErr = nBErr - FloydIndexMap[ nBC = FloydMap[nBErr] ]; \
44 nTemp = p1T[nX++] >> 12; \
45 nGErr = MinMax( nTemp, 0, 255 ); \
46 nGErr = nGErr - FloydIndexMap[ nGC = FloydMap[nGErr] ]; \
47 nTemp = p1T[nX] >> 12; \
48 nRErr = MinMax( nTemp, 0, 255 ); \
49 nRErr = nRErr - FloydIndexMap[ nRC = FloydMap[nRErr] ];
51 #define CALC_TABLES3 \
52 p2T[nX++] += FloydError3[nBErr]; \
53 p2T[nX++] += FloydError3[nGErr]; \
54 p2T[nX++] += FloydError3[nRErr];
56 #define CALC_TABLES5 \
57 p2T[nX++] += FloydError5[nBErr]; \
58 p2T[nX++] += FloydError5[nGErr]; \
59 p2T[nX++] += FloydError5[nRErr];
61 #define CALC_TABLES7 \
62 p1T[++nX] += FloydError7[nBErr]; \
63 p2T[nX++] += FloydError1[nBErr]; \
64 p1T[nX] += FloydError7[nGErr]; \
65 p2T[nX++] += FloydError1[nGErr]; \
66 p1T[nX] += FloydError7[nRErr]; \
67 p2T[nX] += FloydError1[nRErr];
69 const extern sal_uLong nVCLRLut
[ 6 ] = { 16, 17, 18, 19, 20, 21 };
70 const extern sal_uLong nVCLGLut
[ 6 ] = { 0, 6, 12, 18, 24, 30 };
71 const extern sal_uLong nVCLBLut
[ 6 ] = { 0, 36, 72, 108, 144, 180 };
73 const extern sal_uLong nVCLDitherLut
[ 256 ] =
75 0, 49152, 12288, 61440, 3072, 52224, 15360, 64512, 768, 49920, 13056,
76 62208, 3840, 52992, 16128, 65280, 32768, 16384, 45056, 28672, 35840, 19456,
77 48128, 31744, 33536, 17152, 45824, 29440, 36608, 20224, 48896, 32512, 8192,
78 57344, 4096, 53248, 11264, 60416, 7168, 56320, 8960, 58112, 4864, 54016,
79 12032, 61184, 7936, 57088, 40960, 24576, 36864, 20480, 44032, 27648, 39936,
80 23552, 41728, 25344, 37632, 21248, 44800, 28416, 40704, 24320, 2048, 51200,
81 14336, 63488, 1024, 50176, 13312, 62464, 2816, 51968, 15104, 64256, 1792,
82 50944, 14080, 63232, 34816, 18432, 47104, 30720, 33792, 17408, 46080, 29696,
83 35584, 19200, 47872, 31488, 34560, 18176, 46848, 30464, 10240, 59392, 6144,
84 55296, 9216, 58368, 5120, 54272, 11008, 60160, 6912, 56064, 9984, 59136,
85 5888, 55040, 43008, 26624, 38912, 22528, 41984, 25600, 37888, 21504, 43776,
86 27392, 39680, 23296, 42752, 26368, 38656, 22272, 512, 49664, 12800, 61952,
87 3584, 52736, 15872, 65024, 256, 49408, 12544, 61696, 3328, 52480, 15616,
88 64768, 33280, 16896, 45568, 29184, 36352, 19968, 48640, 32256, 33024, 16640,
89 45312, 28928, 36096, 19712, 48384, 32000, 8704, 57856, 4608, 53760, 11776,
90 60928, 7680, 56832, 8448, 57600, 4352, 53504, 11520, 60672, 7424, 56576,
91 41472, 25088, 37376, 20992, 44544, 28160, 40448, 24064, 41216, 24832, 37120,
92 20736, 44288, 27904, 40192, 23808, 2560, 51712, 14848, 64000, 1536, 50688,
93 13824, 62976, 2304, 51456, 14592, 63744, 1280, 50432, 13568, 62720, 35328,
94 18944, 47616, 31232, 34304, 17920, 46592, 30208, 35072, 18688, 47360, 30976,
95 34048, 17664, 46336, 29952, 10752, 59904, 6656, 55808, 9728, 58880, 5632,
96 54784, 10496, 59648, 6400, 55552, 9472, 58624, 5376, 54528, 43520, 27136,
97 39424, 23040, 42496, 26112, 38400, 22016, 43264, 26880, 39168, 22784, 42240,
101 const extern sal_uLong nVCLLut
[ 256 ] =
103 0, 1286, 2572, 3858, 5144, 6430, 7716, 9002,
104 10288, 11574, 12860, 14146, 15432, 16718, 18004, 19290,
105 20576, 21862, 23148, 24434, 25720, 27006, 28292, 29578,
106 30864, 32150, 33436, 34722, 36008, 37294, 38580, 39866,
107 41152, 42438, 43724, 45010, 46296, 47582, 48868, 50154,
108 51440, 52726, 54012, 55298, 56584, 57870, 59156, 60442,
109 61728, 63014, 64300, 65586, 66872, 68158, 69444, 70730,
110 72016, 73302, 74588, 75874, 77160, 78446, 79732, 81018,
111 82304, 83590, 84876, 86162, 87448, 88734, 90020, 91306,
112 92592, 93878, 95164, 96450, 97736, 99022,100308,101594,
113 102880,104166,105452,106738,108024,109310,110596,111882,
114 113168,114454,115740,117026,118312,119598,120884,122170,
115 123456,124742,126028,127314,128600,129886,131172,132458,
116 133744,135030,136316,137602,138888,140174,141460,142746,
117 144032,145318,146604,147890,149176,150462,151748,153034,
118 154320,155606,156892,158178,159464,160750,162036,163322,
119 164608,165894,167180,168466,169752,171038,172324,173610,
120 174896,176182,177468,178754,180040,181326,182612,183898,
121 185184,186470,187756,189042,190328,191614,192900,194186,
122 195472,196758,198044,199330,200616,201902,203188,204474,
123 205760,207046,208332,209618,210904,212190,213476,214762,
124 216048,217334,218620,219906,221192,222478,223764,225050,
125 226336,227622,228908,230194,231480,232766,234052,235338,
126 236624,237910,239196,240482,241768,243054,244340,245626,
127 246912,248198,249484,250770,252056,253342,254628,255914,
128 257200,258486,259772,261058,262344,263630,264916,266202,
129 267488,268774,270060,271346,272632,273918,275204,276490,
130 277776,279062,280348,281634,282920,284206,285492,286778,
131 288064,289350,290636,291922,293208,294494,295780,297066,
132 298352,299638,300924,302210,303496,304782,306068,307354,
133 308640,309926,311212,312498,313784,315070,316356,317642,
134 318928,320214,321500,322786,324072,325358,326644,327930
137 const long FloydMap
[256] =
139 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
140 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
141 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
142 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
143 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
144 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
145 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
146 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
147 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
148 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
149 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
150 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
151 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
152 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
153 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
154 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
157 const long FloydError1
[61] =
159 -7680, -7424, -7168, -6912, -6656, -6400, -6144,
160 -5888, -5632, -5376, -5120, -4864, -4608, -4352,
161 -4096, -3840, -3584, -3328, -3072, -2816, -2560,
162 -2304, -2048, -1792, -1536, -1280, -1024, -768,
163 -512, -256, 0, 256, 512, 768, 1024, 1280, 1536,
164 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
165 3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632,
166 5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680
169 const long FloydError3
[61] =
171 -23040, -22272, -21504, -20736, -19968, -19200,
172 -18432, -17664, -16896, -16128, -15360, -14592,
173 -13824, -13056, -12288, -11520, -10752, -9984,
174 -9216, -8448, -7680, -6912, -6144, -5376, -4608,
175 -3840, -3072, -2304, -1536, -768, 0, 768, 1536,
176 2304, 3072, 3840, 4608, 5376, 6144, 6912, 7680,
177 8448, 9216, 9984, 10752, 11520, 12288, 13056,
178 13824, 14592, 15360, 16128, 16896, 17664, 18432,
179 19200, 19968, 20736, 21504, 22272, 23040
182 const long FloydError5
[61] =
184 -38400, -37120, -35840, -34560, -33280, -32000,
185 -30720, -29440, -28160, -26880, -25600, -24320,
186 -23040, -21760, -20480, -19200, -17920, -16640,
187 -15360, -14080, -12800, -11520, -10240, -8960,
188 -7680, -6400, -5120, -3840, -2560, -1280, 0,
189 1280, 2560, 3840, 5120, 6400, 7680, 8960, 10240,
190 11520, 12800, 14080, 15360, 16640, 17920, 19200,
191 20480, 21760, 23040, 24320, 25600, 26880, 28160,
192 29440, 30720, 32000, 33280, 34560, 35840, 37120,
196 const long FloydError7
[61] =
198 -53760, -51968, -50176, -48384, -46592, -44800,
199 -43008, -41216, -39424, -37632, -35840, -34048,
200 -32256, -30464, -28672, -26880, -25088, -23296,
201 -21504, -19712, -17920, -16128, -14336, -12544,
202 -10752, -8960, -7168, -5376, -3584, -1792, 0,
203 1792, 3584, 5376, 7168, 8960, 10752, 12544, 14336,
204 16128, 17920, 19712, 21504, 23296, 25088, 26880,
205 28672, 30464, 32256, 34048, 35840, 37632, 39424,
206 41216, 43008, 44800, 46592, 48384, 50176, 51968,
210 const long FloydIndexMap
[6] =
212 -30, 21, 72, 123, 174, 225
215 void ImplCreateDitherMatrix( sal_uInt8 (*pDitherMatrix
)[16][16] )
217 const double fVal
= 3.125;
218 const double fVal16
= fVal
/ 16.;
219 const double fValScale
= 254.;
220 sal_uInt16 pMtx
[ 16 ][ 16 ];
222 static const sal_uInt8 pMagic
[4][4] = { { 0, 14, 3, 13, },
228 for ( long i
= 0; i
< 4; i
++ )
229 for ( long j
= 0; j
< 4; j
++ )
230 for ( long k
= 0; k
< 4; k
++ )
231 for ( long l
= 0; l
< 4; l
++ )
233 pMtx
[ (k
<<2) + i
][(l
<<2 ) + j
] = (sal_uInt16
) ( 0.5 + pMagic
[i
][j
]*fVal
+ pMagic
[k
][l
]*fVal16
);
234 nMax
= std::max ( pMtx
[ (k
<<2) + i
][(l
<<2 ) + j
], nMax
);
237 // Scale to interval [0;254]
238 double tmp
= fValScale
/ nMax
;
239 for ( long i
= 0; i
< 16; i
++ )
240 for( long j
= 0; j
< 16; j
++ )
241 (*pDitherMatrix
)[i
][j
] = (sal_uInt8
) ( tmp
* pMtx
[i
][j
] );
244 bool Bitmap::Convert( BmpConversion eConversion
)
246 const sal_uInt16 nBitCount
= GetBitCount ();
249 switch( eConversion
)
251 case( BMP_CONVERSION_1BIT_THRESHOLD
):
252 bRet
= ImplMakeMono( 128 );
255 case( BMP_CONVERSION_1BIT_MATRIX
):
256 bRet
= ImplMakeMonoDither();
259 case( BMP_CONVERSION_4BIT_GREYS
):
260 bRet
= ImplMakeGreyscales( 16 );
263 case( BMP_CONVERSION_4BIT_COLORS
):
266 bRet
= ImplConvertUp( 4, NULL
);
267 else if( nBitCount
> 4 )
268 bRet
= ImplConvertDown( 4, NULL
);
274 case( BMP_CONVERSION_4BIT_TRANS
):
276 Color
aTrans( BMP_COL_TRANS
);
279 bRet
= ImplConvertUp( 4, &aTrans
);
281 bRet
= ImplConvertDown( 4, &aTrans
);
285 case( BMP_CONVERSION_8BIT_GREYS
):
286 bRet
= ImplMakeGreyscales( 256 );
289 case( BMP_CONVERSION_8BIT_COLORS
):
292 bRet
= ImplConvertUp( 8 );
293 else if( nBitCount
> 8 )
294 bRet
= ImplConvertDown( 8 );
300 case( BMP_CONVERSION_8BIT_TRANS
):
302 Color
aTrans( BMP_COL_TRANS
);
305 bRet
= ImplConvertUp( 8, &aTrans
);
307 bRet
= ImplConvertDown( 8, &aTrans
);
311 case( BMP_CONVERSION_24BIT
):
314 bRet
= ImplConvertUp( 24, NULL
);
320 case( BMP_CONVERSION_GHOSTED
):
321 bRet
= ImplConvertGhosted();
325 OSL_FAIL( "Bitmap::Convert(): Unsupported conversion" );
332 bool Bitmap::ImplMakeMono( sal_uInt8 cThreshold
)
334 BitmapReadAccess
* pReadAcc
= AcquireReadAccess();
339 Bitmap
aNewBmp( GetSizePixel(), 1 );
340 BitmapWriteAccess
* pWriteAcc
= aNewBmp
.AcquireWriteAccess();
344 const BitmapColor
aBlack( pWriteAcc
->GetBestMatchingColor( Color( COL_BLACK
) ) );
345 const BitmapColor
aWhite( pWriteAcc
->GetBestMatchingColor( Color( COL_WHITE
) ) );
346 const long nWidth
= pWriteAcc
->Width();
347 const long nHeight
= pWriteAcc
->Height();
349 if( pReadAcc
->HasPalette() )
351 for( long nY
= 0L; nY
< nHeight
; nY
++ )
353 for( long nX
= 0L; nX
< nWidth
; nX
++ )
355 const sal_uInt8 cIndex
= pReadAcc
->GetPixelIndex( nY
, nX
);
356 if( pReadAcc
->GetPaletteColor( cIndex
).GetLuminance() >=
359 pWriteAcc
->SetPixel( nY
, nX
, aWhite
);
362 pWriteAcc
->SetPixel( nY
, nX
, aBlack
);
368 for( long nY
= 0L; nY
< nHeight
; nY
++ )
370 for( long nX
= 0L; nX
< nWidth
; nX
++ )
372 if( pReadAcc
->GetPixel( nY
, nX
).GetLuminance() >=
375 pWriteAcc
->SetPixel( nY
, nX
, aWhite
);
378 pWriteAcc
->SetPixel( nY
, nX
, aBlack
);
383 ReleaseAccess( pWriteAcc
);
387 ReleaseAccess( pReadAcc
);
391 const MapMode
aMap( maPrefMapMode
);
392 const Size
aSize( maPrefSize
);
396 maPrefMapMode
= aMap
;
404 bool Bitmap::ImplMakeMonoDither()
406 BitmapReadAccess
* pReadAcc
= AcquireReadAccess();
411 Bitmap
aNewBmp( GetSizePixel(), 1 );
412 BitmapWriteAccess
* pWriteAcc
= aNewBmp
.AcquireWriteAccess();
416 const BitmapColor
aBlack( pWriteAcc
->GetBestMatchingColor( Color( COL_BLACK
) ) );
417 const BitmapColor
aWhite( pWriteAcc
->GetBestMatchingColor( Color( COL_WHITE
) ) );
418 const long nWidth
= pWriteAcc
->Width();
419 const long nHeight
= pWriteAcc
->Height();
420 sal_uInt8 pDitherMatrix
[ 16 ][ 16 ];
422 ImplCreateDitherMatrix( &pDitherMatrix
);
424 if( pReadAcc
->HasPalette() )
426 for( long nY
= 0L; nY
< nHeight
; nY
++ )
428 for( long nX
= 0L, nModY
= nY
% 16; nX
< nWidth
; nX
++ )
430 const sal_uInt8 cIndex
= pReadAcc
->GetPixelIndex( nY
, nX
);
431 if( pReadAcc
->GetPaletteColor( cIndex
).GetLuminance() >
432 pDitherMatrix
[ nModY
][ nX
% 16 ] )
434 pWriteAcc
->SetPixel( nY
, nX
, aWhite
);
437 pWriteAcc
->SetPixel( nY
, nX
, aBlack
);
443 for( long nY
= 0L; nY
< nHeight
; nY
++ )
445 for( long nX
= 0L, nModY
= nY
% 16; nX
< nWidth
; nX
++ )
447 if( pReadAcc
->GetPixel( nY
, nX
).GetLuminance() >
448 pDitherMatrix
[ nModY
][ nX
% 16 ] )
450 pWriteAcc
->SetPixel( nY
, nX
, aWhite
);
453 pWriteAcc
->SetPixel( nY
, nX
, aBlack
);
458 ReleaseAccess( pWriteAcc
);
462 ReleaseAccess( pReadAcc
);
466 const MapMode
aMap( maPrefMapMode
);
467 const Size
aSize( maPrefSize
);
471 maPrefMapMode
= aMap
;
479 bool Bitmap::ImplMakeGreyscales( sal_uInt16 nGreys
)
481 DBG_ASSERT( nGreys
== 16 || nGreys
== 256, "Only 16 or 256 greyscales are supported!" );
483 BitmapReadAccess
* pReadAcc
= AcquireReadAccess();
488 const BitmapPalette
& rPal
= GetGreyPalette( nGreys
);
489 sal_uLong nShift
= ( ( nGreys
== 16 ) ? 4UL : 0UL );
490 bool bPalDiffers
= !pReadAcc
->HasPalette() || ( rPal
.GetEntryCount() != pReadAcc
->GetPaletteEntryCount() );
493 bPalDiffers
= ( (BitmapPalette
&) rPal
!= pReadAcc
->GetPalette() );
497 Bitmap
aNewBmp( GetSizePixel(), ( nGreys
== 16 ) ? 4 : 8, &rPal
);
498 BitmapWriteAccess
* pWriteAcc
= aNewBmp
.AcquireWriteAccess();
502 const long nWidth
= pWriteAcc
->Width();
503 const long nHeight
= pWriteAcc
->Height();
505 if( pReadAcc
->HasPalette() )
507 for( long nY
= 0L; nY
< nHeight
; nY
++ )
509 for( long nX
= 0L; nX
< nWidth
; nX
++ )
511 const sal_uInt8 cIndex
= pReadAcc
->GetPixelIndex( nY
, nX
);
512 pWriteAcc
->SetPixelIndex( nY
, nX
,
513 (pReadAcc
->GetPaletteColor( cIndex
).GetLuminance() >> nShift
) );
517 else if( pReadAcc
->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR
&&
518 pWriteAcc
->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL
)
522 for( long nY
= 0L; nY
< nHeight
; nY
++ )
524 Scanline pReadScan
= pReadAcc
->GetScanline( nY
);
525 Scanline pWriteScan
= pWriteAcc
->GetScanline( nY
);
527 for( long nX
= 0L; nX
< nWidth
; nX
++ )
529 const sal_uLong nB
= *pReadScan
++;
530 const sal_uLong nG
= *pReadScan
++;
531 const sal_uLong nR
= *pReadScan
++;
533 *pWriteScan
++ = (sal_uInt8
) ( ( nB
* 28UL + nG
* 151UL + nR
* 77UL ) >> nShift
);
537 else if( pReadAcc
->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB
&&
538 pWriteAcc
->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL
)
542 for( long nY
= 0L; nY
< nHeight
; nY
++ )
544 Scanline pReadScan
= pReadAcc
->GetScanline( nY
);
545 Scanline pWriteScan
= pWriteAcc
->GetScanline( nY
);
547 for( long nX
= 0L; nX
< nWidth
; nX
++ )
549 const sal_uLong nR
= *pReadScan
++;
550 const sal_uLong nG
= *pReadScan
++;
551 const sal_uLong nB
= *pReadScan
++;
553 *pWriteScan
++ = (sal_uInt8
) ( ( nB
* 28UL + nG
* 151UL + nR
* 77UL ) >> nShift
);
559 for( long nY
= 0L; nY
< nHeight
; nY
++ )
560 for( long nX
= 0L; nX
< nWidth
; nX
++ )
561 pWriteAcc
->SetPixelIndex( nY
, nX
, (pReadAcc
->GetPixel( nY
, nX
) ).GetLuminance() >> nShift
);
564 ReleaseAccess( pWriteAcc
);
568 ReleaseAccess( pReadAcc
);
572 const MapMode
aMap( maPrefMapMode
);
573 const Size
aSize( maPrefSize
);
577 maPrefMapMode
= aMap
;
583 ReleaseAccess( pReadAcc
);
591 bool Bitmap::ImplConvertUp(sal_uInt16 nBitCount
, Color
* pExtColor
)
593 DBG_ASSERT( nBitCount
> GetBitCount(), "New BitCount must be greater!" );
595 Bitmap::ScopedReadAccess
pReadAcc(*this);
600 BitmapPalette aPalette
;
601 Bitmap
aNewBmp(GetSizePixel(), nBitCount
, pReadAcc
->HasPalette() ? &pReadAcc
->GetPalette() : &aPalette
);
602 Bitmap::ScopedWriteAccess
pWriteAcc(aNewBmp
);
606 const long nWidth
= pWriteAcc
->Width();
607 const long nHeight
= pWriteAcc
->Height();
609 if (pWriteAcc
->HasPalette())
611 const sal_uInt16 nOldCount
= 1 << GetBitCount();
612 const BitmapPalette
& rOldPalette
= pReadAcc
->GetPalette();
614 aPalette
.SetEntryCount(1 << nBitCount
);
616 for (sal_uInt16 i
= 0; i
< nOldCount
; i
++)
617 aPalette
[i
] = rOldPalette
[i
];
620 aPalette
[aPalette
.GetEntryCount() - 1] = *pExtColor
;
622 pWriteAcc
->SetPalette(aPalette
);
624 for (long nY
= 0L; nY
< nHeight
; nY
++)
626 for (long nX
= 0L; nX
< nWidth
; nX
++)
628 pWriteAcc
->SetPixel(nY
, nX
, pReadAcc
->GetPixel(nY
, nX
));
634 if (pReadAcc
->HasPalette())
636 for (long nY
= 0L; nY
< nHeight
; nY
++)
638 for (long nX
= 0L; nX
< nWidth
; nX
++)
640 pWriteAcc
->SetPixel(nY
, nX
, pReadAcc
->GetPaletteColor(pReadAcc
->GetPixelIndex(nY
, nX
)));
646 for (long nY
= 0L; nY
< nHeight
; nY
++)
648 for (long nX
= 0L; nX
< nWidth
; nX
++)
650 pWriteAcc
->SetPixel(nY
, nX
, pReadAcc
->GetPixel(nY
, nX
));
660 const MapMode
aMap(maPrefMapMode
);
661 const Size
aSize(maPrefSize
);
665 maPrefMapMode
= aMap
;
673 bool Bitmap::ImplConvertDown(sal_uInt16 nBitCount
, Color
* pExtColor
)
675 DBG_ASSERT(nBitCount
<= GetBitCount(), "New BitCount must be lower ( or equal when pExtColor is set )!");
677 Bitmap::ScopedReadAccess
pReadAcc(*this);
682 BitmapPalette aPalette
;
683 Bitmap
aNewBmp(GetSizePixel(), nBitCount
, &aPalette
);
684 Bitmap::ScopedWriteAccess
pWriteAcc(aNewBmp
);
688 const sal_uInt16 nCount
= 1 << nBitCount
;
689 const long nWidth
= pWriteAcc
->Width();
690 const long nWidth1
= nWidth
- 1L;
691 const long nHeight
= pWriteAcc
->Height();
692 Octree
aOctree(*pReadAcc
, pExtColor
? (nCount
- 1) : nCount
);
693 aPalette
= aOctree
.GetPalette();
694 InverseColorMap
aColorMap(aPalette
);
696 ImpErrorQuad aErrQuad
;
697 std::vector
<ImpErrorQuad
> pErrQuad1(nWidth
);
698 std::vector
<ImpErrorQuad
> pErrQuad2(nWidth
);
699 ImpErrorQuad
* pQLine1
= pErrQuad1
.data();
700 ImpErrorQuad
* pQLine2
= NULL
;
707 aPalette
.SetEntryCount(aPalette
.GetEntryCount() + 1);
708 aPalette
[aPalette
.GetEntryCount() - 1] = *pExtColor
;
711 // set Black/White always, if we have enough space
712 if (aPalette
.GetEntryCount() < (nCount
- 1))
714 aPalette
.SetEntryCount(aPalette
.GetEntryCount() + 2);
715 aPalette
[aPalette
.GetEntryCount() - 2] = Color(COL_BLACK
);
716 aPalette
[aPalette
.GetEntryCount() - 1] = Color(COL_WHITE
);
719 pWriteAcc
->SetPalette(aPalette
);
721 for (long nY
= 0L; nY
< std::min(nHeight
, 2L); nY
++, nYTmp
++)
723 pQLine2
= !nY
? pErrQuad1
.data() : pErrQuad2
.data();
724 for (long nX
= 0L; nX
< nWidth
; nX
++)
726 if (pReadAcc
->HasPalette())
727 pQLine2
[nX
] = pReadAcc
->GetPaletteColor(pReadAcc
->GetPixelIndex(nYTmp
, nX
));
729 pQLine2
[nX
] = pReadAcc
->GetPixel(nYTmp
, nX
);
733 for (long nY
= 0L; nY
< nHeight
; nY
++, nYTmp
++)
735 // first pixel in the line
736 cIndex
= (sal_uInt8
) aColorMap
.GetBestPaletteIndex(pQLine1
[0].ImplGetColor());
737 pWriteAcc
->SetPixelIndex(nY
, 0, cIndex
);
740 for (nX
= 1L; nX
< nWidth1
; nX
++)
742 aColor
= pQLine1
[nX
].ImplGetColor();
743 cIndex
= static_cast<sal_uInt8
>(aColorMap
.GetBestPaletteIndex(aColor
));
744 aErrQuad
= (ImpErrorQuad(aColor
) -= pWriteAcc
->GetPaletteColor(cIndex
));
745 pQLine1
[++nX
].ImplAddColorError7(aErrQuad
);
746 pQLine2
[nX
--].ImplAddColorError1(aErrQuad
);
747 pQLine2
[nX
--].ImplAddColorError5(aErrQuad
);
748 pQLine2
[nX
++].ImplAddColorError3(aErrQuad
);
749 pWriteAcc
->SetPixelIndex(nY
, nX
, cIndex
);
755 cIndex
= static_cast<sal_uInt8
>(aColorMap
.GetBestPaletteIndex(pQLine1
[nWidth1
].ImplGetColor()));
756 pWriteAcc
->SetPixelIndex(nY
, nX
, cIndex
);
759 // Refill/copy row buffer
761 pQLine2
= (bQ1
= !bQ1
) ? pErrQuad2
.data() : pErrQuad1
.data();
765 for (nX
= 0L; nX
< nWidth
; nX
++)
767 if (pReadAcc
->HasPalette())
768 pQLine2
[nX
] = pReadAcc
->GetPaletteColor(pReadAcc
->GetPixelIndex(nYTmp
, nX
));
770 pQLine2
[nX
] = pReadAcc
->GetPixel(nYTmp
, nX
);
780 const MapMode
aMap(maPrefMapMode
);
781 const Size
aSize(maPrefSize
);
785 maPrefMapMode
= aMap
;
793 bool Bitmap::ImplConvertGhosted()
796 BitmapReadAccess
* pR
= AcquireReadAccess();
801 if( pR
->HasPalette() )
803 BitmapPalette
aNewPal( pR
->GetPaletteEntryCount() );
805 for( long i
= 0, nCount
= aNewPal
.GetEntryCount(); i
< nCount
; i
++ )
807 const BitmapColor
& rOld
= pR
->GetPaletteColor( (sal_uInt16
) i
);
808 aNewPal
[ (sal_uInt16
) i
] = BitmapColor( ( rOld
.GetRed() >> 1 ) | 0x80,
809 ( rOld
.GetGreen() >> 1 ) | 0x80,
810 ( rOld
.GetBlue() >> 1 ) | 0x80 );
813 aNewBmp
= Bitmap( GetSizePixel(), GetBitCount(), &aNewPal
);
814 BitmapWriteAccess
* pW
= aNewBmp
.AcquireWriteAccess();
818 pW
->CopyBuffer( *pR
);
825 aNewBmp
= Bitmap( GetSizePixel(), 24 );
827 BitmapWriteAccess
* pW
= aNewBmp
.AcquireWriteAccess();
831 const long nWidth
= pR
->Width(), nHeight
= pR
->Height();
833 for( long nY
= 0; nY
< nHeight
; nY
++ )
835 for( long nX
= 0; nX
< nWidth
; nX
++ )
837 const BitmapColor
aOld( pR
->GetPixel( nY
, nX
) );
838 pW
->SetPixel( nY
, nX
, BitmapColor( ( aOld
.GetRed() >> 1 ) | 0x80,
839 ( aOld
.GetGreen() >> 1 ) | 0x80,
840 ( aOld
.GetBlue() >> 1 ) | 0x80 ) );
855 const MapMode
aMap( maPrefMapMode
);
856 const Size
aSize( maPrefSize
);
860 maPrefMapMode
= aMap
;
867 bool Bitmap::Scale( const double& rScaleX
, const double& rScaleY
, BmpScaleFlag nScaleFlag
)
869 if(basegfx::fTools::equalZero(rScaleX
) || basegfx::fTools::equalZero(rScaleY
))
875 if(basegfx::fTools::equal(rScaleX
, 1.0) && basegfx::fTools::equal(rScaleY
, 1.0))
881 const sal_uInt16
nStartCount(GetBitCount());
885 // implementation specific scaling
886 ImpBitmap
* pImpBmp
= new ImpBitmap
;
888 if( pImpBmp
->ImplCreate( *mpImpBmp
) && pImpBmp
->ImplScale( rScaleX
, rScaleY
, nScaleFlag
) )
890 ImplSetImpBitmap( pImpBmp
);
891 SAL_INFO( "vcl.opengl", "Ref count: " << mpImpBmp
->ImplGetRefCount() );
892 maPrefMapMode
= MapMode( MAP_PIXEL
);
893 maPrefSize
= pImpBmp
->ImplGetSize();
904 //If we start with a 1 bit image, then after scaling it in any mode except
905 //BmpScaleFlag::Fast we have a 24bit image which is perfectly correct, but we
906 //are going to down-shift it to mono again and Bitmap::ImplMakeMono just
907 //has "Bitmap aNewBmp( GetSizePixel(), 1 );" to create a 1 bit bitmap which
908 //will default to black/white and the colors mapped to which ever is closer
911 //So the easiest thing to do to retain the colors of 1 bit bitmaps is to
912 //just use the fast scale rather than attempting to count unique colors in
913 //the other converters and pass all the info down through
914 //Bitmap::ImplMakeMono
915 if (nStartCount
== 1 && nScaleFlag
!= BmpScaleFlag::NONE
)
916 nScaleFlag
= BmpScaleFlag::Fast
;
922 case BmpScaleFlag::NONE
:
927 case BmpScaleFlag::Fast
:
929 bRetval
= ImplScaleFast( rScaleX
, rScaleY
);
932 case BmpScaleFlag::Interpolate
:
934 bRetval
= ImplScaleInterpolate( rScaleX
, rScaleY
);
937 case BmpScaleFlag::Super
:
938 case BmpScaleFlag::Default
:
940 if (GetSizePixel().Width() < 2 || GetSizePixel().Height() < 2)
942 // fallback to ImplScaleFast
943 bRetval
= ImplScaleFast( rScaleX
, rScaleY
);
947 BitmapScaleSuper
aScaleSuper(rScaleX
, rScaleY
);
948 bRetval
= aScaleSuper
.filter(*this);
952 case BmpScaleFlag::Lanczos
:
953 case BmpScaleFlag::BestQuality
:
955 const Lanczos3Kernel kernel
;
957 bRetval
= ImplScaleConvolution( rScaleX
, rScaleY
, kernel
);
960 case BmpScaleFlag::BiCubic
:
962 const BicubicKernel kernel
;
964 bRetval
= ImplScaleConvolution( rScaleX
, rScaleY
, kernel
);
967 case BmpScaleFlag::BiLinear
:
969 const BilinearKernel kernel
;
971 bRetval
= ImplScaleConvolution( rScaleX
, rScaleY
, kernel
);
974 case BmpScaleFlag::Box
:
976 const BoxKernel kernel
;
978 bRetval
= ImplScaleConvolution( rScaleX
, rScaleY
, kernel
);
983 OSL_ENSURE(!bRetval
|| nStartCount
== GetBitCount(), "Bitmap::Scale has changed the ColorDepth, this should *not* happen (!)");
987 bool Bitmap::Scale( const Size
& rNewSize
, BmpScaleFlag nScaleFlag
)
989 const Size
aSize( GetSizePixel() );
992 if( aSize
.Width() && aSize
.Height() )
994 bRet
= Scale( (double) rNewSize
.Width() / aSize
.Width(),
995 (double) rNewSize
.Height() / aSize
.Height(),
1004 bool Bitmap::HasFastScale()
1006 return OpenGLHelper::isVCLOpenGLEnabled();
1009 void Bitmap::AdaptBitCount(Bitmap
& rNew
) const
1011 ImplAdaptBitCount(rNew
);
1014 void Bitmap::ImplAdaptBitCount(Bitmap
& rNew
) const
1016 // aNew is the result of some operation; adapt it's BitCount to the original (this)
1017 if(GetBitCount() != rNew
.GetBitCount())
1019 switch(GetBitCount())
1023 rNew
.Convert(BMP_CONVERSION_1BIT_THRESHOLD
);
1028 if(HasGreyPalette())
1030 rNew
.Convert(BMP_CONVERSION_4BIT_GREYS
);
1034 rNew
.Convert(BMP_CONVERSION_4BIT_COLORS
);
1040 if(HasGreyPalette())
1042 rNew
.Convert(BMP_CONVERSION_8BIT_GREYS
);
1046 rNew
.Convert(BMP_CONVERSION_8BIT_COLORS
);
1052 rNew
.Convert(BMP_CONVERSION_24BIT
);
1057 OSL_ENSURE(false, "BitDepth adaption failed (!)");
1064 bool Bitmap::ImplScaleFast( const double& rScaleX
, const double& rScaleY
)
1066 const Size
aSizePix( GetSizePixel() );
1067 const long nNewWidth
= FRound( aSizePix
.Width() * rScaleX
);
1068 const long nNewHeight
= FRound( aSizePix
.Height() * rScaleY
);
1071 if( nNewWidth
&& nNewHeight
)
1073 BitmapReadAccess
* pReadAcc
= AcquireReadAccess();
1077 Bitmap
aNewBmp( Size( nNewWidth
, nNewHeight
), GetBitCount(), &pReadAcc
->GetPalette() );
1078 BitmapWriteAccess
* pWriteAcc
= aNewBmp
.AcquireWriteAccess();
1082 const long nScanlineSize
= pWriteAcc
->GetScanlineSize();
1083 const long nNewWidth1
= nNewWidth
- 1L;
1084 const long nNewHeight1
= nNewHeight
- 1L;
1086 if( nNewWidth1
&& nNewHeight1
)
1088 const double nWidth
= pReadAcc
->Width();
1089 const double nHeight
= pReadAcc
->Height();
1090 boost::scoped_array
<long> pLutX(new long[ nNewWidth
]);
1091 boost::scoped_array
<long> pLutY(new long[ nNewHeight
]);
1093 for( long nX
= 0L; nX
< nNewWidth
; nX
++ )
1094 pLutX
[ nX
] = long(nX
* nWidth
/ nNewWidth
);
1096 for( long nY
= 0L; nY
< nNewHeight
; nY
++ )
1097 pLutY
[ nY
] = long(nY
* nHeight
/ nNewHeight
);
1100 while( nActY
< nNewHeight
)
1102 long nMapY
= pLutY
[ nActY
];
1104 for( long nX
= 0L; nX
< nNewWidth
; nX
++ )
1105 pWriteAcc
->SetPixel( nActY
, nX
, pReadAcc
->GetPixel( nMapY
, pLutX
[ nX
] ) );
1107 while( ( nActY
< nNewHeight1
) && ( pLutY
[ nActY
+ 1 ] == nMapY
) )
1109 memcpy( pWriteAcc
->GetScanline( nActY
+ 1L ),
1110 pWriteAcc
->GetScanline( nActY
), nScanlineSize
);
1117 ReleaseAccess( pWriteAcc
);
1120 ReleaseAccess( pReadAcc
);
1123 ImplAssignWithSize( aNewBmp
);
1130 bool Bitmap::ImplScaleInterpolate( const double& rScaleX
, const double& rScaleY
)
1132 const Size
aSizePix( GetSizePixel() );
1133 const long nNewWidth
= FRound( aSizePix
.Width() * rScaleX
);
1134 const long nNewHeight
= FRound( aSizePix
.Height() * rScaleY
);
1137 if( ( nNewWidth
> 1L ) && ( nNewHeight
> 1L ) )
1139 BitmapReadAccess
* pReadAcc
= AcquireReadAccess();
1142 long nWidth
= pReadAcc
->Width();
1143 long nHeight
= pReadAcc
->Height();
1144 Bitmap
aNewBmp( Size( nNewWidth
, nHeight
), 24 );
1145 BitmapWriteAccess
* pWriteAcc
= aNewBmp
.AcquireWriteAccess();
1149 const long nNewWidth1
= nNewWidth
- 1L;
1150 const long nWidth1
= pReadAcc
->Width() - 1L;
1151 const double fRevScaleX
= (double) nWidth1
/ nNewWidth1
;
1153 boost::scoped_array
<long> pLutInt(new long[ nNewWidth
]);
1154 boost::scoped_array
<long> pLutFrac(new long[ nNewWidth
]);
1156 for( long nX
= 0L, nTemp
= nWidth
- 2L; nX
< nNewWidth
; nX
++ )
1158 double fTemp
= nX
* fRevScaleX
;
1159 pLutInt
[ nX
] = MinMax( (long) fTemp
, 0, nTemp
);
1160 fTemp
-= pLutInt
[ nX
];
1161 pLutFrac
[ nX
] = (long) ( fTemp
* 1024. );
1164 for( long nY
= 0L; nY
< nHeight
; nY
++ )
1169 if( pReadAcc
->HasPalette() )
1171 aCol0
= pReadAcc
->GetPaletteColor( pReadAcc
->GetPixelIndex( nY
, 0 ) );
1175 aCol0
= pReadAcc
->GetPixel( nY
, 0 );
1178 for( long nX
= 0L; nX
< nNewWidth
; nX
++ )
1180 pWriteAcc
->SetPixel( nY
, nX
, aCol0
);
1185 for( long nX
= 0L; nX
< nNewWidth
; nX
++ )
1187 long nTemp
= pLutInt
[ nX
];
1189 BitmapColor aCol0
, aCol1
;
1190 if( pReadAcc
->HasPalette() )
1192 aCol0
= pReadAcc
->GetPaletteColor( pReadAcc
->GetPixelIndex( nY
, nTemp
++ ) );
1193 aCol1
= pReadAcc
->GetPaletteColor( pReadAcc
->GetPixelIndex( nY
, nTemp
) );
1197 aCol0
= pReadAcc
->GetPixel( nY
, nTemp
++ );
1198 aCol1
= pReadAcc
->GetPixel( nY
, nTemp
);
1201 nTemp
= pLutFrac
[ nX
];
1203 long lXR0
= aCol0
.GetRed();
1204 long lXG0
= aCol0
.GetGreen();
1205 long lXB0
= aCol0
.GetBlue();
1206 long lXR1
= aCol1
.GetRed() - lXR0
;
1207 long lXG1
= aCol1
.GetGreen() - lXG0
;
1208 long lXB1
= aCol1
.GetBlue() - lXB0
;
1210 aCol0
.SetRed( (sal_uInt8
) ( ( lXR1
* nTemp
+ ( lXR0
<< 10 ) ) >> 10 ) );
1211 aCol0
.SetGreen( (sal_uInt8
) ( ( lXG1
* nTemp
+ ( lXG0
<< 10 ) ) >> 10 ) );
1212 aCol0
.SetBlue( (sal_uInt8
) ( ( lXB1
* nTemp
+ ( lXB0
<< 10 ) ) >> 10 ) );
1214 pWriteAcc
->SetPixel( nY
, nX
, aCol0
);
1222 ReleaseAccess( pReadAcc
);
1223 ReleaseAccess( pWriteAcc
);
1228 const Bitmap
aOriginal(*this);
1230 aNewBmp
= Bitmap( Size( nNewWidth
, nNewHeight
), 24 );
1231 pReadAcc
= AcquireReadAccess();
1232 pWriteAcc
= aNewBmp
.AcquireWriteAccess();
1234 if( pReadAcc
&& pWriteAcc
)
1236 const long nNewHeight1
= nNewHeight
- 1L;
1237 const long nHeight1
= pReadAcc
->Height() - 1L;
1238 const double fRevScaleY
= (double) nHeight1
/ nNewHeight1
;
1240 boost::scoped_array
<long> pLutInt(new long[ nNewHeight
]);
1241 boost::scoped_array
<long> pLutFrac(new long[ nNewHeight
]);
1243 for( long nY
= 0L, nTemp
= nHeight
- 2L; nY
< nNewHeight
; nY
++ )
1245 double fTemp
= nY
* fRevScaleY
;
1246 pLutInt
[ nY
] = MinMax( (long) fTemp
, 0, nTemp
);
1247 fTemp
-= pLutInt
[ nY
];
1248 pLutFrac
[ nY
] = (long) ( fTemp
* 1024. );
1251 // after 1st step, bitmap *is* 24bit format (see above)
1252 OSL_ENSURE(!pReadAcc
->HasPalette(), "OOps, somehow ImplScaleInterpolate in-between format has palette, should not happen (!)");
1254 for( long nX
= 0L; nX
< nNewWidth
; nX
++ )
1258 BitmapColor aCol0
= pReadAcc
->GetPixel( 0, nX
);
1260 for( long nY
= 0L; nY
< nNewHeight
; nY
++ )
1262 pWriteAcc
->SetPixel( nY
, nX
, aCol0
);
1267 for( long nY
= 0L; nY
< nNewHeight
; nY
++ )
1269 long nTemp
= pLutInt
[ nY
];
1271 BitmapColor aCol0
= pReadAcc
->GetPixel( nTemp
++, nX
);
1272 BitmapColor aCol1
= pReadAcc
->GetPixel( nTemp
, nX
);
1274 nTemp
= pLutFrac
[ nY
];
1276 long lXR0
= aCol0
.GetRed();
1277 long lXG0
= aCol0
.GetGreen();
1278 long lXB0
= aCol0
.GetBlue();
1279 long lXR1
= aCol1
.GetRed() - lXR0
;
1280 long lXG1
= aCol1
.GetGreen() - lXG0
;
1281 long lXB1
= aCol1
.GetBlue() - lXB0
;
1283 aCol0
.SetRed( (sal_uInt8
) ( ( lXR1
* nTemp
+ ( lXR0
<< 10 ) ) >> 10 ) );
1284 aCol0
.SetGreen( (sal_uInt8
) ( ( lXG1
* nTemp
+ ( lXG0
<< 10 ) ) >> 10 ) );
1285 aCol0
.SetBlue( (sal_uInt8
) ( ( lXB1
* nTemp
+ ( lXB0
<< 10 ) ) >> 10 ) );
1287 pWriteAcc
->SetPixel( nY
, nX
, aCol0
);
1295 ReleaseAccess( pReadAcc
);
1296 ReleaseAccess( pWriteAcc
);
1300 aOriginal
.ImplAdaptBitCount(aNewBmp
);
1309 bRet
= ImplScaleFast( rScaleX
, rScaleY
);
1317 void ImplCalculateContributions(
1318 const sal_uInt32 aSourceSize
,
1319 const sal_uInt32 aDestinationSize
,
1320 sal_uInt32
& aNumberOfContributions
,
1322 sal_uInt32
*& pPixels
,
1323 sal_uInt32
*& pCount
,
1324 const Kernel
& aKernel
)
1326 const double fSamplingRadius(aKernel
.GetWidth());
1327 const double fScale(aDestinationSize
/ static_cast< double >(aSourceSize
));
1328 const double fScaledRadius((fScale
< 1.0) ? fSamplingRadius
/ fScale
: fSamplingRadius
);
1329 const double fFilterFactor((fScale
< 1.0) ? fScale
: 1.0);
1331 aNumberOfContributions
= (static_cast< sal_uInt32
>(fabs(ceil(fScaledRadius
))) * 2) + 1;
1332 const sal_uInt32
nAllocSize(aDestinationSize
* aNumberOfContributions
);
1333 pWeights
= new double[nAllocSize
];
1334 pPixels
= new sal_uInt32
[nAllocSize
];
1335 pCount
= new sal_uInt32
[aDestinationSize
];
1337 for(sal_uInt32
i(0); i
< aDestinationSize
; i
++)
1339 const sal_uInt32
aIndex(i
* aNumberOfContributions
);
1340 const double aCenter(i
/ fScale
);
1341 const sal_Int32
aLeft(static_cast< sal_Int32
>(floor(aCenter
- fScaledRadius
)));
1342 const sal_Int32
aRight(static_cast< sal_Int32
>(ceil(aCenter
+ fScaledRadius
)));
1343 sal_uInt32
aCurrentCount(0);
1345 for(sal_Int32
j(aLeft
); j
<= aRight
; j
++)
1347 const double aWeight(aKernel
.Calculate(fFilterFactor
* (aCenter
- static_cast< double>(j
))));
1349 // Reduce calculations with ignoring weights of 0.0
1350 if(fabs(aWeight
) < 0.0001)
1355 // Handling on edges
1356 const sal_uInt32
aPixelIndex(MinMax(j
, 0, aSourceSize
- 1));
1357 const sal_uInt32
nIndex(aIndex
+ aCurrentCount
);
1359 pWeights
[nIndex
] = aWeight
;
1360 pPixels
[nIndex
] = aPixelIndex
;
1365 pCount
[i
] = aCurrentCount
;
1369 bool ImplScaleConvolutionHor(
1372 const double& rScaleX
,
1373 const Kernel
& aKernel
)
1375 // Do horizontal filtering
1376 OSL_ENSURE(rScaleX
> 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
1377 const sal_uInt32
nWidth(rSource
.GetSizePixel().Width());
1378 const sal_uInt32
nNewWidth(FRound(nWidth
* rScaleX
));
1380 if(nWidth
== nNewWidth
)
1385 BitmapReadAccess
* pReadAcc
= rSource
.AcquireReadAccess();
1389 double* pWeights
= 0;
1390 sal_uInt32
* pPixels
= 0;
1391 sal_uInt32
* pCount
= 0;
1392 sal_uInt32
aNumberOfContributions(0);
1394 const sal_uInt32
nHeight(rSource
.GetSizePixel().Height());
1395 ImplCalculateContributions(nWidth
, nNewWidth
, aNumberOfContributions
, pWeights
, pPixels
, pCount
, aKernel
);
1396 rTarget
= Bitmap(Size(nNewWidth
, nHeight
), 24);
1397 BitmapWriteAccess
* pWriteAcc
= rTarget
.AcquireWriteAccess();
1398 bool bResult(0 != pWriteAcc
);
1402 for(sal_uInt32
y(0); y
< nHeight
; y
++)
1404 for(sal_uInt32
x(0); x
< nNewWidth
; x
++)
1406 const sal_uInt32
aBaseIndex(x
* aNumberOfContributions
);
1408 double aValueRed(0.0);
1409 double aValueGreen(0.0);
1410 double aValueBlue(0.0);
1412 for(sal_uInt32
j(0); j
< pCount
[x
]; j
++)
1414 const sal_uInt32
aIndex(aBaseIndex
+ j
);
1415 const double aWeight(pWeights
[aIndex
]);
1420 if(pReadAcc
->HasPalette())
1422 aColor
= pReadAcc
->GetPaletteColor(pReadAcc
->GetPixelIndex(y
, pPixels
[aIndex
]));
1426 aColor
= pReadAcc
->GetPixel(y
, pPixels
[aIndex
]);
1429 aValueRed
+= aWeight
* aColor
.GetRed();
1430 aValueGreen
+= aWeight
* aColor
.GetGreen();
1431 aValueBlue
+= aWeight
* aColor
.GetBlue();
1434 const BitmapColor
aResultColor(
1435 static_cast< sal_uInt8
>(MinMax(static_cast< sal_Int32
>(aValueRed
/ aSum
), 0, 255)),
1436 static_cast< sal_uInt8
>(MinMax(static_cast< sal_Int32
>(aValueGreen
/ aSum
), 0, 255)),
1437 static_cast< sal_uInt8
>(MinMax(static_cast< sal_Int32
>(aValueBlue
/ aSum
), 0, 255)));
1439 pWriteAcc
->SetPixel(y
, x
, aResultColor
);
1443 Bitmap::ReleaseAccess(pWriteAcc
);
1446 Bitmap::ReleaseAccess(pReadAcc
);
1460 bool ImplScaleConvolutionVer(
1463 const double& rScaleY
,
1464 const Kernel
& aKernel
)
1466 // Do vertical filtering
1467 OSL_ENSURE(rScaleY
> 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
1468 const sal_uInt32
nHeight(rSource
.GetSizePixel().Height());
1469 const sal_uInt32
nNewHeight(FRound(nHeight
* rScaleY
));
1471 if(nHeight
== nNewHeight
)
1476 BitmapReadAccess
* pReadAcc
= rSource
.AcquireReadAccess();
1480 double* pWeights
= 0;
1481 sal_uInt32
* pPixels
= 0;
1482 sal_uInt32
* pCount
= 0;
1483 sal_uInt32
aNumberOfContributions(0);
1485 const sal_uInt32
nWidth(rSource
.GetSizePixel().Width());
1486 ImplCalculateContributions(nHeight
, nNewHeight
, aNumberOfContributions
, pWeights
, pPixels
, pCount
, aKernel
);
1487 rTarget
= Bitmap(Size(nWidth
, nNewHeight
), 24);
1488 BitmapWriteAccess
* pWriteAcc
= rTarget
.AcquireWriteAccess();
1489 bool bResult(0 != pWriteAcc
);
1493 for(sal_uInt32
x(0); x
< nWidth
; x
++)
1495 for(sal_uInt32
y(0); y
< nNewHeight
; y
++)
1497 const sal_uInt32
aBaseIndex(y
* aNumberOfContributions
);
1499 double aValueRed(0.0);
1500 double aValueGreen(0.0);
1501 double aValueBlue(0.0);
1503 for(sal_uInt32
j(0); j
< pCount
[y
]; j
++)
1505 const sal_uInt32
aIndex(aBaseIndex
+ j
);
1506 const double aWeight(pWeights
[aIndex
]);
1511 if(pReadAcc
->HasPalette())
1513 aColor
= pReadAcc
->GetPaletteColor(pReadAcc
->GetPixelIndex(pPixels
[aIndex
], x
));
1517 aColor
= pReadAcc
->GetPixel(pPixels
[aIndex
], x
);
1520 aValueRed
+= aWeight
* aColor
.GetRed();
1521 aValueGreen
+= aWeight
* aColor
.GetGreen();
1522 aValueBlue
+= aWeight
* aColor
.GetBlue();
1525 const BitmapColor
aResultColor(
1526 static_cast< sal_uInt8
>(MinMax(static_cast< sal_Int32
>(aValueRed
/ aSum
), 0, 255)),
1527 static_cast< sal_uInt8
>(MinMax(static_cast< sal_Int32
>(aValueGreen
/ aSum
), 0, 255)),
1528 static_cast< sal_uInt8
>(MinMax(static_cast< sal_Int32
>(aValueBlue
/ aSum
), 0, 255)));
1530 if(pWriteAcc
->HasPalette())
1532 pWriteAcc
->SetPixelIndex(y
, x
, static_cast< sal_uInt8
>(pWriteAcc
->GetBestPaletteIndex(aResultColor
)));
1536 pWriteAcc
->SetPixel(y
, x
, aResultColor
);
1542 Bitmap::ReleaseAccess(pWriteAcc
);
1543 Bitmap::ReleaseAccess(pReadAcc
);
1559 // #i121233# Added BmpScaleFlag::Lanczos, BmpScaleFlag::BiCubic, BmpScaleFlag::BiLinear and
1560 // BmpScaleFlag::Box derived from the original commit from Tomas Vajngerl (see
1561 // bugzilla task for deitails) Thanks!
1562 bool Bitmap::ImplScaleConvolution(
1563 const double& rScaleX
,
1564 const double& rScaleY
,
1565 const Kernel
& aKernel
)
1567 const bool bMirrorHor(rScaleX
< 0.0);
1568 const bool bMirrorVer(rScaleY
< 0.0);
1569 const double fScaleX(bMirrorHor
? -rScaleX
: rScaleX
);
1570 const double fScaleY(bMirrorVer
? -rScaleY
: rScaleY
);
1571 const sal_uInt32
nWidth(GetSizePixel().Width());
1572 const sal_uInt32
nHeight(GetSizePixel().Height());
1573 const sal_uInt32
nNewWidth(FRound(nWidth
* fScaleX
));
1574 const sal_uInt32
nNewHeight(FRound(nHeight
* fScaleY
));
1575 const bool bScaleHor(nWidth
!= nNewWidth
);
1576 const bool bScaleVer(nHeight
!= nNewHeight
);
1577 const bool bMirror(bMirrorHor
|| bMirrorVer
);
1579 if(!bMirror
&& !bScaleHor
&& !bScaleVer
)
1585 BmpMirrorFlags
nMirrorFlags(BmpMirrorFlags::NONE
);
1586 bool bMirrorAfter(false);
1592 nMirrorFlags
|= BmpMirrorFlags::Horizontal
;
1597 nMirrorFlags
|= BmpMirrorFlags::Vertical
;
1600 const sal_uInt32
nStartSize(nWidth
* nHeight
);
1601 const sal_uInt32
nEndSize(nNewWidth
* nNewHeight
);
1603 bMirrorAfter
= nStartSize
> nEndSize
;
1607 bResult
= Mirror(nMirrorFlags
);
1615 const sal_uInt32
nInBetweenSizeHorFirst(nHeight
* nNewWidth
);
1616 const sal_uInt32
nInBetweenSizeVerFirst(nNewHeight
* nWidth
);
1617 Bitmap
aSource(*this);
1619 if(nInBetweenSizeHorFirst
< nInBetweenSizeVerFirst
)
1623 bResult
= ImplScaleConvolutionHor(aSource
, aResult
, fScaleX
, aKernel
);
1626 if(bResult
&& bScaleVer
)
1630 // copy partial result, independent of color depth
1634 bResult
= ImplScaleConvolutionVer(aSource
, aResult
, fScaleY
, aKernel
);
1641 bResult
= ImplScaleConvolutionVer(aSource
, aResult
, fScaleY
, aKernel
);
1644 if(bResult
&& bScaleHor
)
1648 // copy partial result, independent of color depth
1652 bResult
= ImplScaleConvolutionHor(aSource
, aResult
, fScaleX
, aKernel
);
1657 if(bResult
&& bMirrorAfter
)
1659 bResult
= aResult
.Mirror(nMirrorFlags
);
1664 ImplAdaptBitCount(aResult
);
1671 bool Bitmap::Dither( BmpDitherFlags nDitherFlags
)
1675 const Size
aSizePix( GetSizePixel() );
1677 if( aSizePix
.Width() == 1 || aSizePix
.Height() == 1 )
1679 else if( nDitherFlags
& BmpDitherFlags::Matrix
)
1680 bRet
= ImplDitherMatrix();
1681 else if( nDitherFlags
& BmpDitherFlags::Floyd
)
1682 bRet
= ImplDitherFloyd();
1683 else if( ( nDitherFlags
& BmpDitherFlags::Floyd16
) && ( GetBitCount() == 24 ) )
1684 bRet
= ImplDitherFloyd16();
1689 bool Bitmap::ImplDitherMatrix()
1691 BitmapReadAccess
* pReadAcc
= AcquireReadAccess();
1692 Bitmap
aNewBmp( GetSizePixel(), 8 );
1693 BitmapWriteAccess
* pWriteAcc
= aNewBmp
.AcquireWriteAccess();
1696 if( pReadAcc
&& pWriteAcc
)
1698 const sal_uLong nWidth
= pReadAcc
->Width();
1699 const sal_uLong nHeight
= pReadAcc
->Height();
1700 BitmapColor
aIndex( (sal_uInt8
) 0 );
1702 if( pReadAcc
->HasPalette() )
1704 for( sal_uLong nY
= 0UL; nY
< nHeight
; nY
++ )
1706 for( sal_uLong nX
= 0UL, nModY
= ( nY
& 0x0FUL
) << 4UL; nX
< nWidth
; nX
++ )
1708 const BitmapColor
aCol( pReadAcc
->GetPaletteColor( pReadAcc
->GetPixelIndex( nY
, nX
) ) );
1709 const sal_uLong nD
= nVCLDitherLut
[ nModY
+ ( nX
& 0x0FUL
) ];
1710 const sal_uLong nR
= ( nVCLLut
[ aCol
.GetRed() ] + nD
) >> 16UL;
1711 const sal_uLong nG
= ( nVCLLut
[ aCol
.GetGreen() ] + nD
) >> 16UL;
1712 const sal_uLong nB
= ( nVCLLut
[ aCol
.GetBlue() ] + nD
) >> 16UL;
1714 aIndex
.SetIndex( (sal_uInt8
) ( nVCLRLut
[ nR
] + nVCLGLut
[ nG
] + nVCLBLut
[ nB
] ) );
1715 pWriteAcc
->SetPixel( nY
, nX
, aIndex
);
1721 for( sal_uLong nY
= 0UL; nY
< nHeight
; nY
++ )
1723 for( sal_uLong nX
= 0UL, nModY
= ( nY
& 0x0FUL
) << 4UL; nX
< nWidth
; nX
++ )
1725 const BitmapColor
aCol( pReadAcc
->GetPixel( nY
, nX
) );
1726 const sal_uLong nD
= nVCLDitherLut
[ nModY
+ ( nX
& 0x0FUL
) ];
1727 const sal_uLong nR
= ( nVCLLut
[ aCol
.GetRed() ] + nD
) >> 16UL;
1728 const sal_uLong nG
= ( nVCLLut
[ aCol
.GetGreen() ] + nD
) >> 16UL;
1729 const sal_uLong nB
= ( nVCLLut
[ aCol
.GetBlue() ] + nD
) >> 16UL;
1731 aIndex
.SetIndex( (sal_uInt8
) ( nVCLRLut
[ nR
] + nVCLGLut
[ nG
] + nVCLBLut
[ nB
] ) );
1732 pWriteAcc
->SetPixel( nY
, nX
, aIndex
);
1740 ReleaseAccess( pReadAcc
);
1741 ReleaseAccess( pWriteAcc
);
1745 const MapMode
aMap( maPrefMapMode
);
1746 const Size
aSize( maPrefSize
);
1750 maPrefMapMode
= aMap
;
1757 bool Bitmap::ImplDitherFloyd()
1759 const Size
aSize( GetSizePixel() );
1762 if( ( aSize
.Width() > 3 ) && ( aSize
.Height() > 2 ) )
1764 BitmapReadAccess
* pReadAcc
= AcquireReadAccess();
1765 Bitmap
aNewBmp( GetSizePixel(), 8 );
1766 BitmapWriteAccess
* pWriteAcc
= aNewBmp
.AcquireWriteAccess();
1768 if( pReadAcc
&& pWriteAcc
)
1771 long nWidth
= pReadAcc
->Width();
1772 long nWidth1
= nWidth
- 1L;
1773 long nHeight
= pReadAcc
->Height();
1775 long nW
= nWidth
* 3L;
1777 long nRErr
, nGErr
, nBErr
;
1779 boost::scoped_array
<long> p1(new long[ nW
]);
1780 boost::scoped_array
<long> p2(new long[ nW
]);
1781 long* p1T
= p1
.get();
1782 long* p2T
= p2
.get();
1784 bool bPal
= pReadAcc
->HasPalette();
1790 for( long nZ
= 0; nZ
< nWidth
; nZ
++ )
1792 aColor
= pReadAcc
->GetPaletteColor( pReadAcc
->GetPixelIndex( 0, nZ
) );
1794 *pTmp
++ = (long) aColor
.GetBlue() << 12;
1795 *pTmp
++ = (long) aColor
.GetGreen() << 12;
1796 *pTmp
++ = (long) aColor
.GetRed() << 12;
1801 for( long nZ
= 0; nZ
< nWidth
; nZ
++ )
1803 aColor
= pReadAcc
->GetPixel( 0, nZ
);
1805 *pTmp
++ = (long) aColor
.GetBlue() << 12;
1806 *pTmp
++ = (long) aColor
.GetGreen() << 12;
1807 *pTmp
++ = (long) aColor
.GetRed() << 12;
1811 for( long nY
= 1, nYAcc
= 0L; nY
<= nHeight
; nY
++, nYAcc
++ )
1821 for( long nZ
= 0; nZ
< nWidth
; nZ
++ )
1823 aColor
= pReadAcc
->GetPaletteColor( pReadAcc
->GetPixelIndex( nY
, nZ
) );
1825 *pTmp
++ = (long) aColor
.GetBlue() << 12;
1826 *pTmp
++ = (long) aColor
.GetGreen() << 12;
1827 *pTmp
++ = (long) aColor
.GetRed() << 12;
1832 for( long nZ
= 0; nZ
< nWidth
; nZ
++ )
1834 aColor
= pReadAcc
->GetPixel( nY
, nZ
);
1836 *pTmp
++ = (long) aColor
.GetBlue() << 12;
1837 *pTmp
++ = (long) aColor
.GetGreen() << 12;
1838 *pTmp
++ = (long) aColor
.GetRed() << 12;
1843 // Examine first Pixel separately
1850 pWriteAcc
->SetPixelIndex( nYAcc
, 0, static_cast<sal_uInt8
>(nVCLBLut
[ nBC
] + nVCLGLut
[nGC
] + nVCLRLut
[nRC
]) );
1852 // Get middle Pixels using a loop
1854 for ( nX
= 3L, nXAcc
= 1L; nX
< nW2
; nXAcc
++ )
1861 pWriteAcc
->SetPixelIndex( nYAcc
, nXAcc
, static_cast<sal_uInt8
>(nVCLBLut
[ nBC
] + nVCLGLut
[nGC
] + nVCLRLut
[nRC
]) );
1864 // Treat last Pixel separately
1869 pWriteAcc
->SetPixelIndex( nYAcc
, nWidth1
, static_cast<sal_uInt8
>(nVCLBLut
[ nBC
] + nVCLGLut
[nGC
] + nVCLRLut
[nRC
]) );
1875 ReleaseAccess( pReadAcc
);
1876 ReleaseAccess( pWriteAcc
);
1880 const MapMode
aMap( maPrefMapMode
);
1881 const Size
aPrefSize( maPrefSize
);
1885 maPrefMapMode
= aMap
;
1886 maPrefSize
= aPrefSize
;
1893 bool Bitmap::ImplDitherFloyd16()
1895 BitmapReadAccess
* pReadAcc
= AcquireReadAccess();
1896 Bitmap
aNewBmp( GetSizePixel(), 24 );
1897 BitmapWriteAccess
* pWriteAcc
= aNewBmp
.AcquireWriteAccess();
1900 if( pReadAcc
&& pWriteAcc
)
1902 const long nWidth
= pWriteAcc
->Width();
1903 const long nWidth1
= nWidth
- 1L;
1904 const long nHeight
= pWriteAcc
->Height();
1906 BitmapColor aBestCol
;
1907 ImpErrorQuad aErrQuad
;
1908 boost::scoped_array
<ImpErrorQuad
> pErrQuad1(new ImpErrorQuad
[ nWidth
]);
1909 boost::scoped_array
<ImpErrorQuad
> pErrQuad2(new ImpErrorQuad
[ nWidth
]);
1910 ImpErrorQuad
* pQLine1
= pErrQuad1
.get();
1911 ImpErrorQuad
* pQLine2
= 0;
1915 for( long nY
= 0L; nY
< std::min( nHeight
, 2L ); nY
++, nYTmp
++ )
1917 pQLine2
= !nY
? pErrQuad1
.get() : pErrQuad2
.get();
1918 for( long nX
= 0L; nX
< nWidth
; nX
++ )
1919 pQLine2
[ nX
] = pReadAcc
->GetPixel( nYTmp
, nX
);
1922 for( long nY
= 0L; nY
< nHeight
; nY
++, nYTmp
++ )
1925 aBestCol
= pQLine1
[ 0 ].ImplGetColor();
1926 aBestCol
.SetRed( ( aBestCol
.GetRed() & 248 ) | 7 );
1927 aBestCol
.SetGreen( ( aBestCol
.GetGreen() & 248 ) | 7 );
1928 aBestCol
.SetBlue( ( aBestCol
.GetBlue() & 248 ) | 7 );
1929 pWriteAcc
->SetPixel( nY
, 0, aBestCol
);
1932 for( nX
= 1L; nX
< nWidth1
; nX
++ )
1934 aColor
= pQLine1
[ nX
].ImplGetColor();
1935 aBestCol
.SetRed( ( aColor
.GetRed() & 248 ) | 7 );
1936 aBestCol
.SetGreen( ( aColor
.GetGreen() & 248 ) | 7 );
1937 aBestCol
.SetBlue( ( aColor
.GetBlue() & 248 ) | 7 );
1938 aErrQuad
= ( ImpErrorQuad( aColor
) -= aBestCol
);
1939 pQLine1
[ ++nX
].ImplAddColorError7( aErrQuad
);
1940 pQLine2
[ nX
-- ].ImplAddColorError1( aErrQuad
);
1941 pQLine2
[ nX
-- ].ImplAddColorError5( aErrQuad
);
1942 pQLine2
[ nX
++ ].ImplAddColorError3( aErrQuad
);
1943 pWriteAcc
->SetPixel( nY
, nX
, aBestCol
);
1947 aBestCol
= pQLine1
[ nWidth1
].ImplGetColor();
1948 aBestCol
.SetRed( ( aBestCol
.GetRed() & 248 ) | 7 );
1949 aBestCol
.SetGreen( ( aBestCol
.GetGreen() & 248 ) | 7 );
1950 aBestCol
.SetBlue( ( aBestCol
.GetBlue() & 248 ) | 7 );
1951 pWriteAcc
->SetPixel( nY
, nX
, aBestCol
);
1953 // Refill/copy row buffer
1955 pQLine2
= ( bQ1
= !bQ1
) ? pErrQuad2
.get() : pErrQuad1
.get();
1957 if( nYTmp
< nHeight
)
1958 for( nX
= 0L; nX
< nWidth
; nX
++ )
1959 pQLine2
[ nX
] = pReadAcc
->GetPixel( nYTmp
, nX
);
1965 ReleaseAccess( pReadAcc
);
1966 ReleaseAccess( pWriteAcc
);
1970 const MapMode
aMap( maPrefMapMode
);
1971 const Size
aSize( maPrefSize
);
1975 maPrefMapMode
= aMap
;
1982 bool Bitmap::ReduceColors( sal_uInt16 nColorCount
, BmpReduce eReduce
)
1986 if( GetColorCount() <= (sal_uLong
) nColorCount
)
1988 else if( nColorCount
)
1990 if( BMP_REDUCE_SIMPLE
== eReduce
)
1991 bRet
= ImplReduceSimple( nColorCount
);
1992 else if( BMP_REDUCE_POPULAR
== eReduce
)
1993 bRet
= ImplReducePopular( nColorCount
);
1995 bRet
= ImplReduceMedian( nColorCount
);
2003 bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount
)
2006 BitmapReadAccess
* pRAcc
= AcquireReadAccess();
2007 const sal_uInt16 nColCount
= std::min( nColorCount
, (sal_uInt16
) 256 );
2008 sal_uInt16 nBitCount
;
2011 if( nColCount
<= 2 )
2013 else if( nColCount
<= 16 )
2020 Octree
aOct( *pRAcc
, nColCount
);
2021 const BitmapPalette
& rPal
= aOct
.GetPalette();
2022 BitmapWriteAccess
* pWAcc
;
2024 aNewBmp
= Bitmap( GetSizePixel(), nBitCount
, &rPal
);
2025 pWAcc
= aNewBmp
.AcquireWriteAccess();
2029 const long nWidth
= pRAcc
->Width();
2030 const long nHeight
= pRAcc
->Height();
2032 if( pRAcc
->HasPalette() )
2034 for( long nY
= 0L; nY
< nHeight
; nY
++ )
2035 for( long nX
=0L; nX
< nWidth
; nX
++ )
2036 pWAcc
->SetPixelIndex( nY
, nX
, static_cast<sal_uInt8
>(aOct
.GetBestPaletteIndex( pRAcc
->GetPaletteColor( pRAcc
->GetPixelIndex( nY
, nX
) ))) );
2040 for( long nY
= 0L; nY
< nHeight
; nY
++ )
2041 for( long nX
=0L; nX
< nWidth
; nX
++ )
2042 pWAcc
->SetPixelIndex( nY
, nX
, static_cast<sal_uInt8
>(aOct
.GetBestPaletteIndex( pRAcc
->GetPixel( nY
, nX
) )) );
2045 ReleaseAccess( pWAcc
);
2049 ReleaseAccess( pRAcc
);
2054 const MapMode
aMap( maPrefMapMode
);
2055 const Size
aSize( maPrefSize
);
2058 maPrefMapMode
= aMap
;
2065 struct PopularColorCount
2071 extern "C" int SAL_CALL
ImplPopularCmpFnc( const void* p1
, const void* p2
)
2075 if( static_cast<PopularColorCount
const *>(p1
)->mnCount
< static_cast<PopularColorCount
const *>(p2
)->mnCount
)
2077 else if( static_cast<PopularColorCount
const *>(p1
)->mnCount
== static_cast<PopularColorCount
const *>(p2
)->mnCount
)
2085 bool Bitmap::ImplReducePopular( sal_uInt16 nColCount
)
2087 BitmapReadAccess
* pRAcc
= AcquireReadAccess();
2088 sal_uInt16 nBitCount
;
2091 if( nColCount
> 256 )
2094 if( nColCount
< 17 )
2101 const sal_uInt32 nValidBits
= 4;
2102 const sal_uInt32 nRightShiftBits
= 8 - nValidBits
;
2103 const sal_uInt32 nLeftShiftBits1
= nValidBits
;
2104 const sal_uInt32 nLeftShiftBits2
= nValidBits
<< 1;
2105 const sal_uInt32 nColorsPerComponent
= 1 << nValidBits
;
2106 const sal_uInt32 nColorOffset
= 256 / nColorsPerComponent
;
2107 const sal_uInt32 nTotalColors
= nColorsPerComponent
* nColorsPerComponent
* nColorsPerComponent
;
2108 const long nWidth
= pRAcc
->Width();
2109 const long nHeight
= pRAcc
->Height();
2110 boost::scoped_array
<PopularColorCount
> pCountTable(new PopularColorCount
[ nTotalColors
]);
2112 memset( pCountTable
.get(), 0, nTotalColors
* sizeof( PopularColorCount
) );
2114 for( long nR
= 0, nIndex
= 0; nR
< 256; nR
+= nColorOffset
)
2116 for( long nG
= 0; nG
< 256; nG
+= nColorOffset
)
2118 for( long nB
= 0; nB
< 256; nB
+= nColorOffset
)
2120 pCountTable
[ nIndex
].mnIndex
= nIndex
;
2126 if( pRAcc
->HasPalette() )
2128 for( long nY
= 0L; nY
< nHeight
; nY
++ )
2130 for( long nX
= 0L; nX
< nWidth
; nX
++ )
2132 const BitmapColor
& rCol
= pRAcc
->GetPaletteColor( pRAcc
->GetPixelIndex( nY
, nX
) );
2133 pCountTable
[ ( ( ( (sal_uInt32
) rCol
.GetRed() ) >> nRightShiftBits
) << nLeftShiftBits2
) |
2134 ( ( ( (sal_uInt32
) rCol
.GetGreen() ) >> nRightShiftBits
) << nLeftShiftBits1
) |
2135 ( ( (sal_uInt32
) rCol
.GetBlue() ) >> nRightShiftBits
) ].mnCount
++;
2141 for( long nY
= 0L; nY
< nHeight
; nY
++ )
2143 for( long nX
= 0L; nX
< nWidth
; nX
++ )
2145 const BitmapColor
aCol( pRAcc
->GetPixel( nY
, nX
) );
2146 pCountTable
[ ( ( ( (sal_uInt32
) aCol
.GetRed() ) >> nRightShiftBits
) << nLeftShiftBits2
) |
2147 ( ( ( (sal_uInt32
) aCol
.GetGreen() ) >> nRightShiftBits
) << nLeftShiftBits1
) |
2148 ( ( (sal_uInt32
) aCol
.GetBlue() ) >> nRightShiftBits
) ].mnCount
++;
2153 BitmapPalette
aNewPal( nColCount
);
2155 qsort( pCountTable
.get(), nTotalColors
, sizeof( PopularColorCount
), ImplPopularCmpFnc
);
2157 for( sal_uInt16 n
= 0; n
< nColCount
; n
++ )
2159 const PopularColorCount
& rPop
= pCountTable
[ n
];
2160 aNewPal
[ n
] = BitmapColor( (sal_uInt8
) ( ( rPop
.mnIndex
>> nLeftShiftBits2
) << nRightShiftBits
),
2161 (sal_uInt8
) ( ( ( rPop
.mnIndex
>> nLeftShiftBits1
) & ( nColorsPerComponent
- 1 ) ) << nRightShiftBits
),
2162 (sal_uInt8
) ( ( rPop
.mnIndex
& ( nColorsPerComponent
- 1 ) ) << nRightShiftBits
) );
2165 Bitmap
aNewBmp( GetSizePixel(), nBitCount
, &aNewPal
);
2166 BitmapWriteAccess
* pWAcc
= aNewBmp
.AcquireWriteAccess();
2170 BitmapColor
aDstCol( (sal_uInt8
) 0 );
2171 boost::scoped_array
<sal_uInt8
> pIndexMap(new sal_uInt8
[ nTotalColors
]);
2173 for( long nR
= 0, nIndex
= 0; nR
< 256; nR
+= nColorOffset
)
2174 for( long nG
= 0; nG
< 256; nG
+= nColorOffset
)
2175 for( long nB
= 0; nB
< 256; nB
+= nColorOffset
)
2176 pIndexMap
[ nIndex
++ ] = (sal_uInt8
) aNewPal
.GetBestIndex( BitmapColor( (sal_uInt8
) nR
, (sal_uInt8
) nG
, (sal_uInt8
) nB
) );
2178 if( pRAcc
->HasPalette() )
2180 for( long nY
= 0L; nY
< nHeight
; nY
++ )
2182 for( long nX
= 0L; nX
< nWidth
; nX
++ )
2184 const BitmapColor
& rCol
= pRAcc
->GetPaletteColor( pRAcc
->GetPixelIndex( nY
, nX
) );
2185 aDstCol
.SetIndex( pIndexMap
[ ( ( ( (sal_uInt32
) rCol
.GetRed() ) >> nRightShiftBits
) << nLeftShiftBits2
) |
2186 ( ( ( (sal_uInt32
) rCol
.GetGreen() ) >> nRightShiftBits
) << nLeftShiftBits1
) |
2187 ( ( (sal_uInt32
) rCol
.GetBlue() ) >> nRightShiftBits
) ] );
2188 pWAcc
->SetPixel( nY
, nX
, aDstCol
);
2194 for( long nY
= 0L; nY
< nHeight
; nY
++ )
2196 for( long nX
= 0L; nX
< nWidth
; nX
++ )
2198 const BitmapColor
aCol( pRAcc
->GetPixel( nY
, nX
) );
2199 aDstCol
.SetIndex( pIndexMap
[ ( ( ( (sal_uInt32
) aCol
.GetRed() ) >> nRightShiftBits
) << nLeftShiftBits2
) |
2200 ( ( ( (sal_uInt32
) aCol
.GetGreen() ) >> nRightShiftBits
) << nLeftShiftBits1
) |
2201 ( ( (sal_uInt32
) aCol
.GetBlue() ) >> nRightShiftBits
) ] );
2202 pWAcc
->SetPixel( nY
, nX
, aDstCol
);
2207 ReleaseAccess( pWAcc
);
2211 pCountTable
.reset();
2212 ReleaseAccess( pRAcc
);
2216 const MapMode
aMap( maPrefMapMode
);
2217 const Size
aSize( maPrefSize
);
2220 maPrefMapMode
= aMap
;
2228 bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount
)
2230 BitmapReadAccess
* pRAcc
= AcquireReadAccess();
2231 sal_uInt16 nBitCount
;
2234 if( nColCount
< 17 )
2236 else if( nColCount
< 257 )
2240 OSL_FAIL( "Bitmap::ImplReduceMedian(): invalid color count!" );
2247 Bitmap
aNewBmp( GetSizePixel(), nBitCount
);
2248 BitmapWriteAccess
* pWAcc
= aNewBmp
.AcquireWriteAccess();
2252 const sal_uLong nSize
= 32768UL * sizeof( sal_uLong
);
2253 sal_uLong
* pColBuf
= static_cast<sal_uLong
*>(rtl_allocateMemory( nSize
));
2254 const long nWidth
= pWAcc
->Width();
2255 const long nHeight
= pWAcc
->Height();
2258 memset( pColBuf
, 0, nSize
);
2261 if( pRAcc
->HasPalette() )
2263 for( long nY
= 0L; nY
< nHeight
; nY
++ )
2265 for( long nX
= 0L; nX
< nWidth
; nX
++ )
2267 const BitmapColor
& rCol
= pRAcc
->GetPaletteColor( pRAcc
->GetPixelIndex( nY
, nX
) );
2268 pColBuf
[ RGB15( rCol
.GetRed() >> 3, rCol
.GetGreen() >> 3, rCol
.GetBlue() >> 3 ) ]++;
2274 for( long nY
= 0L; nY
< nHeight
; nY
++ )
2276 for( long nX
= 0L; nX
< nWidth
; nX
++ )
2278 const BitmapColor
aCol( pRAcc
->GetPixel( nY
, nX
) );
2279 pColBuf
[ RGB15( aCol
.GetRed() >> 3, aCol
.GetGreen() >> 3, aCol
.GetBlue() >> 3 ) ]++;
2284 // create palette via median cut
2285 BitmapPalette
aPal( pWAcc
->GetPaletteEntryCount() );
2286 ImplMedianCut( pColBuf
, aPal
, 0, 31, 0, 31, 0, 31,
2287 nColCount
, nWidth
* nHeight
, nIndex
);
2289 // do mapping of colors to palette
2290 InverseColorMap
aMap( aPal
);
2291 pWAcc
->SetPalette( aPal
);
2292 for( long nY
= 0L; nY
< nHeight
; nY
++ )
2293 for( long nX
= 0L; nX
< nWidth
; nX
++ )
2294 pWAcc
->SetPixelIndex( nY
, nX
, static_cast<sal_uInt8
>( aMap
.GetBestPaletteIndex( pRAcc
->GetColor( nY
, nX
) )) );
2296 rtl_freeMemory( pColBuf
);
2297 ReleaseAccess( pWAcc
);
2301 ReleaseAccess( pRAcc
);
2305 const MapMode
aMap( maPrefMapMode
);
2306 const Size
aSize( maPrefSize
);
2309 maPrefMapMode
= aMap
;
2317 void Bitmap::ImplMedianCut( sal_uLong
* pColBuf
, BitmapPalette
& rPal
,
2318 long nR1
, long nR2
, long nG1
, long nG2
, long nB1
, long nB2
,
2319 long nColors
, long nPixels
, long& rIndex
)
2325 const long nRLen
= nR2
- nR1
;
2326 const long nGLen
= nG2
- nG1
;
2327 const long nBLen
= nB2
- nB1
;
2328 sal_uLong
* pBuf
= pColBuf
;
2330 if( !nRLen
&& !nGLen
&& !nBLen
)
2332 if( pBuf
[ RGB15( nR1
, nG1
, nB1
) ] )
2334 aCol
.SetRed( (sal_uInt8
) ( nR1
<< 3 ) );
2335 aCol
.SetGreen( (sal_uInt8
) ( nG1
<< 3 ) );
2336 aCol
.SetBlue( (sal_uInt8
) ( nB1
<< 3 ) );
2337 rPal
[ (sal_uInt16
) rIndex
++ ] = aCol
;
2342 if( 1 == nColors
|| 1 == nPixels
)
2344 long nPixSum
= 0, nRSum
= 0, nGSum
= 0, nBSum
= 0;
2346 for( long nR
= nR1
; nR
<= nR2
; nR
++ )
2348 for( long nG
= nG1
; nG
<= nG2
; nG
++ )
2350 for( long nB
= nB1
; nB
<= nB2
; nB
++ )
2352 nPixSum
= pBuf
[ RGB15( nR
, nG
, nB
) ];
2356 nRSum
+= nR
* nPixSum
;
2357 nGSum
+= nG
* nPixSum
;
2358 nBSum
+= nB
* nPixSum
;
2364 aCol
.SetRed( (sal_uInt8
) ( ( nRSum
/ nPixels
) << 3 ) );
2365 aCol
.SetGreen( (sal_uInt8
) ( ( nGSum
/ nPixels
) << 3 ) );
2366 aCol
.SetBlue( (sal_uInt8
) ( ( nBSum
/ nPixels
) << 3 ) );
2367 rPal
[ (sal_uInt16
) rIndex
++ ] = aCol
;
2371 const long nTest
= ( nPixels
>> 1 );
2375 if( nBLen
> nGLen
&& nBLen
> nRLen
)
2379 while( nPixNew
< nTest
)
2381 nB
++, nPixOld
= nPixNew
;
2382 for( long nR
= nR1
; nR
<= nR2
; nR
++ )
2383 for( long nG
= nG1
; nG
<= nG2
; nG
++ )
2384 nPixNew
+= pBuf
[ RGB15( nR
, nG
, nB
) ];
2389 ImplMedianCut( pBuf
, rPal
, nR1
, nR2
, nG1
, nG2
, nB1
, nB
, nColors
>> 1, nPixNew
, rIndex
);
2390 ImplMedianCut( pBuf
, rPal
, nR1
, nR2
, nG1
, nG2
, nB
+ 1, nB2
, nColors
>> 1, nPixels
- nPixNew
, rIndex
);
2394 ImplMedianCut( pBuf
, rPal
, nR1
, nR2
, nG1
, nG2
, nB1
, nB
- 1, nColors
>> 1, nPixOld
, rIndex
);
2395 ImplMedianCut( pBuf
, rPal
, nR1
, nR2
, nG1
, nG2
, nB
, nB2
, nColors
>> 1, nPixels
- nPixOld
, rIndex
);
2398 else if( nGLen
> nRLen
)
2402 while( nPixNew
< nTest
)
2404 nG
++, nPixOld
= nPixNew
;
2405 for( long nR
= nR1
; nR
<= nR2
; nR
++ )
2406 for( long nB
= nB1
; nB
<= nB2
; nB
++ )
2407 nPixNew
+= pBuf
[ RGB15( nR
, nG
, nB
) ];
2412 ImplMedianCut( pBuf
, rPal
, nR1
, nR2
, nG1
, nG
, nB1
, nB2
, nColors
>> 1, nPixNew
, rIndex
);
2413 ImplMedianCut( pBuf
, rPal
, nR1
, nR2
, nG
+ 1, nG2
, nB1
, nB2
, nColors
>> 1, nPixels
- nPixNew
, rIndex
);
2417 ImplMedianCut( pBuf
, rPal
, nR1
, nR2
, nG1
, nG
- 1, nB1
, nB2
, nColors
>> 1, nPixOld
, rIndex
);
2418 ImplMedianCut( pBuf
, rPal
, nR1
, nR2
, nG
, nG2
, nB1
, nB2
, nColors
>> 1, nPixels
- nPixOld
, rIndex
);
2425 while( nPixNew
< nTest
)
2427 nR
++, nPixOld
= nPixNew
;
2428 for( long nG
= nG1
; nG
<= nG2
; nG
++ )
2429 for( long nB
= nB1
; nB
<= nB2
; nB
++ )
2430 nPixNew
+= pBuf
[ RGB15( nR
, nG
, nB
) ];
2435 ImplMedianCut( pBuf
, rPal
, nR1
, nR
, nG1
, nG2
, nB1
, nB2
, nColors
>> 1, nPixNew
, rIndex
);
2436 ImplMedianCut( pBuf
, rPal
, nR1
+ 1, nR2
, nG1
, nG2
, nB1
, nB2
, nColors
>> 1, nPixels
- nPixNew
, rIndex
);
2440 ImplMedianCut( pBuf
, rPal
, nR1
, nR
- 1, nG1
, nG2
, nB1
, nB2
, nColors
>> 1, nPixOld
, rIndex
);
2441 ImplMedianCut( pBuf
, rPal
, nR
, nR2
, nG1
, nG2
, nB1
, nB2
, nColors
>> 1, nPixels
- nPixOld
, rIndex
);
2448 bool Bitmap::Vectorize( tools::PolyPolygon
& rPolyPoly
, BmpVectorizeFlags nFlags
, const Link
<>* pProgress
)
2450 return ImplVectorizer::ImplVectorize( *this, rPolyPoly
, nFlags
, pProgress
);
2453 bool Bitmap::Vectorize( GDIMetaFile
& rMtf
, sal_uInt8 cReduce
, BmpVectorizeFlags nFlags
, const Link
<>* pProgress
)
2455 return ImplVectorizer::ImplVectorize( *this, rMtf
, cReduce
, nFlags
, pProgress
);
2458 bool Bitmap::Adjust( short nLuminancePercent
, short nContrastPercent
,
2459 short nChannelRPercent
, short nChannelGPercent
, short nChannelBPercent
,
2460 double fGamma
, bool bInvert
, bool msoBrightness
)
2464 // nothing to do => return quickly
2465 if( !nLuminancePercent
&& !nContrastPercent
&&
2466 !nChannelRPercent
&& !nChannelGPercent
&& !nChannelBPercent
&&
2467 ( fGamma
== 1.0 ) && !bInvert
)
2473 BitmapWriteAccess
* pAcc
= AcquireWriteAccess();
2478 const long nW
= pAcc
->Width();
2479 const long nH
= pAcc
->Height();
2480 boost::scoped_array
<sal_uInt8
> cMapR(new sal_uInt8
[ 256 ]);
2481 boost::scoped_array
<sal_uInt8
> cMapG(new sal_uInt8
[ 256 ]);
2482 boost::scoped_array
<sal_uInt8
> cMapB(new sal_uInt8
[ 256 ]);
2483 double fM
, fROff
, fGOff
, fBOff
, fOff
;
2486 if( nContrastPercent
>= 0 )
2487 fM
= 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent
, 0L, 100L ) );
2489 fM
= ( 128.0 + 1.27 * MinMax( nContrastPercent
, -100L, 0L ) ) / 128.0;
2492 // total offset = luminance offset + contrast offset
2493 fOff
= MinMax( nLuminancePercent
, -100L, 100L ) * 2.55 + 128.0 - fM
* 128.0;
2495 fOff
= MinMax( nLuminancePercent
, -100L, 100L ) * 2.55;
2497 // channel offset = channel offset + total offset
2498 fROff
= nChannelRPercent
* 2.55 + fOff
;
2499 fGOff
= nChannelGPercent
* 2.55 + fOff
;
2500 fBOff
= nChannelBPercent
* 2.55 + fOff
;
2502 // calculate gamma value
2503 fGamma
= ( fGamma
<= 0.0 || fGamma
> 10.0 ) ? 1.0 : ( 1.0 / fGamma
);
2504 const bool bGamma
= ( fGamma
!= 1.0 );
2506 // create mapping table
2507 for( long nX
= 0L; nX
< 256L; nX
++ )
2511 cMapR
[ nX
] = (sal_uInt8
) MinMax( FRound( nX
* fM
+ fROff
), 0L, 255L );
2512 cMapG
[ nX
] = (sal_uInt8
) MinMax( FRound( nX
* fM
+ fGOff
), 0L, 255L );
2513 cMapB
[ nX
] = (sal_uInt8
) MinMax( FRound( nX
* fM
+ fBOff
), 0L, 255L );
2517 // LO simply uses (in a somewhat optimized form) "newcolor = (oldcolor-128)*contrast+brightness+128"
2518 // as the formula, i.e. contrast first, brightness afterwards. MSOffice, for whatever weird reason,
2519 // use neither first, but apparently it applies half of brightness before contrast and half afterwards.
2520 cMapR
[ nX
] = (sal_uInt8
) MinMax( FRound( (nX
+fROff
/2-128) * fM
+ 128 + fROff
/2 ), 0L, 255L );
2521 cMapG
[ nX
] = (sal_uInt8
) MinMax( FRound( (nX
+fGOff
/2-128) * fM
+ 128 + fGOff
/2 ), 0L, 255L );
2522 cMapB
[ nX
] = (sal_uInt8
) MinMax( FRound( (nX
+fBOff
/2-128) * fM
+ 128 + fBOff
/2 ), 0L, 255L );
2526 cMapR
[ nX
] = GAMMA( cMapR
[ nX
], fGamma
);
2527 cMapG
[ nX
] = GAMMA( cMapG
[ nX
], fGamma
);
2528 cMapB
[ nX
] = GAMMA( cMapB
[ nX
], fGamma
);
2533 cMapR
[ nX
] = ~cMapR
[ nX
];
2534 cMapG
[ nX
] = ~cMapG
[ nX
];
2535 cMapB
[ nX
] = ~cMapB
[ nX
];
2540 if( pAcc
->HasPalette() )
2542 BitmapColor aNewCol
;
2544 for( sal_uInt16 i
= 0, nCount
= pAcc
->GetPaletteEntryCount(); i
< nCount
; i
++ )
2546 const BitmapColor
& rCol
= pAcc
->GetPaletteColor( i
);
2547 aNewCol
.SetRed( cMapR
[ rCol
.GetRed() ] );
2548 aNewCol
.SetGreen( cMapG
[ rCol
.GetGreen() ] );
2549 aNewCol
.SetBlue( cMapB
[ rCol
.GetBlue() ] );
2550 pAcc
->SetPaletteColor( i
, aNewCol
);
2553 else if( pAcc
->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR
)
2555 for( long nY
= 0L; nY
< nH
; nY
++ )
2557 Scanline pScan
= pAcc
->GetScanline( nY
);
2559 for( long nX
= 0L; nX
< nW
; nX
++ )
2561 *pScan
= cMapB
[ *pScan
]; pScan
++;
2562 *pScan
= cMapG
[ *pScan
]; pScan
++;
2563 *pScan
= cMapR
[ *pScan
]; pScan
++;
2567 else if( pAcc
->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB
)
2569 for( long nY
= 0L; nY
< nH
; nY
++ )
2571 Scanline pScan
= pAcc
->GetScanline( nY
);
2573 for( long nX
= 0L; nX
< nW
; nX
++ )
2575 *pScan
= cMapR
[ *pScan
]; pScan
++;
2576 *pScan
= cMapG
[ *pScan
]; pScan
++;
2577 *pScan
= cMapB
[ *pScan
]; pScan
++;
2583 for( long nY
= 0L; nY
< nH
; nY
++ )
2585 for( long nX
= 0L; nX
< nW
; nX
++ )
2587 aCol
= pAcc
->GetPixel( nY
, nX
);
2588 aCol
.SetRed( cMapR
[ aCol
.GetRed() ] );
2589 aCol
.SetGreen( cMapG
[ aCol
.GetGreen() ] );
2590 aCol
.SetBlue( cMapB
[ aCol
.GetBlue() ] );
2591 pAcc
->SetPixel( nY
, nX
, aCol
);
2596 ReleaseAccess( pAcc
);
2604 bool Bitmap::ImplConvolutionPass(Bitmap
& aNewBitmap
, BitmapReadAccess
* pReadAcc
, int aNumberOfContributions
, double* pWeights
, int* pPixels
, int* pCount
)
2606 BitmapWriteAccess
* pWriteAcc
= aNewBitmap
.AcquireWriteAccess();
2608 if (!pReadAcc
|| !pWriteAcc
)
2611 const int nHeight
= GetSizePixel().Height();
2612 assert(GetSizePixel().Height() == aNewBitmap
.GetSizePixel().Width());
2613 const int nWidth
= GetSizePixel().Width();
2614 assert(GetSizePixel().Width() == aNewBitmap
.GetSizePixel().Height());
2617 double aValueRed
, aValueGreen
, aValueBlue
;
2618 double aSum
, aWeight
;
2619 int aBaseIndex
, aIndex
;
2621 for (int nSourceY
= 0; nSourceY
< nHeight
; ++nSourceY
)
2623 for (int nSourceX
= 0; nSourceX
< nWidth
; ++nSourceX
)
2625 aBaseIndex
= nSourceX
* aNumberOfContributions
;
2626 aSum
= aValueRed
= aValueGreen
= aValueBlue
= 0.0;
2628 for (int j
= 0; j
< pCount
[nSourceX
]; ++j
)
2630 aIndex
= aBaseIndex
+ j
;
2631 aSum
+= aWeight
= pWeights
[ aIndex
];
2633 aColor
= pReadAcc
->GetColor(nSourceY
, pPixels
[aIndex
]);
2635 aValueRed
+= aWeight
* aColor
.GetRed();
2636 aValueGreen
+= aWeight
* aColor
.GetGreen();
2637 aValueBlue
+= aWeight
* aColor
.GetBlue();
2640 BitmapColor
aResultColor(
2641 (sal_uInt8
) MinMax( aValueRed
/ aSum
, 0, 255 ),
2642 (sal_uInt8
) MinMax( aValueGreen
/ aSum
, 0, 255 ),
2643 (sal_uInt8
) MinMax( aValueBlue
/ aSum
, 0, 255 ) );
2645 int nDestX
= nSourceY
;
2646 int nDestY
= nSourceX
;
2648 pWriteAcc
->SetPixel(nDestY
, nDestX
, aResultColor
);
2651 ReleaseAccess( pWriteAcc
);
2655 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */