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/bitmapaccess.hxx>
24 #include <vcl/bitmapex.hxx>
25 #include <vcl/bitmap.hxx>
26 #include <config_features.h>
27 #if HAVE_FEATURE_OPENGL
28 #include <vcl/opengl/OpenGLHelper.hxx>
33 #include "impoctree.hxx"
34 #include "impvect.hxx"
36 #include <bitmapscalesuper.hxx>
38 #include "BitmapScaleConvolution.hxx"
40 #define RGB15( _def_cR, _def_cG, _def_cB ) (((sal_uLong)(_def_cR)<<10UL)|((sal_uLong)(_def_cG)<<5UL)|(sal_uLong)(_def_cB))
41 #define GAMMA( _def_cVal, _def_InvGamma ) ((sal_uInt8)MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0,255))
44 nTemp = p1T[nX++] >> 12; \
45 nBErr = MinMax( nTemp, 0, 255 ); \
46 nBErr = nBErr - FloydIndexMap[ nBC = FloydMap[nBErr] ]; \
47 nTemp = p1T[nX++] >> 12; \
48 nGErr = MinMax( nTemp, 0, 255 ); \
49 nGErr = nGErr - FloydIndexMap[ nGC = FloydMap[nGErr] ]; \
50 nTemp = p1T[nX] >> 12; \
51 nRErr = MinMax( nTemp, 0, 255 ); \
52 nRErr = nRErr - FloydIndexMap[ nRC = FloydMap[nRErr] ];
54 #define CALC_TABLES3 \
55 p2T[nX++] += FloydError3[nBErr]; \
56 p2T[nX++] += FloydError3[nGErr]; \
57 p2T[nX++] += FloydError3[nRErr];
59 #define CALC_TABLES5 \
60 p2T[nX++] += FloydError5[nBErr]; \
61 p2T[nX++] += FloydError5[nGErr]; \
62 p2T[nX++] += FloydError5[nRErr];
64 #define CALC_TABLES7 \
65 p1T[++nX] += FloydError7[nBErr]; \
66 p2T[nX++] += FloydError1[nBErr]; \
67 p1T[nX] += FloydError7[nGErr]; \
68 p2T[nX++] += FloydError1[nGErr]; \
69 p1T[nX] += FloydError7[nRErr]; \
70 p2T[nX] += FloydError1[nRErr];
72 const extern sal_uLong nVCLRLut
[ 6 ] = { 16, 17, 18, 19, 20, 21 };
73 const extern sal_uLong nVCLGLut
[ 6 ] = { 0, 6, 12, 18, 24, 30 };
74 const extern sal_uLong nVCLBLut
[ 6 ] = { 0, 36, 72, 108, 144, 180 };
76 const extern sal_uLong nVCLDitherLut
[ 256 ] =
78 0, 49152, 12288, 61440, 3072, 52224, 15360, 64512, 768, 49920, 13056,
79 62208, 3840, 52992, 16128, 65280, 32768, 16384, 45056, 28672, 35840, 19456,
80 48128, 31744, 33536, 17152, 45824, 29440, 36608, 20224, 48896, 32512, 8192,
81 57344, 4096, 53248, 11264, 60416, 7168, 56320, 8960, 58112, 4864, 54016,
82 12032, 61184, 7936, 57088, 40960, 24576, 36864, 20480, 44032, 27648, 39936,
83 23552, 41728, 25344, 37632, 21248, 44800, 28416, 40704, 24320, 2048, 51200,
84 14336, 63488, 1024, 50176, 13312, 62464, 2816, 51968, 15104, 64256, 1792,
85 50944, 14080, 63232, 34816, 18432, 47104, 30720, 33792, 17408, 46080, 29696,
86 35584, 19200, 47872, 31488, 34560, 18176, 46848, 30464, 10240, 59392, 6144,
87 55296, 9216, 58368, 5120, 54272, 11008, 60160, 6912, 56064, 9984, 59136,
88 5888, 55040, 43008, 26624, 38912, 22528, 41984, 25600, 37888, 21504, 43776,
89 27392, 39680, 23296, 42752, 26368, 38656, 22272, 512, 49664, 12800, 61952,
90 3584, 52736, 15872, 65024, 256, 49408, 12544, 61696, 3328, 52480, 15616,
91 64768, 33280, 16896, 45568, 29184, 36352, 19968, 48640, 32256, 33024, 16640,
92 45312, 28928, 36096, 19712, 48384, 32000, 8704, 57856, 4608, 53760, 11776,
93 60928, 7680, 56832, 8448, 57600, 4352, 53504, 11520, 60672, 7424, 56576,
94 41472, 25088, 37376, 20992, 44544, 28160, 40448, 24064, 41216, 24832, 37120,
95 20736, 44288, 27904, 40192, 23808, 2560, 51712, 14848, 64000, 1536, 50688,
96 13824, 62976, 2304, 51456, 14592, 63744, 1280, 50432, 13568, 62720, 35328,
97 18944, 47616, 31232, 34304, 17920, 46592, 30208, 35072, 18688, 47360, 30976,
98 34048, 17664, 46336, 29952, 10752, 59904, 6656, 55808, 9728, 58880, 5632,
99 54784, 10496, 59648, 6400, 55552, 9472, 58624, 5376, 54528, 43520, 27136,
100 39424, 23040, 42496, 26112, 38400, 22016, 43264, 26880, 39168, 22784, 42240,
104 const extern sal_uLong nVCLLut
[ 256 ] =
106 0, 1286, 2572, 3858, 5144, 6430, 7716, 9002,
107 10288, 11574, 12860, 14146, 15432, 16718, 18004, 19290,
108 20576, 21862, 23148, 24434, 25720, 27006, 28292, 29578,
109 30864, 32150, 33436, 34722, 36008, 37294, 38580, 39866,
110 41152, 42438, 43724, 45010, 46296, 47582, 48868, 50154,
111 51440, 52726, 54012, 55298, 56584, 57870, 59156, 60442,
112 61728, 63014, 64300, 65586, 66872, 68158, 69444, 70730,
113 72016, 73302, 74588, 75874, 77160, 78446, 79732, 81018,
114 82304, 83590, 84876, 86162, 87448, 88734, 90020, 91306,
115 92592, 93878, 95164, 96450, 97736, 99022,100308,101594,
116 102880,104166,105452,106738,108024,109310,110596,111882,
117 113168,114454,115740,117026,118312,119598,120884,122170,
118 123456,124742,126028,127314,128600,129886,131172,132458,
119 133744,135030,136316,137602,138888,140174,141460,142746,
120 144032,145318,146604,147890,149176,150462,151748,153034,
121 154320,155606,156892,158178,159464,160750,162036,163322,
122 164608,165894,167180,168466,169752,171038,172324,173610,
123 174896,176182,177468,178754,180040,181326,182612,183898,
124 185184,186470,187756,189042,190328,191614,192900,194186,
125 195472,196758,198044,199330,200616,201902,203188,204474,
126 205760,207046,208332,209618,210904,212190,213476,214762,
127 216048,217334,218620,219906,221192,222478,223764,225050,
128 226336,227622,228908,230194,231480,232766,234052,235338,
129 236624,237910,239196,240482,241768,243054,244340,245626,
130 246912,248198,249484,250770,252056,253342,254628,255914,
131 257200,258486,259772,261058,262344,263630,264916,266202,
132 267488,268774,270060,271346,272632,273918,275204,276490,
133 277776,279062,280348,281634,282920,284206,285492,286778,
134 288064,289350,290636,291922,293208,294494,295780,297066,
135 298352,299638,300924,302210,303496,304782,306068,307354,
136 308640,309926,311212,312498,313784,315070,316356,317642,
137 318928,320214,321500,322786,324072,325358,326644,327930
140 const long FloydMap
[256] =
142 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
143 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
144 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
145 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
146 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
147 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
148 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
149 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
150 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
151 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
152 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
153 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
154 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
155 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
156 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
157 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
160 const long FloydError1
[61] =
162 -7680, -7424, -7168, -6912, -6656, -6400, -6144,
163 -5888, -5632, -5376, -5120, -4864, -4608, -4352,
164 -4096, -3840, -3584, -3328, -3072, -2816, -2560,
165 -2304, -2048, -1792, -1536, -1280, -1024, -768,
166 -512, -256, 0, 256, 512, 768, 1024, 1280, 1536,
167 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
168 3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632,
169 5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680
172 const long FloydError3
[61] =
174 -23040, -22272, -21504, -20736, -19968, -19200,
175 -18432, -17664, -16896, -16128, -15360, -14592,
176 -13824, -13056, -12288, -11520, -10752, -9984,
177 -9216, -8448, -7680, -6912, -6144, -5376, -4608,
178 -3840, -3072, -2304, -1536, -768, 0, 768, 1536,
179 2304, 3072, 3840, 4608, 5376, 6144, 6912, 7680,
180 8448, 9216, 9984, 10752, 11520, 12288, 13056,
181 13824, 14592, 15360, 16128, 16896, 17664, 18432,
182 19200, 19968, 20736, 21504, 22272, 23040
185 const long FloydError5
[61] =
187 -38400, -37120, -35840, -34560, -33280, -32000,
188 -30720, -29440, -28160, -26880, -25600, -24320,
189 -23040, -21760, -20480, -19200, -17920, -16640,
190 -15360, -14080, -12800, -11520, -10240, -8960,
191 -7680, -6400, -5120, -3840, -2560, -1280, 0,
192 1280, 2560, 3840, 5120, 6400, 7680, 8960, 10240,
193 11520, 12800, 14080, 15360, 16640, 17920, 19200,
194 20480, 21760, 23040, 24320, 25600, 26880, 28160,
195 29440, 30720, 32000, 33280, 34560, 35840, 37120,
199 const long FloydError7
[61] =
201 -53760, -51968, -50176, -48384, -46592, -44800,
202 -43008, -41216, -39424, -37632, -35840, -34048,
203 -32256, -30464, -28672, -26880, -25088, -23296,
204 -21504, -19712, -17920, -16128, -14336, -12544,
205 -10752, -8960, -7168, -5376, -3584, -1792, 0,
206 1792, 3584, 5376, 7168, 8960, 10752, 12544, 14336,
207 16128, 17920, 19712, 21504, 23296, 25088, 26880,
208 28672, 30464, 32256, 34048, 35840, 37632, 39424,
209 41216, 43008, 44800, 46592, 48384, 50176, 51968,
213 const long FloydIndexMap
[6] =
215 -30, 21, 72, 123, 174, 225
218 bool Bitmap::Convert( BmpConversion eConversion
)
220 // try to convert in backend
223 std::shared_ptr
<ImpBitmap
> xImpBmp(new ImpBitmap
);
224 if (xImpBmp
->ImplCreate(*mxImpBmp
) && xImpBmp
->ImplConvert(eConversion
))
226 ImplSetImpBitmap(xImpBmp
);
227 SAL_INFO( "vcl.opengl", "Ref count: " << mxImpBmp
.use_count() );
232 const sal_uInt16 nBitCount
= GetBitCount ();
235 switch( eConversion
)
237 case BmpConversion::N1BitThreshold
:
238 bRet
= ImplMakeMono( 128 );
241 case BmpConversion::N4BitGreys
:
242 bRet
= ImplMakeGreyscales( 16 );
245 case BmpConversion::N4BitColors
:
248 bRet
= ImplConvertUp( 4 );
249 else if( nBitCount
> 4 )
250 bRet
= ImplConvertDown( 4 );
256 case BmpConversion::N8BitGreys
:
257 bRet
= ImplMakeGreyscales( 256 );
260 case BmpConversion::N8BitColors
:
263 bRet
= ImplConvertUp( 8 );
264 else if( nBitCount
> 8 )
265 bRet
= ImplConvertDown( 8 );
271 case BmpConversion::N8BitTrans
:
273 Color
aTrans( BMP_COL_TRANS
);
276 bRet
= ImplConvertUp( 8, &aTrans
);
278 bRet
= ImplConvertDown( 8, &aTrans
);
282 case BmpConversion::N24Bit
:
285 bRet
= ImplConvertUp( 24 );
291 case BmpConversion::Ghosted
:
292 bRet
= ImplConvertGhosted();
296 OSL_FAIL( "Bitmap::Convert(): Unsupported conversion" );
303 bool Bitmap::ImplMakeMono( sal_uInt8 cThreshold
)
305 ScopedReadAccess
pReadAcc(*this);
310 Bitmap
aNewBmp( GetSizePixel(), 1 );
311 ScopedWriteAccess
pWriteAcc(aNewBmp
);
315 const BitmapColor
aBlack( pWriteAcc
->GetBestMatchingColor( Color( COL_BLACK
) ) );
316 const BitmapColor
aWhite( pWriteAcc
->GetBestMatchingColor( Color( COL_WHITE
) ) );
317 const long nWidth
= pWriteAcc
->Width();
318 const long nHeight
= pWriteAcc
->Height();
320 if( pReadAcc
->HasPalette() )
322 for( long nY
= 0; nY
< nHeight
; nY
++ )
324 for( long nX
= 0; nX
< nWidth
; nX
++ )
326 const sal_uInt8 cIndex
= pReadAcc
->GetPixelIndex( nY
, nX
);
327 if( pReadAcc
->GetPaletteColor( cIndex
).GetLuminance() >=
330 pWriteAcc
->SetPixel( nY
, nX
, aWhite
);
333 pWriteAcc
->SetPixel( nY
, nX
, aBlack
);
339 for( long nY
= 0; nY
< nHeight
; nY
++ )
341 for( long nX
= 0; nX
< nWidth
; nX
++ )
343 if( pReadAcc
->GetPixel( nY
, nX
).GetLuminance() >=
346 pWriteAcc
->SetPixel( nY
, nX
, aWhite
);
349 pWriteAcc
->SetPixel( nY
, nX
, aBlack
);
362 const MapMode
aMap( maPrefMapMode
);
363 const Size
aSize( maPrefSize
);
367 maPrefMapMode
= aMap
;
375 bool Bitmap::ImplMakeGreyscales( sal_uInt16 nGreys
)
377 SAL_WARN_IF( nGreys
!= 16 && nGreys
!= 256, "vcl", "Only 16 or 256 greyscales are supported!" );
379 ScopedReadAccess
pReadAcc(*this);
384 const BitmapPalette
& rPal
= GetGreyPalette( nGreys
);
385 sal_uLong nShift
= ( ( nGreys
== 16 ) ? 4UL : 0UL );
386 bool bPalDiffers
= !pReadAcc
->HasPalette() || ( rPal
.GetEntryCount() != pReadAcc
->GetPaletteEntryCount() );
389 bPalDiffers
= ( (BitmapPalette
&) rPal
!= pReadAcc
->GetPalette() );
393 Bitmap
aNewBmp( GetSizePixel(), ( nGreys
== 16 ) ? 4 : 8, &rPal
);
394 ScopedWriteAccess
pWriteAcc(aNewBmp
);
398 const long nWidth
= pWriteAcc
->Width();
399 const long nHeight
= pWriteAcc
->Height();
401 if( pReadAcc
->HasPalette() )
403 for( long nY
= 0; nY
< nHeight
; nY
++ )
405 for( long nX
= 0; nX
< nWidth
; nX
++ )
407 const sal_uInt8 cIndex
= pReadAcc
->GetPixelIndex( nY
, nX
);
408 pWriteAcc
->SetPixelIndex( nY
, nX
,
409 (pReadAcc
->GetPaletteColor( cIndex
).GetLuminance() >> nShift
) );
413 else if( pReadAcc
->GetScanlineFormat() == ScanlineFormat::N24BitTcBgr
&&
414 pWriteAcc
->GetScanlineFormat() == ScanlineFormat::N8BitPal
)
418 for( long nY
= 0; nY
< nHeight
; nY
++ )
420 Scanline pReadScan
= pReadAcc
->GetScanline( nY
);
421 Scanline pWriteScan
= pWriteAcc
->GetScanline( nY
);
423 for( long nX
= 0; nX
< nWidth
; nX
++ )
425 const sal_uLong nB
= *pReadScan
++;
426 const sal_uLong nG
= *pReadScan
++;
427 const sal_uLong nR
= *pReadScan
++;
429 *pWriteScan
++ = (sal_uInt8
) ( ( nB
* 28UL + nG
* 151UL + nR
* 77UL ) >> nShift
);
433 else if( pReadAcc
->GetScanlineFormat() == ScanlineFormat::N24BitTcRgb
&&
434 pWriteAcc
->GetScanlineFormat() == ScanlineFormat::N8BitPal
)
438 for( long nY
= 0; nY
< nHeight
; nY
++ )
440 Scanline pReadScan
= pReadAcc
->GetScanline( nY
);
441 Scanline pWriteScan
= pWriteAcc
->GetScanline( nY
);
443 for( long nX
= 0; nX
< nWidth
; nX
++ )
445 const sal_uLong nR
= *pReadScan
++;
446 const sal_uLong nG
= *pReadScan
++;
447 const sal_uLong nB
= *pReadScan
++;
449 *pWriteScan
++ = (sal_uInt8
) ( ( nB
* 28UL + nG
* 151UL + nR
* 77UL ) >> nShift
);
455 for( long nY
= 0; nY
< nHeight
; nY
++ )
456 for( long nX
= 0; nX
< nWidth
; nX
++ )
457 pWriteAcc
->SetPixelIndex( nY
, nX
, (pReadAcc
->GetPixel( nY
, nX
) ).GetLuminance() >> nShift
);
468 const MapMode
aMap( maPrefMapMode
);
469 const Size
aSize( maPrefSize
);
473 maPrefMapMode
= aMap
;
487 bool Bitmap::ImplConvertUp(sal_uInt16 nBitCount
, Color
* pExtColor
)
489 SAL_WARN_IF( nBitCount
<= GetBitCount(), "vcl", "New BitCount must be greater!" );
491 Bitmap::ScopedReadAccess
pReadAcc(*this);
496 BitmapPalette aPalette
;
497 Bitmap
aNewBmp(GetSizePixel(), nBitCount
, pReadAcc
->HasPalette() ? &pReadAcc
->GetPalette() : &aPalette
);
498 Bitmap::ScopedWriteAccess
pWriteAcc(aNewBmp
);
502 const long nWidth
= pWriteAcc
->Width();
503 const long nHeight
= pWriteAcc
->Height();
505 if (pWriteAcc
->HasPalette())
507 const BitmapPalette
& rOldPalette
= pReadAcc
->GetPalette();
508 const sal_uInt16 nOldCount
= rOldPalette
.GetEntryCount();
509 assert(nOldCount
<= (1 << GetBitCount()));
511 aPalette
.SetEntryCount(1 << nBitCount
);
513 for (sal_uInt16 i
= 0; i
< nOldCount
; i
++)
514 aPalette
[i
] = rOldPalette
[i
];
517 aPalette
[aPalette
.GetEntryCount() - 1] = *pExtColor
;
519 pWriteAcc
->SetPalette(aPalette
);
521 for (long nY
= 0; nY
< nHeight
; nY
++)
523 for (long nX
= 0; nX
< nWidth
; nX
++)
525 pWriteAcc
->SetPixel(nY
, nX
, pReadAcc
->GetPixel(nY
, nX
));
531 if (pReadAcc
->HasPalette())
533 for (long nY
= 0; nY
< nHeight
; nY
++)
535 for (long nX
= 0; nX
< nWidth
; nX
++)
537 pWriteAcc
->SetPixel(nY
, nX
, pReadAcc
->GetPaletteColor(pReadAcc
->GetPixelIndex(nY
, nX
)));
543 for (long nY
= 0; nY
< nHeight
; nY
++)
545 for (long nX
= 0; nX
< nWidth
; nX
++)
547 pWriteAcc
->SetPixel(nY
, nX
, pReadAcc
->GetPixel(nY
, nX
));
557 const MapMode
aMap(maPrefMapMode
);
558 const Size
aSize(maPrefSize
);
562 maPrefMapMode
= aMap
;
570 bool Bitmap::ImplConvertDown(sal_uInt16 nBitCount
, Color
* pExtColor
)
572 SAL_WARN_IF(nBitCount
> GetBitCount(), "vcl", "New BitCount must be lower ( or equal when pExtColor is set )!");
574 Bitmap::ScopedReadAccess
pReadAcc(*this);
579 BitmapPalette aPalette
;
580 Bitmap
aNewBmp(GetSizePixel(), nBitCount
, &aPalette
);
581 Bitmap::ScopedWriteAccess
pWriteAcc(aNewBmp
);
585 const sal_uInt16 nCount
= 1 << nBitCount
;
586 const long nWidth
= pWriteAcc
->Width();
587 const long nWidth1
= nWidth
- 1;
588 const long nHeight
= pWriteAcc
->Height();
589 Octree
aOctree(*pReadAcc
, pExtColor
? (nCount
- 1) : nCount
);
590 aPalette
= aOctree
.GetPalette();
591 InverseColorMap
aColorMap(aPalette
);
593 ImpErrorQuad aErrQuad
;
594 std::vector
<ImpErrorQuad
> aErrQuad1(nWidth
);
595 std::vector
<ImpErrorQuad
> aErrQuad2(nWidth
);
596 ImpErrorQuad
* pQLine1
= aErrQuad1
.data();
597 ImpErrorQuad
* pQLine2
= nullptr;
604 aPalette
.SetEntryCount(aPalette
.GetEntryCount() + 1);
605 aPalette
[aPalette
.GetEntryCount() - 1] = *pExtColor
;
608 // set Black/White always, if we have enough space
609 if (aPalette
.GetEntryCount() < (nCount
- 1))
611 aPalette
.SetEntryCount(aPalette
.GetEntryCount() + 2);
612 aPalette
[aPalette
.GetEntryCount() - 2] = Color(COL_BLACK
);
613 aPalette
[aPalette
.GetEntryCount() - 1] = Color(COL_WHITE
);
616 pWriteAcc
->SetPalette(aPalette
);
618 for (long nY
= 0; nY
< std::min(nHeight
, 2L); nY
++, nYTmp
++)
620 pQLine2
= !nY
? aErrQuad1
.data() : aErrQuad2
.data();
621 for (long nX
= 0; nX
< nWidth
; nX
++)
623 if (pReadAcc
->HasPalette())
624 pQLine2
[nX
] = pReadAcc
->GetPaletteColor(pReadAcc
->GetPixelIndex(nYTmp
, nX
));
626 pQLine2
[nX
] = pReadAcc
->GetPixel(nYTmp
, nX
);
630 for (long nY
= 0; nY
< nHeight
; nY
++, nYTmp
++)
632 // first pixel in the line
633 cIndex
= (sal_uInt8
) aColorMap
.GetBestPaletteIndex(pQLine1
[0].ImplGetColor());
634 pWriteAcc
->SetPixelIndex(nY
, 0, cIndex
);
637 for (nX
= 1; nX
< nWidth1
; nX
++)
639 aColor
= pQLine1
[nX
].ImplGetColor();
640 cIndex
= static_cast<sal_uInt8
>(aColorMap
.GetBestPaletteIndex(aColor
));
641 aErrQuad
= (ImpErrorQuad(aColor
) -= pWriteAcc
->GetPaletteColor(cIndex
));
642 pQLine1
[++nX
].ImplAddColorError7(aErrQuad
);
643 pQLine2
[nX
--].ImplAddColorError1(aErrQuad
);
644 pQLine2
[nX
--].ImplAddColorError5(aErrQuad
);
645 pQLine2
[nX
++].ImplAddColorError3(aErrQuad
);
646 pWriteAcc
->SetPixelIndex(nY
, nX
, cIndex
);
652 cIndex
= static_cast<sal_uInt8
>(aColorMap
.GetBestPaletteIndex(pQLine1
[nWidth1
].ImplGetColor()));
653 pWriteAcc
->SetPixelIndex(nY
, nX
, cIndex
);
656 // Refill/copy row buffer
659 pQLine2
= bQ1
? aErrQuad2
.data() : aErrQuad1
.data();
663 for (nX
= 0; nX
< nWidth
; nX
++)
665 if (pReadAcc
->HasPalette())
666 pQLine2
[nX
] = pReadAcc
->GetPaletteColor(pReadAcc
->GetPixelIndex(nYTmp
, nX
));
668 pQLine2
[nX
] = pReadAcc
->GetPixel(nYTmp
, nX
);
678 const MapMode
aMap(maPrefMapMode
);
679 const Size
aSize(maPrefSize
);
683 maPrefMapMode
= aMap
;
691 bool Bitmap::ImplConvertGhosted()
694 ScopedReadAccess
pR(*this);
699 if( pR
->HasPalette() )
701 BitmapPalette
aNewPal( pR
->GetPaletteEntryCount() );
703 for( long i
= 0, nCount
= aNewPal
.GetEntryCount(); i
< nCount
; i
++ )
705 const BitmapColor
& rOld
= pR
->GetPaletteColor( (sal_uInt16
) i
);
706 aNewPal
[ (sal_uInt16
) i
] = BitmapColor( ( rOld
.GetRed() >> 1 ) | 0x80,
707 ( rOld
.GetGreen() >> 1 ) | 0x80,
708 ( rOld
.GetBlue() >> 1 ) | 0x80 );
711 aNewBmp
= Bitmap( GetSizePixel(), GetBitCount(), &aNewPal
);
712 ScopedWriteAccess
pW(aNewBmp
);
716 pW
->CopyBuffer( *pR
);
722 aNewBmp
= Bitmap( GetSizePixel(), 24 );
724 ScopedWriteAccess
pW(aNewBmp
);
728 const long nWidth
= pR
->Width(), nHeight
= pR
->Height();
730 for( long nY
= 0; nY
< nHeight
; nY
++ )
732 for( long nX
= 0; nX
< nWidth
; nX
++ )
734 const BitmapColor
aOld( pR
->GetPixel( nY
, nX
) );
735 pW
->SetPixel( nY
, nX
, BitmapColor( ( aOld
.GetRed() >> 1 ) | 0x80,
736 ( aOld
.GetGreen() >> 1 ) | 0x80,
737 ( aOld
.GetBlue() >> 1 ) | 0x80 ) );
751 const MapMode
aMap( maPrefMapMode
);
752 const Size
aSize( maPrefSize
);
756 maPrefMapMode
= aMap
;
763 bool Bitmap::Scale( const double& rScaleX
, const double& rScaleY
, BmpScaleFlag nScaleFlag
)
765 if(basegfx::fTools::equalZero(rScaleX
) || basegfx::fTools::equalZero(rScaleY
))
771 if(basegfx::fTools::equal(rScaleX
, 1.0) && basegfx::fTools::equal(rScaleY
, 1.0))
777 const sal_uInt16
nStartCount(GetBitCount());
779 if (mxImpBmp
&& mxImpBmp
->ImplScalingSupported())
781 // implementation specific scaling
782 std::shared_ptr
<ImpBitmap
> xImpBmp(new ImpBitmap
);
783 if (xImpBmp
->ImplCreate(*mxImpBmp
) && xImpBmp
->ImplScale(rScaleX
, rScaleY
, nScaleFlag
))
785 ImplSetImpBitmap(xImpBmp
);
786 SAL_INFO( "vcl.opengl", "Ref count: " << mxImpBmp
.use_count() );
787 maPrefMapMode
= MapMode( MapUnit::MapPixel
);
788 maPrefSize
= xImpBmp
->ImplGetSize();
795 //If we start with a 1 bit image, then after scaling it in any mode except
796 //BmpScaleFlag::Fast we have a 24bit image which is perfectly correct, but we
797 //are going to down-shift it to mono again and Bitmap::ImplMakeMono just
798 //has "Bitmap aNewBmp( GetSizePixel(), 1 );" to create a 1 bit bitmap which
799 //will default to black/white and the colors mapped to which ever is closer
802 //So the easiest thing to do to retain the colors of 1 bit bitmaps is to
803 //just use the fast scale rather than attempting to count unique colors in
804 //the other converters and pass all the info down through
805 //Bitmap::ImplMakeMono
806 if (nStartCount
== 1)
807 nScaleFlag
= BmpScaleFlag::Fast
;
813 case BmpScaleFlag::Fast
:
815 bRetval
= ImplScaleFast( rScaleX
, rScaleY
);
818 case BmpScaleFlag::Interpolate
:
820 bRetval
= ImplScaleInterpolate( rScaleX
, rScaleY
);
823 case BmpScaleFlag::Default
:
825 if (GetSizePixel().Width() < 2 || GetSizePixel().Height() < 2)
827 // fallback to ImplScaleFast
828 bRetval
= ImplScaleFast( rScaleX
, rScaleY
);
832 BitmapScaleSuper
aScaleSuper(rScaleX
, rScaleY
);
833 bRetval
= aScaleSuper
.filter(*this);
837 case BmpScaleFlag::Lanczos
:
838 case BmpScaleFlag::BestQuality
:
840 vcl::BitmapScaleConvolution
aScaleConvolution(rScaleX
, rScaleY
, vcl::ConvolutionKernelType::Lanczos3
);
841 bRetval
= aScaleConvolution
.filter(*this);
844 case BmpScaleFlag::BiCubic
:
846 vcl::BitmapScaleConvolution
aScaleConvolution(rScaleX
, rScaleY
, vcl::ConvolutionKernelType::BiCubic
);
847 bRetval
= aScaleConvolution
.filter(*this);
850 case BmpScaleFlag::BiLinear
:
852 vcl::BitmapScaleConvolution
aScaleConvolution(rScaleX
, rScaleY
, vcl::ConvolutionKernelType::BiLinear
);
853 bRetval
= aScaleConvolution
.filter(*this);
858 OSL_ENSURE(!bRetval
|| nStartCount
== GetBitCount(), "Bitmap::Scale has changed the ColorDepth, this should *not* happen (!)");
862 bool Bitmap::Scale( const Size
& rNewSize
, BmpScaleFlag nScaleFlag
)
864 const Size
aSize( GetSizePixel() );
867 if( aSize
.Width() && aSize
.Height() )
869 bRet
= Scale( (double) rNewSize
.Width() / aSize
.Width(),
870 (double) rNewSize
.Height() / aSize
.Height(),
879 bool Bitmap::HasFastScale()
881 #if HAVE_FEATURE_OPENGL
882 return OpenGLHelper::isVCLOpenGLEnabled();
888 void Bitmap::AdaptBitCount(Bitmap
& rNew
) const
890 ImplAdaptBitCount(rNew
);
893 void Bitmap::ImplAdaptBitCount(Bitmap
& rNew
) const
895 // aNew is the result of some operation; adapt it's BitCount to the original (this)
896 if(GetBitCount() != rNew
.GetBitCount())
898 switch(GetBitCount())
902 rNew
.Convert(BmpConversion::N1BitThreshold
);
909 rNew
.Convert(BmpConversion::N4BitGreys
);
913 rNew
.Convert(BmpConversion::N4BitColors
);
921 rNew
.Convert(BmpConversion::N8BitGreys
);
925 rNew
.Convert(BmpConversion::N8BitColors
);
931 rNew
.Convert(BmpConversion::N24Bit
);
936 OSL_ENSURE(false, "BitDepth adaption failed (!)");
943 bool Bitmap::ImplScaleFast( const double& rScaleX
, const double& rScaleY
)
945 const Size
aSizePix( GetSizePixel() );
946 const long nNewWidth
= FRound( aSizePix
.Width() * rScaleX
);
947 const long nNewHeight
= FRound( aSizePix
.Height() * rScaleY
);
950 if( nNewWidth
&& nNewHeight
)
952 ScopedReadAccess
pReadAcc(*this);
956 Bitmap
aNewBmp( Size( nNewWidth
, nNewHeight
), GetBitCount(), &pReadAcc
->GetPalette() );
957 ScopedWriteAccess
pWriteAcc(aNewBmp
);
961 const long nScanlineSize
= pWriteAcc
->GetScanlineSize();
962 const long nNewWidth1
= nNewWidth
- 1;
963 const long nNewHeight1
= nNewHeight
- 1;
965 if( nNewWidth1
&& nNewHeight1
)
967 const double nWidth
= pReadAcc
->Width();
968 const double nHeight
= pReadAcc
->Height();
969 std::unique_ptr
<long[]> pLutX(new long[ nNewWidth
]);
970 std::unique_ptr
<long[]> pLutY(new long[ nNewHeight
]);
972 for( long nX
= 0; nX
< nNewWidth
; nX
++ )
973 pLutX
[ nX
] = long(nX
* nWidth
/ nNewWidth
);
975 for( long nY
= 0; nY
< nNewHeight
; nY
++ )
976 pLutY
[ nY
] = long(nY
* nHeight
/ nNewHeight
);
979 while( nActY
< nNewHeight
)
981 long nMapY
= pLutY
[ nActY
];
983 for( long nX
= 0; nX
< nNewWidth
; nX
++ )
984 pWriteAcc
->SetPixel( nActY
, nX
, pReadAcc
->GetPixel( nMapY
, pLutX
[ nX
] ) );
986 while( ( nActY
< nNewHeight1
) && ( pLutY
[ nActY
+ 1 ] == nMapY
) )
988 memcpy( pWriteAcc
->GetScanline( nActY
+ 1 ),
989 pWriteAcc
->GetScanline( nActY
), nScanlineSize
);
1003 ImplAssignWithSize( aNewBmp
);
1010 bool Bitmap::ImplScaleInterpolate( const double& rScaleX
, const double& rScaleY
)
1012 const Size
aSizePix( GetSizePixel() );
1013 const long nNewWidth
= FRound( aSizePix
.Width() * rScaleX
);
1014 const long nNewHeight
= FRound( aSizePix
.Height() * rScaleY
);
1017 if( ( nNewWidth
> 1 ) && ( nNewHeight
> 1 ) )
1019 ScopedReadAccess
pReadAcc(*this);
1022 long nWidth
= pReadAcc
->Width();
1023 long nHeight
= pReadAcc
->Height();
1024 Bitmap
aNewBmp( Size( nNewWidth
, nHeight
), 24 );
1025 ScopedWriteAccess
pWriteAcc(aNewBmp
);
1029 const long nNewWidth1
= nNewWidth
- 1;
1030 const long nWidth1
= pReadAcc
->Width() - 1;
1031 const double fRevScaleX
= (double) nWidth1
/ nNewWidth1
;
1033 std::unique_ptr
<long[]> pLutInt(new long[ nNewWidth
]);
1034 std::unique_ptr
<long[]> pLutFrac(new long[ nNewWidth
]);
1036 for( long nX
= 0, nTemp
= nWidth
- 2; nX
< nNewWidth
; nX
++ )
1038 double fTemp
= nX
* fRevScaleX
;
1039 pLutInt
[ nX
] = MinMax( (long) fTemp
, 0, nTemp
);
1040 fTemp
-= pLutInt
[ nX
];
1041 pLutFrac
[ nX
] = (long) ( fTemp
* 1024. );
1044 for( long nY
= 0; nY
< nHeight
; nY
++ )
1049 if( pReadAcc
->HasPalette() )
1051 aCol0
= pReadAcc
->GetPaletteColor( pReadAcc
->GetPixelIndex( nY
, 0 ) );
1055 aCol0
= pReadAcc
->GetPixel( nY
, 0 );
1058 for( long nX
= 0; nX
< nNewWidth
; nX
++ )
1060 pWriteAcc
->SetPixel( nY
, nX
, aCol0
);
1065 for( long nX
= 0; nX
< nNewWidth
; nX
++ )
1067 long nTemp
= pLutInt
[ nX
];
1069 BitmapColor aCol0
, aCol1
;
1070 if( pReadAcc
->HasPalette() )
1072 aCol0
= pReadAcc
->GetPaletteColor( pReadAcc
->GetPixelIndex( nY
, nTemp
++ ) );
1073 aCol1
= pReadAcc
->GetPaletteColor( pReadAcc
->GetPixelIndex( nY
, nTemp
) );
1077 aCol0
= pReadAcc
->GetPixel( nY
, nTemp
++ );
1078 aCol1
= pReadAcc
->GetPixel( nY
, nTemp
);
1081 nTemp
= pLutFrac
[ nX
];
1083 long lXR0
= aCol0
.GetRed();
1084 long lXG0
= aCol0
.GetGreen();
1085 long lXB0
= aCol0
.GetBlue();
1086 long lXR1
= aCol1
.GetRed() - lXR0
;
1087 long lXG1
= aCol1
.GetGreen() - lXG0
;
1088 long lXB1
= aCol1
.GetBlue() - lXB0
;
1090 aCol0
.SetRed( (sal_uInt8
) ( ( lXR1
* nTemp
+ ( lXR0
<< 10 ) ) >> 10 ) );
1091 aCol0
.SetGreen( (sal_uInt8
) ( ( lXG1
* nTemp
+ ( lXG0
<< 10 ) ) >> 10 ) );
1092 aCol0
.SetBlue( (sal_uInt8
) ( ( lXB1
* nTemp
+ ( lXB0
<< 10 ) ) >> 10 ) );
1094 pWriteAcc
->SetPixel( nY
, nX
, aCol0
);
1108 const Bitmap
aOriginal(*this);
1110 aNewBmp
= Bitmap( Size( nNewWidth
, nNewHeight
), 24 );
1111 pReadAcc
= ScopedReadAccess(*this);
1112 pWriteAcc
= ScopedWriteAccess(aNewBmp
);
1114 if( pReadAcc
&& pWriteAcc
)
1116 const long nNewHeight1
= nNewHeight
- 1;
1117 const long nHeight1
= pReadAcc
->Height() - 1;
1118 const double fRevScaleY
= (double) nHeight1
/ nNewHeight1
;
1120 std::unique_ptr
<long[]> pLutInt(new long[ nNewHeight
]);
1121 std::unique_ptr
<long[]> pLutFrac(new long[ nNewHeight
]);
1123 for( long nY
= 0, nTemp
= nHeight
- 2; nY
< nNewHeight
; nY
++ )
1125 double fTemp
= nY
* fRevScaleY
;
1126 pLutInt
[ nY
] = MinMax( (long) fTemp
, 0, nTemp
);
1127 fTemp
-= pLutInt
[ nY
];
1128 pLutFrac
[ nY
] = (long) ( fTemp
* 1024. );
1131 // after 1st step, bitmap *is* 24bit format (see above)
1132 OSL_ENSURE(!pReadAcc
->HasPalette(), "OOps, somehow ImplScaleInterpolate in-between format has palette, should not happen (!)");
1134 for( long nX
= 0; nX
< nNewWidth
; nX
++ )
1138 BitmapColor aCol0
= pReadAcc
->GetPixel( 0, nX
);
1140 for( long nY
= 0; nY
< nNewHeight
; nY
++ )
1142 pWriteAcc
->SetPixel( nY
, nX
, aCol0
);
1147 for( long nY
= 0; nY
< nNewHeight
; nY
++ )
1149 long nTemp
= pLutInt
[ nY
];
1151 BitmapColor aCol0
= pReadAcc
->GetPixel( nTemp
++, nX
);
1152 BitmapColor aCol1
= pReadAcc
->GetPixel( nTemp
, nX
);
1154 nTemp
= pLutFrac
[ nY
];
1156 long lXR0
= aCol0
.GetRed();
1157 long lXG0
= aCol0
.GetGreen();
1158 long lXB0
= aCol0
.GetBlue();
1159 long lXR1
= aCol1
.GetRed() - lXR0
;
1160 long lXG1
= aCol1
.GetGreen() - lXG0
;
1161 long lXB1
= aCol1
.GetBlue() - lXB0
;
1163 aCol0
.SetRed( (sal_uInt8
) ( ( lXR1
* nTemp
+ ( lXR0
<< 10 ) ) >> 10 ) );
1164 aCol0
.SetGreen( (sal_uInt8
) ( ( lXG1
* nTemp
+ ( lXG0
<< 10 ) ) >> 10 ) );
1165 aCol0
.SetBlue( (sal_uInt8
) ( ( lXB1
* nTemp
+ ( lXB0
<< 10 ) ) >> 10 ) );
1167 pWriteAcc
->SetPixel( nY
, nX
, aCol0
);
1180 aOriginal
.ImplAdaptBitCount(aNewBmp
);
1189 bRet
= ImplScaleFast( rScaleX
, rScaleY
);
1195 bool Bitmap::Dither( BmpDitherFlags nDitherFlags
)
1199 const Size
aSizePix( GetSizePixel() );
1201 if( aSizePix
.Width() == 1 || aSizePix
.Height() == 1 )
1203 else if( nDitherFlags
& BmpDitherFlags::Matrix
)
1204 bRet
= ImplDitherMatrix();
1205 else if( nDitherFlags
& BmpDitherFlags::Floyd
)
1206 bRet
= ImplDitherFloyd();
1207 else if( ( nDitherFlags
& BmpDitherFlags::Floyd16
) && ( GetBitCount() == 24 ) )
1208 bRet
= ImplDitherFloyd16();
1213 bool Bitmap::ImplDitherMatrix()
1215 ScopedReadAccess
pReadAcc(*this);
1216 Bitmap
aNewBmp( GetSizePixel(), 8 );
1217 ScopedWriteAccess
pWriteAcc(aNewBmp
);
1220 if( pReadAcc
&& pWriteAcc
)
1222 const sal_uLong nWidth
= pReadAcc
->Width();
1223 const sal_uLong nHeight
= pReadAcc
->Height();
1224 BitmapColor
aIndex( (sal_uInt8
) 0 );
1226 if( pReadAcc
->HasPalette() )
1228 for( sal_uLong nY
= 0UL; nY
< nHeight
; nY
++ )
1230 for( sal_uLong nX
= 0UL, nModY
= ( nY
& 0x0FUL
) << 4UL; nX
< nWidth
; nX
++ )
1232 const BitmapColor
aCol( pReadAcc
->GetPaletteColor( pReadAcc
->GetPixelIndex( nY
, nX
) ) );
1233 const sal_uLong nD
= nVCLDitherLut
[ nModY
+ ( nX
& 0x0FUL
) ];
1234 const sal_uLong nR
= ( nVCLLut
[ aCol
.GetRed() ] + nD
) >> 16UL;
1235 const sal_uLong nG
= ( nVCLLut
[ aCol
.GetGreen() ] + nD
) >> 16UL;
1236 const sal_uLong nB
= ( nVCLLut
[ aCol
.GetBlue() ] + nD
) >> 16UL;
1238 aIndex
.SetIndex( (sal_uInt8
) ( nVCLRLut
[ nR
] + nVCLGLut
[ nG
] + nVCLBLut
[ nB
] ) );
1239 pWriteAcc
->SetPixel( nY
, nX
, aIndex
);
1245 for( sal_uLong nY
= 0UL; nY
< nHeight
; nY
++ )
1247 for( sal_uLong nX
= 0UL, nModY
= ( nY
& 0x0FUL
) << 4UL; nX
< nWidth
; nX
++ )
1249 const BitmapColor
aCol( pReadAcc
->GetPixel( nY
, nX
) );
1250 const sal_uLong nD
= nVCLDitherLut
[ nModY
+ ( nX
& 0x0FUL
) ];
1251 const sal_uLong nR
= ( nVCLLut
[ aCol
.GetRed() ] + nD
) >> 16UL;
1252 const sal_uLong nG
= ( nVCLLut
[ aCol
.GetGreen() ] + nD
) >> 16UL;
1253 const sal_uLong nB
= ( nVCLLut
[ aCol
.GetBlue() ] + nD
) >> 16UL;
1255 aIndex
.SetIndex( (sal_uInt8
) ( nVCLRLut
[ nR
] + nVCLGLut
[ nG
] + nVCLBLut
[ nB
] ) );
1256 pWriteAcc
->SetPixel( nY
, nX
, aIndex
);
1269 const MapMode
aMap( maPrefMapMode
);
1270 const Size
aSize( maPrefSize
);
1274 maPrefMapMode
= aMap
;
1281 bool Bitmap::ImplDitherFloyd()
1283 const Size
aSize( GetSizePixel() );
1286 if( ( aSize
.Width() > 3 ) && ( aSize
.Height() > 2 ) )
1288 ScopedReadAccess
pReadAcc(*this);
1289 Bitmap
aNewBmp( GetSizePixel(), 8 );
1290 ScopedWriteAccess
pWriteAcc(aNewBmp
);
1292 if( pReadAcc
&& pWriteAcc
)
1295 long nWidth
= pReadAcc
->Width();
1296 long nWidth1
= nWidth
- 1;
1297 long nHeight
= pReadAcc
->Height();
1299 long nW
= nWidth
* 3;
1301 long nRErr
, nGErr
, nBErr
;
1303 std::unique_ptr
<long[]> p1(new long[ nW
]);
1304 std::unique_ptr
<long[]> p2(new long[ nW
]);
1305 long* p1T
= p1
.get();
1306 long* p2T
= p2
.get();
1308 bool bPal
= pReadAcc
->HasPalette();
1314 for( long nZ
= 0; nZ
< nWidth
; nZ
++ )
1316 aColor
= pReadAcc
->GetPaletteColor( pReadAcc
->GetPixelIndex( 0, nZ
) );
1318 *pTmp
++ = (long) aColor
.GetBlue() << 12;
1319 *pTmp
++ = (long) aColor
.GetGreen() << 12;
1320 *pTmp
++ = (long) aColor
.GetRed() << 12;
1325 for( long nZ
= 0; nZ
< nWidth
; nZ
++ )
1327 aColor
= pReadAcc
->GetPixel( 0, nZ
);
1329 *pTmp
++ = (long) aColor
.GetBlue() << 12;
1330 *pTmp
++ = (long) aColor
.GetGreen() << 12;
1331 *pTmp
++ = (long) aColor
.GetRed() << 12;
1335 for( long nY
= 1, nYAcc
= 0; nY
<= nHeight
; nY
++, nYAcc
++ )
1345 for( long nZ
= 0; nZ
< nWidth
; nZ
++ )
1347 aColor
= pReadAcc
->GetPaletteColor( pReadAcc
->GetPixelIndex( nY
, nZ
) );
1349 *pTmp
++ = (long) aColor
.GetBlue() << 12;
1350 *pTmp
++ = (long) aColor
.GetGreen() << 12;
1351 *pTmp
++ = (long) aColor
.GetRed() << 12;
1356 for( long nZ
= 0; nZ
< nWidth
; nZ
++ )
1358 aColor
= pReadAcc
->GetPixel( nY
, nZ
);
1360 *pTmp
++ = (long) aColor
.GetBlue() << 12;
1361 *pTmp
++ = (long) aColor
.GetGreen() << 12;
1362 *pTmp
++ = (long) aColor
.GetRed() << 12;
1367 // Examine first Pixel separately
1374 pWriteAcc
->SetPixelIndex( nYAcc
, 0, static_cast<sal_uInt8
>(nVCLBLut
[ nBC
] + nVCLGLut
[nGC
] + nVCLRLut
[nRC
]) );
1376 // Get middle Pixels using a loop
1378 for ( nX
= 3, nXAcc
= 1; nX
< nW2
; nXAcc
++ )
1385 pWriteAcc
->SetPixelIndex( nYAcc
, nXAcc
, static_cast<sal_uInt8
>(nVCLBLut
[ nBC
] + nVCLGLut
[nGC
] + nVCLRLut
[nRC
]) );
1388 // Treat last Pixel separately
1393 pWriteAcc
->SetPixelIndex( nYAcc
, nWidth1
, static_cast<sal_uInt8
>(nVCLBLut
[ nBC
] + nVCLGLut
[nGC
] + nVCLRLut
[nRC
]) );
1404 const MapMode
aMap( maPrefMapMode
);
1405 const Size
aPrefSize( maPrefSize
);
1409 maPrefMapMode
= aMap
;
1410 maPrefSize
= aPrefSize
;
1417 bool Bitmap::ImplDitherFloyd16()
1419 ScopedReadAccess
pReadAcc(*this);
1420 Bitmap
aNewBmp( GetSizePixel(), 24 );
1421 ScopedWriteAccess
pWriteAcc(aNewBmp
);
1424 if( pReadAcc
&& pWriteAcc
)
1426 const long nWidth
= pWriteAcc
->Width();
1427 const long nWidth1
= nWidth
- 1;
1428 const long nHeight
= pWriteAcc
->Height();
1430 BitmapColor aBestCol
;
1431 ImpErrorQuad aErrQuad
;
1432 std::unique_ptr
<ImpErrorQuad
[]> pErrQuad1(new ImpErrorQuad
[ nWidth
]);
1433 std::unique_ptr
<ImpErrorQuad
[]> pErrQuad2(new ImpErrorQuad
[ nWidth
]);
1434 ImpErrorQuad
* pQLine1
= pErrQuad1
.get();
1435 ImpErrorQuad
* pQLine2
= nullptr;
1439 for( long nY
= 0; nY
< std::min( nHeight
, 2L ); nY
++, nYTmp
++ )
1441 pQLine2
= !nY
? pErrQuad1
.get() : pErrQuad2
.get();
1442 for( long nX
= 0; nX
< nWidth
; nX
++ )
1443 pQLine2
[ nX
] = pReadAcc
->GetPixel( nYTmp
, nX
);
1446 for( long nY
= 0; nY
< nHeight
; nY
++, nYTmp
++ )
1449 aBestCol
= pQLine1
[ 0 ].ImplGetColor();
1450 aBestCol
.SetRed( ( aBestCol
.GetRed() & 248 ) | 7 );
1451 aBestCol
.SetGreen( ( aBestCol
.GetGreen() & 248 ) | 7 );
1452 aBestCol
.SetBlue( ( aBestCol
.GetBlue() & 248 ) | 7 );
1453 pWriteAcc
->SetPixel( nY
, 0, aBestCol
);
1456 for( nX
= 1; nX
< nWidth1
; nX
++ )
1458 aColor
= pQLine1
[ nX
].ImplGetColor();
1459 aBestCol
.SetRed( ( aColor
.GetRed() & 248 ) | 7 );
1460 aBestCol
.SetGreen( ( aColor
.GetGreen() & 248 ) | 7 );
1461 aBestCol
.SetBlue( ( aColor
.GetBlue() & 248 ) | 7 );
1462 aErrQuad
= ( ImpErrorQuad( aColor
) -= aBestCol
);
1463 pQLine1
[ ++nX
].ImplAddColorError7( aErrQuad
);
1464 pQLine2
[ nX
-- ].ImplAddColorError1( aErrQuad
);
1465 pQLine2
[ nX
-- ].ImplAddColorError5( aErrQuad
);
1466 pQLine2
[ nX
++ ].ImplAddColorError3( aErrQuad
);
1467 pWriteAcc
->SetPixel( nY
, nX
, aBestCol
);
1471 aBestCol
= pQLine1
[ nWidth1
].ImplGetColor();
1472 aBestCol
.SetRed( ( aBestCol
.GetRed() & 248 ) | 7 );
1473 aBestCol
.SetGreen( ( aBestCol
.GetGreen() & 248 ) | 7 );
1474 aBestCol
.SetBlue( ( aBestCol
.GetBlue() & 248 ) | 7 );
1475 pWriteAcc
->SetPixel( nY
, nX
, aBestCol
);
1477 // Refill/copy row buffer
1480 pQLine2
= bQ1
? pErrQuad2
.get() : pErrQuad1
.get();
1482 if( nYTmp
< nHeight
)
1483 for( nX
= 0; nX
< nWidth
; nX
++ )
1484 pQLine2
[ nX
] = pReadAcc
->GetPixel( nYTmp
, nX
);
1495 const MapMode
aMap( maPrefMapMode
);
1496 const Size
aSize( maPrefSize
);
1500 maPrefMapMode
= aMap
;
1507 bool Bitmap::ReduceColors( sal_uInt16 nColorCount
, BmpReduce eReduce
)
1511 if( GetColorCount() <= (sal_uLong
) nColorCount
)
1513 else if( nColorCount
)
1515 if( BMP_REDUCE_SIMPLE
== eReduce
)
1516 bRet
= ImplReduceSimple( nColorCount
);
1517 else if( BMP_REDUCE_POPULAR
== eReduce
)
1518 bRet
= ImplReducePopular( nColorCount
);
1520 bRet
= ImplReduceMedian( nColorCount
);
1528 bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount
)
1531 ScopedReadAccess
pRAcc(*this);
1532 const sal_uInt16 nColCount
= std::min( nColorCount
, (sal_uInt16
) 256 );
1533 sal_uInt16 nBitCount
;
1536 if( nColCount
<= 2 )
1538 else if( nColCount
<= 16 )
1545 Octree
aOct( *pRAcc
, nColCount
);
1546 const BitmapPalette
& rPal
= aOct
.GetPalette();
1548 aNewBmp
= Bitmap( GetSizePixel(), nBitCount
, &rPal
);
1549 ScopedWriteAccess
pWAcc(aNewBmp
);
1553 const long nWidth
= pRAcc
->Width();
1554 const long nHeight
= pRAcc
->Height();
1556 if( pRAcc
->HasPalette() )
1558 for( long nY
= 0; nY
< nHeight
; nY
++ )
1559 for( long nX
=0; nX
< nWidth
; nX
++ )
1560 pWAcc
->SetPixelIndex( nY
, nX
, static_cast<sal_uInt8
>(aOct
.GetBestPaletteIndex( pRAcc
->GetPaletteColor( pRAcc
->GetPixelIndex( nY
, nX
) ))) );
1564 for( long nY
= 0; nY
< nHeight
; nY
++ )
1565 for( long nX
=0; nX
< nWidth
; nX
++ )
1566 pWAcc
->SetPixelIndex( nY
, nX
, static_cast<sal_uInt8
>(aOct
.GetBestPaletteIndex( pRAcc
->GetPixel( nY
, nX
) )) );
1578 const MapMode
aMap( maPrefMapMode
);
1579 const Size
aSize( maPrefSize
);
1582 maPrefMapMode
= aMap
;
1589 struct PopularColorCount
1595 extern "C" int SAL_CALL
ImplPopularCmpFnc( const void* p1
, const void* p2
)
1599 if( static_cast<PopularColorCount
const *>(p1
)->mnCount
< static_cast<PopularColorCount
const *>(p2
)->mnCount
)
1601 else if( static_cast<PopularColorCount
const *>(p1
)->mnCount
== static_cast<PopularColorCount
const *>(p2
)->mnCount
)
1609 bool Bitmap::ImplReducePopular( sal_uInt16 nColCount
)
1611 ScopedReadAccess
pRAcc(*this);
1612 sal_uInt16 nBitCount
;
1615 if( nColCount
> 256 )
1618 if( nColCount
< 17 )
1625 const sal_uInt32 nValidBits
= 4;
1626 const sal_uInt32 nRightShiftBits
= 8 - nValidBits
;
1627 const sal_uInt32 nLeftShiftBits1
= nValidBits
;
1628 const sal_uInt32 nLeftShiftBits2
= nValidBits
<< 1;
1629 const sal_uInt32 nColorsPerComponent
= 1 << nValidBits
;
1630 const sal_uInt32 nColorOffset
= 256 / nColorsPerComponent
;
1631 const sal_uInt32 nTotalColors
= nColorsPerComponent
* nColorsPerComponent
* nColorsPerComponent
;
1632 const long nWidth
= pRAcc
->Width();
1633 const long nHeight
= pRAcc
->Height();
1634 std::unique_ptr
<PopularColorCount
[]> pCountTable(new PopularColorCount
[ nTotalColors
]);
1636 memset( pCountTable
.get(), 0, nTotalColors
* sizeof( PopularColorCount
) );
1638 for( long nR
= 0, nIndex
= 0; nR
< 256; nR
+= nColorOffset
)
1640 for( long nG
= 0; nG
< 256; nG
+= nColorOffset
)
1642 for( long nB
= 0; nB
< 256; nB
+= nColorOffset
)
1644 pCountTable
[ nIndex
].mnIndex
= nIndex
;
1650 if( pRAcc
->HasPalette() )
1652 for( long nY
= 0; nY
< nHeight
; nY
++ )
1654 for( long nX
= 0; nX
< nWidth
; nX
++ )
1656 const BitmapColor
& rCol
= pRAcc
->GetPaletteColor( pRAcc
->GetPixelIndex( nY
, nX
) );
1657 pCountTable
[ ( ( ( (sal_uInt32
) rCol
.GetRed() ) >> nRightShiftBits
) << nLeftShiftBits2
) |
1658 ( ( ( (sal_uInt32
) rCol
.GetGreen() ) >> nRightShiftBits
) << nLeftShiftBits1
) |
1659 ( ( (sal_uInt32
) rCol
.GetBlue() ) >> nRightShiftBits
) ].mnCount
++;
1665 for( long nY
= 0; nY
< nHeight
; nY
++ )
1667 for( long nX
= 0; nX
< nWidth
; nX
++ )
1669 const BitmapColor
aCol( pRAcc
->GetPixel( nY
, nX
) );
1670 pCountTable
[ ( ( ( (sal_uInt32
) aCol
.GetRed() ) >> nRightShiftBits
) << nLeftShiftBits2
) |
1671 ( ( ( (sal_uInt32
) aCol
.GetGreen() ) >> nRightShiftBits
) << nLeftShiftBits1
) |
1672 ( ( (sal_uInt32
) aCol
.GetBlue() ) >> nRightShiftBits
) ].mnCount
++;
1677 BitmapPalette
aNewPal( nColCount
);
1679 qsort( pCountTable
.get(), nTotalColors
, sizeof( PopularColorCount
), ImplPopularCmpFnc
);
1681 for( sal_uInt16 n
= 0; n
< nColCount
; n
++ )
1683 const PopularColorCount
& rPop
= pCountTable
[ n
];
1684 aNewPal
[ n
] = BitmapColor( (sal_uInt8
) ( ( rPop
.mnIndex
>> nLeftShiftBits2
) << nRightShiftBits
),
1685 (sal_uInt8
) ( ( ( rPop
.mnIndex
>> nLeftShiftBits1
) & ( nColorsPerComponent
- 1 ) ) << nRightShiftBits
),
1686 (sal_uInt8
) ( ( rPop
.mnIndex
& ( nColorsPerComponent
- 1 ) ) << nRightShiftBits
) );
1689 Bitmap
aNewBmp( GetSizePixel(), nBitCount
, &aNewPal
);
1690 ScopedWriteAccess
pWAcc(aNewBmp
);
1694 BitmapColor
aDstCol( (sal_uInt8
) 0 );
1695 std::unique_ptr
<sal_uInt8
[]> pIndexMap(new sal_uInt8
[ nTotalColors
]);
1697 for( long nR
= 0, nIndex
= 0; nR
< 256; nR
+= nColorOffset
)
1698 for( long nG
= 0; nG
< 256; nG
+= nColorOffset
)
1699 for( long nB
= 0; nB
< 256; nB
+= nColorOffset
)
1700 pIndexMap
[ nIndex
++ ] = (sal_uInt8
) aNewPal
.GetBestIndex( BitmapColor( (sal_uInt8
) nR
, (sal_uInt8
) nG
, (sal_uInt8
) nB
) );
1702 if( pRAcc
->HasPalette() )
1704 for( long nY
= 0; nY
< nHeight
; nY
++ )
1706 for( long nX
= 0; nX
< nWidth
; nX
++ )
1708 const BitmapColor
& rCol
= pRAcc
->GetPaletteColor( pRAcc
->GetPixelIndex( nY
, nX
) );
1709 aDstCol
.SetIndex( pIndexMap
[ ( ( ( (sal_uInt32
) rCol
.GetRed() ) >> nRightShiftBits
) << nLeftShiftBits2
) |
1710 ( ( ( (sal_uInt32
) rCol
.GetGreen() ) >> nRightShiftBits
) << nLeftShiftBits1
) |
1711 ( ( (sal_uInt32
) rCol
.GetBlue() ) >> nRightShiftBits
) ] );
1712 pWAcc
->SetPixel( nY
, nX
, aDstCol
);
1718 for( long nY
= 0; nY
< nHeight
; nY
++ )
1720 for( long nX
= 0; nX
< nWidth
; nX
++ )
1722 const BitmapColor
aCol( pRAcc
->GetPixel( nY
, nX
) );
1723 aDstCol
.SetIndex( pIndexMap
[ ( ( ( (sal_uInt32
) aCol
.GetRed() ) >> nRightShiftBits
) << nLeftShiftBits2
) |
1724 ( ( ( (sal_uInt32
) aCol
.GetGreen() ) >> nRightShiftBits
) << nLeftShiftBits1
) |
1725 ( ( (sal_uInt32
) aCol
.GetBlue() ) >> nRightShiftBits
) ] );
1726 pWAcc
->SetPixel( nY
, nX
, aDstCol
);
1735 pCountTable
.reset();
1740 const MapMode
aMap( maPrefMapMode
);
1741 const Size
aSize( maPrefSize
);
1744 maPrefMapMode
= aMap
;
1752 bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount
)
1754 ScopedReadAccess
pRAcc(*this);
1755 sal_uInt16 nBitCount
;
1758 if( nColCount
< 17 )
1760 else if( nColCount
< 257 )
1764 OSL_FAIL( "Bitmap::ImplReduceMedian(): invalid color count!" );
1771 Bitmap
aNewBmp( GetSizePixel(), nBitCount
);
1772 ScopedWriteAccess
pWAcc(aNewBmp
);
1776 const sal_uLong nSize
= 32768UL * sizeof( sal_uLong
);
1777 sal_uLong
* pColBuf
= static_cast<sal_uLong
*>(rtl_allocateMemory( nSize
));
1778 const long nWidth
= pWAcc
->Width();
1779 const long nHeight
= pWAcc
->Height();
1782 memset( pColBuf
, 0, nSize
);
1785 if( pRAcc
->HasPalette() )
1787 for( long nY
= 0; nY
< nHeight
; nY
++ )
1789 for( long nX
= 0; nX
< nWidth
; nX
++ )
1791 const BitmapColor
& rCol
= pRAcc
->GetPaletteColor( pRAcc
->GetPixelIndex( nY
, nX
) );
1792 pColBuf
[ RGB15( rCol
.GetRed() >> 3, rCol
.GetGreen() >> 3, rCol
.GetBlue() >> 3 ) ]++;
1798 for( long nY
= 0; nY
< nHeight
; nY
++ )
1800 for( long nX
= 0; nX
< nWidth
; nX
++ )
1802 const BitmapColor
aCol( pRAcc
->GetPixel( nY
, nX
) );
1803 pColBuf
[ RGB15( aCol
.GetRed() >> 3, aCol
.GetGreen() >> 3, aCol
.GetBlue() >> 3 ) ]++;
1808 // create palette via median cut
1809 BitmapPalette
aPal( pWAcc
->GetPaletteEntryCount() );
1810 ImplMedianCut( pColBuf
, aPal
, 0, 31, 0, 31, 0, 31,
1811 nColCount
, nWidth
* nHeight
, nIndex
);
1813 // do mapping of colors to palette
1814 InverseColorMap
aMap( aPal
);
1815 pWAcc
->SetPalette( aPal
);
1816 for( long nY
= 0; nY
< nHeight
; nY
++ )
1817 for( long nX
= 0; nX
< nWidth
; nX
++ )
1818 pWAcc
->SetPixelIndex( nY
, nX
, static_cast<sal_uInt8
>( aMap
.GetBestPaletteIndex( pRAcc
->GetColor( nY
, nX
) )) );
1820 rtl_freeMemory( pColBuf
);
1829 const MapMode
aMap( maPrefMapMode
);
1830 const Size
aSize( maPrefSize
);
1833 maPrefMapMode
= aMap
;
1841 void Bitmap::ImplMedianCut( sal_uLong
* pColBuf
, BitmapPalette
& rPal
,
1842 long nR1
, long nR2
, long nG1
, long nG2
, long nB1
, long nB2
,
1843 long nColors
, long nPixels
, long& rIndex
)
1849 const long nRLen
= nR2
- nR1
;
1850 const long nGLen
= nG2
- nG1
;
1851 const long nBLen
= nB2
- nB1
;
1852 sal_uLong
* pBuf
= pColBuf
;
1854 if( !nRLen
&& !nGLen
&& !nBLen
)
1856 if( pBuf
[ RGB15( nR1
, nG1
, nB1
) ] )
1858 aCol
.SetRed( (sal_uInt8
) ( nR1
<< 3 ) );
1859 aCol
.SetGreen( (sal_uInt8
) ( nG1
<< 3 ) );
1860 aCol
.SetBlue( (sal_uInt8
) ( nB1
<< 3 ) );
1861 rPal
[ (sal_uInt16
) rIndex
++ ] = aCol
;
1866 if( 1 == nColors
|| 1 == nPixels
)
1868 long nPixSum
= 0, nRSum
= 0, nGSum
= 0, nBSum
= 0;
1870 for( long nR
= nR1
; nR
<= nR2
; nR
++ )
1872 for( long nG
= nG1
; nG
<= nG2
; nG
++ )
1874 for( long nB
= nB1
; nB
<= nB2
; nB
++ )
1876 nPixSum
= pBuf
[ RGB15( nR
, nG
, nB
) ];
1880 nRSum
+= nR
* nPixSum
;
1881 nGSum
+= nG
* nPixSum
;
1882 nBSum
+= nB
* nPixSum
;
1888 aCol
.SetRed( (sal_uInt8
) ( ( nRSum
/ nPixels
) << 3 ) );
1889 aCol
.SetGreen( (sal_uInt8
) ( ( nGSum
/ nPixels
) << 3 ) );
1890 aCol
.SetBlue( (sal_uInt8
) ( ( nBSum
/ nPixels
) << 3 ) );
1891 rPal
[ (sal_uInt16
) rIndex
++ ] = aCol
;
1895 const long nTest
= ( nPixels
>> 1 );
1899 if( nBLen
> nGLen
&& nBLen
> nRLen
)
1903 while( nPixNew
< nTest
)
1907 for( long nR
= nR1
; nR
<= nR2
; nR
++ )
1908 for( long nG
= nG1
; nG
<= nG2
; nG
++ )
1909 nPixNew
+= pBuf
[ RGB15( nR
, nG
, nB
) ];
1914 ImplMedianCut( pBuf
, rPal
, nR1
, nR2
, nG1
, nG2
, nB1
, nB
, nColors
>> 1, nPixNew
, rIndex
);
1915 ImplMedianCut( pBuf
, rPal
, nR1
, nR2
, nG1
, nG2
, nB
+ 1, nB2
, nColors
>> 1, nPixels
- nPixNew
, rIndex
);
1919 ImplMedianCut( pBuf
, rPal
, nR1
, nR2
, nG1
, nG2
, nB1
, nB
- 1, nColors
>> 1, nPixOld
, rIndex
);
1920 ImplMedianCut( pBuf
, rPal
, nR1
, nR2
, nG1
, nG2
, nB
, nB2
, nColors
>> 1, nPixels
- nPixOld
, rIndex
);
1923 else if( nGLen
> nRLen
)
1927 while( nPixNew
< nTest
)
1931 for( long nR
= nR1
; nR
<= nR2
; nR
++ )
1932 for( long nB
= nB1
; nB
<= nB2
; nB
++ )
1933 nPixNew
+= pBuf
[ RGB15( nR
, nG
, nB
) ];
1938 ImplMedianCut( pBuf
, rPal
, nR1
, nR2
, nG1
, nG
, nB1
, nB2
, nColors
>> 1, nPixNew
, rIndex
);
1939 ImplMedianCut( pBuf
, rPal
, nR1
, nR2
, nG
+ 1, nG2
, nB1
, nB2
, nColors
>> 1, nPixels
- nPixNew
, rIndex
);
1943 ImplMedianCut( pBuf
, rPal
, nR1
, nR2
, nG1
, nG
- 1, nB1
, nB2
, nColors
>> 1, nPixOld
, rIndex
);
1944 ImplMedianCut( pBuf
, rPal
, nR1
, nR2
, nG
, nG2
, nB1
, nB2
, nColors
>> 1, nPixels
- nPixOld
, rIndex
);
1951 while( nPixNew
< nTest
)
1955 for( long nG
= nG1
; nG
<= nG2
; nG
++ )
1956 for( long nB
= nB1
; nB
<= nB2
; nB
++ )
1957 nPixNew
+= pBuf
[ RGB15( nR
, nG
, nB
) ];
1962 ImplMedianCut( pBuf
, rPal
, nR1
, nR
, nG1
, nG2
, nB1
, nB2
, nColors
>> 1, nPixNew
, rIndex
);
1963 ImplMedianCut( pBuf
, rPal
, nR1
+ 1, nR2
, nG1
, nG2
, nB1
, nB2
, nColors
>> 1, nPixels
- nPixNew
, rIndex
);
1967 ImplMedianCut( pBuf
, rPal
, nR1
, nR
- 1, nG1
, nG2
, nB1
, nB2
, nColors
>> 1, nPixOld
, rIndex
);
1968 ImplMedianCut( pBuf
, rPal
, nR
, nR2
, nG1
, nG2
, nB1
, nB2
, nColors
>> 1, nPixels
- nPixOld
, rIndex
);
1975 bool Bitmap::Vectorize( GDIMetaFile
& rMtf
, sal_uInt8 cReduce
, const Link
<long,void>* pProgress
)
1977 return ImplVectorizer::ImplVectorize( *this, rMtf
, cReduce
, pProgress
);
1980 bool Bitmap::Adjust( short nLuminancePercent
, short nContrastPercent
,
1981 short nChannelRPercent
, short nChannelGPercent
, short nChannelBPercent
,
1982 double fGamma
, bool bInvert
, bool msoBrightness
)
1986 // nothing to do => return quickly
1987 if( !nLuminancePercent
&& !nContrastPercent
&&
1988 !nChannelRPercent
&& !nChannelGPercent
&& !nChannelBPercent
&&
1989 ( fGamma
== 1.0 ) && !bInvert
)
1995 ScopedWriteAccess
pAcc(*this);
2000 const long nW
= pAcc
->Width();
2001 const long nH
= pAcc
->Height();
2002 std::unique_ptr
<sal_uInt8
[]> cMapR(new sal_uInt8
[ 256 ]);
2003 std::unique_ptr
<sal_uInt8
[]> cMapG(new sal_uInt8
[ 256 ]);
2004 std::unique_ptr
<sal_uInt8
[]> cMapB(new sal_uInt8
[ 256 ]);
2005 double fM
, fROff
, fGOff
, fBOff
, fOff
;
2008 if( nContrastPercent
>= 0 )
2009 fM
= 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent
, 0, 100 ) );
2011 fM
= ( 128.0 + 1.27 * MinMax( nContrastPercent
, -100, 0 ) ) / 128.0;
2014 // total offset = luminance offset + contrast offset
2015 fOff
= MinMax( nLuminancePercent
, -100, 100 ) * 2.55 + 128.0 - fM
* 128.0;
2017 fOff
= MinMax( nLuminancePercent
, -100, 100 ) * 2.55;
2019 // channel offset = channel offset + total offset
2020 fROff
= nChannelRPercent
* 2.55 + fOff
;
2021 fGOff
= nChannelGPercent
* 2.55 + fOff
;
2022 fBOff
= nChannelBPercent
* 2.55 + fOff
;
2024 // calculate gamma value
2025 fGamma
= ( fGamma
<= 0.0 || fGamma
> 10.0 ) ? 1.0 : ( 1.0 / fGamma
);
2026 const bool bGamma
= ( fGamma
!= 1.0 );
2028 // create mapping table
2029 for( long nX
= 0; nX
< 256; nX
++ )
2033 cMapR
[ nX
] = (sal_uInt8
) MinMax( FRound( nX
* fM
+ fROff
), 0, 255 );
2034 cMapG
[ nX
] = (sal_uInt8
) MinMax( FRound( nX
* fM
+ fGOff
), 0, 255 );
2035 cMapB
[ nX
] = (sal_uInt8
) MinMax( FRound( nX
* fM
+ fBOff
), 0, 255 );
2039 // LO simply uses (in a somewhat optimized form) "newcolor = (oldcolor-128)*contrast+brightness+128"
2040 // as the formula, i.e. contrast first, brightness afterwards. MSOffice, for whatever weird reason,
2041 // use neither first, but apparently it applies half of brightness before contrast and half afterwards.
2042 cMapR
[ nX
] = (sal_uInt8
) MinMax( FRound( (nX
+fROff
/2-128) * fM
+ 128 + fROff
/2 ), 0, 255 );
2043 cMapG
[ nX
] = (sal_uInt8
) MinMax( FRound( (nX
+fGOff
/2-128) * fM
+ 128 + fGOff
/2 ), 0, 255 );
2044 cMapB
[ nX
] = (sal_uInt8
) MinMax( FRound( (nX
+fBOff
/2-128) * fM
+ 128 + fBOff
/2 ), 0, 255 );
2048 cMapR
[ nX
] = GAMMA( cMapR
[ nX
], fGamma
);
2049 cMapG
[ nX
] = GAMMA( cMapG
[ nX
], fGamma
);
2050 cMapB
[ nX
] = GAMMA( cMapB
[ nX
], fGamma
);
2055 cMapR
[ nX
] = ~cMapR
[ nX
];
2056 cMapG
[ nX
] = ~cMapG
[ nX
];
2057 cMapB
[ nX
] = ~cMapB
[ nX
];
2062 if( pAcc
->HasPalette() )
2064 BitmapColor aNewCol
;
2066 for( sal_uInt16 i
= 0, nCount
= pAcc
->GetPaletteEntryCount(); i
< nCount
; i
++ )
2068 const BitmapColor
& rCol
= pAcc
->GetPaletteColor( i
);
2069 aNewCol
.SetRed( cMapR
[ rCol
.GetRed() ] );
2070 aNewCol
.SetGreen( cMapG
[ rCol
.GetGreen() ] );
2071 aNewCol
.SetBlue( cMapB
[ rCol
.GetBlue() ] );
2072 pAcc
->SetPaletteColor( i
, aNewCol
);
2075 else if( pAcc
->GetScanlineFormat() == ScanlineFormat::N24BitTcBgr
)
2077 for( long nY
= 0; nY
< nH
; nY
++ )
2079 Scanline pScan
= pAcc
->GetScanline( nY
);
2081 for( long nX
= 0; nX
< nW
; nX
++ )
2083 *pScan
= cMapB
[ *pScan
]; pScan
++;
2084 *pScan
= cMapG
[ *pScan
]; pScan
++;
2085 *pScan
= cMapR
[ *pScan
]; pScan
++;
2089 else if( pAcc
->GetScanlineFormat() == ScanlineFormat::N24BitTcRgb
)
2091 for( long nY
= 0; nY
< nH
; nY
++ )
2093 Scanline pScan
= pAcc
->GetScanline( nY
);
2095 for( long nX
= 0; nX
< nW
; nX
++ )
2097 *pScan
= cMapR
[ *pScan
]; pScan
++;
2098 *pScan
= cMapG
[ *pScan
]; pScan
++;
2099 *pScan
= cMapB
[ *pScan
]; pScan
++;
2105 for( long nY
= 0; nY
< nH
; nY
++ )
2107 for( long nX
= 0; nX
< nW
; nX
++ )
2109 aCol
= pAcc
->GetPixel( nY
, nX
);
2110 aCol
.SetRed( cMapR
[ aCol
.GetRed() ] );
2111 aCol
.SetGreen( cMapG
[ aCol
.GetGreen() ] );
2112 aCol
.SetBlue( cMapB
[ aCol
.GetBlue() ] );
2113 pAcc
->SetPixel( nY
, nX
, aCol
);
2126 bool Bitmap::ImplConvolutionPass(Bitmap
& aNewBitmap
, BitmapReadAccess
* pReadAcc
, int aNumberOfContributions
, double* pWeights
, int* pPixels
, int* pCount
)
2131 ScopedWriteAccess
pWriteAcc(aNewBitmap
);
2135 const int nHeight
= GetSizePixel().Height();
2136 assert(GetSizePixel().Height() == aNewBitmap
.GetSizePixel().Width());
2137 const int nWidth
= GetSizePixel().Width();
2138 assert(GetSizePixel().Width() == aNewBitmap
.GetSizePixel().Height());
2141 double aValueRed
, aValueGreen
, aValueBlue
;
2142 double aSum
, aWeight
;
2143 int aBaseIndex
, aIndex
;
2145 for (int nSourceY
= 0; nSourceY
< nHeight
; ++nSourceY
)
2147 for (int nSourceX
= 0; nSourceX
< nWidth
; ++nSourceX
)
2149 aBaseIndex
= nSourceX
* aNumberOfContributions
;
2150 aSum
= aValueRed
= aValueGreen
= aValueBlue
= 0.0;
2152 for (int j
= 0; j
< pCount
[nSourceX
]; ++j
)
2154 aIndex
= aBaseIndex
+ j
;
2155 aSum
+= aWeight
= pWeights
[ aIndex
];
2157 aColor
= pReadAcc
->GetColor(nSourceY
, pPixels
[aIndex
]);
2159 aValueRed
+= aWeight
* aColor
.GetRed();
2160 aValueGreen
+= aWeight
* aColor
.GetGreen();
2161 aValueBlue
+= aWeight
* aColor
.GetBlue();
2164 BitmapColor
aResultColor(
2165 (sal_uInt8
) MinMax( aValueRed
/ aSum
, 0, 255 ),
2166 (sal_uInt8
) MinMax( aValueGreen
/ aSum
, 0, 255 ),
2167 (sal_uInt8
) MinMax( aValueBlue
/ aSum
, 0, 255 ) );
2169 int nDestX
= nSourceY
;
2170 int nDestY
= nSourceX
;
2172 pWriteAcc
->SetPixel(nDestY
, nDestX
, aResultColor
);
2178 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */