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 .
22 #include <vcl/bitmapaccess.hxx>
23 #include <vcl/bitmapex.hxx>
24 #include <vcl/bitmap.hxx>
25 #include <config_features.h>
26 #include <sal/log.hxx>
27 #include <osl/diagnose.h>
28 #include <tools/helpers.hxx>
29 #if HAVE_FEATURE_OPENGL
30 #include <vcl/opengl/OpenGLHelper.hxx>
32 #include <vcl/BitmapMonochromeFilter.hxx>
34 #include <BitmapScaleSuperFilter.hxx>
35 #include <BitmapScaleConvolutionFilter.hxx>
36 #include <BitmapFastScaleFilter.hxx>
37 #include <BitmapInterpolateScaleFilter.hxx>
38 #include <bitmapwriteaccess.hxx>
39 #include <bitmap/impoctree.hxx>
40 #include <bitmap/Octree.hxx>
42 #include <salinst.hxx>
45 #include "impvect.hxx"
49 #define GAMMA( _def_cVal, _def_InvGamma ) (static_cast<sal_uInt8>(MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0,255)))
52 nTemp = p1T[nX++] >> 12; \
53 nBErr = MinMax( nTemp, 0, 255 ); \
54 nBErr = nBErr - FloydIndexMap[ nBC = FloydMap[nBErr] ]; \
55 nTemp = p1T[nX++] >> 12; \
56 nGErr = MinMax( nTemp, 0, 255 ); \
57 nGErr = nGErr - FloydIndexMap[ nGC = FloydMap[nGErr] ]; \
58 nTemp = p1T[nX] >> 12; \
59 nRErr = MinMax( nTemp, 0, 255 ); \
60 nRErr = nRErr - FloydIndexMap[ nRC = FloydMap[nRErr] ];
62 #define CALC_TABLES3 \
63 p2T[nX++] += FloydError3[nBErr]; \
64 p2T[nX++] += FloydError3[nGErr]; \
65 p2T[nX++] += FloydError3[nRErr];
67 #define CALC_TABLES5 \
68 p2T[nX++] += FloydError5[nBErr]; \
69 p2T[nX++] += FloydError5[nGErr]; \
70 p2T[nX++] += FloydError5[nRErr];
72 #define CALC_TABLES7 \
73 p1T[++nX] += FloydError7[nBErr]; \
74 p2T[nX++] += FloydError1[nBErr]; \
75 p1T[nX] += FloydError7[nGErr]; \
76 p2T[nX++] += FloydError1[nGErr]; \
77 p1T[nX] += FloydError7[nRErr]; \
78 p2T[nX] += FloydError1[nRErr];
80 const extern sal_uLong nVCLRLut
[ 6 ] = { 16, 17, 18, 19, 20, 21 };
81 const extern sal_uLong nVCLGLut
[ 6 ] = { 0, 6, 12, 18, 24, 30 };
82 const extern sal_uLong nVCLBLut
[ 6 ] = { 0, 36, 72, 108, 144, 180 };
84 const extern sal_uLong nVCLDitherLut
[ 256 ] =
86 0, 49152, 12288, 61440, 3072, 52224, 15360, 64512, 768, 49920, 13056,
87 62208, 3840, 52992, 16128, 65280, 32768, 16384, 45056, 28672, 35840, 19456,
88 48128, 31744, 33536, 17152, 45824, 29440, 36608, 20224, 48896, 32512, 8192,
89 57344, 4096, 53248, 11264, 60416, 7168, 56320, 8960, 58112, 4864, 54016,
90 12032, 61184, 7936, 57088, 40960, 24576, 36864, 20480, 44032, 27648, 39936,
91 23552, 41728, 25344, 37632, 21248, 44800, 28416, 40704, 24320, 2048, 51200,
92 14336, 63488, 1024, 50176, 13312, 62464, 2816, 51968, 15104, 64256, 1792,
93 50944, 14080, 63232, 34816, 18432, 47104, 30720, 33792, 17408, 46080, 29696,
94 35584, 19200, 47872, 31488, 34560, 18176, 46848, 30464, 10240, 59392, 6144,
95 55296, 9216, 58368, 5120, 54272, 11008, 60160, 6912, 56064, 9984, 59136,
96 5888, 55040, 43008, 26624, 38912, 22528, 41984, 25600, 37888, 21504, 43776,
97 27392, 39680, 23296, 42752, 26368, 38656, 22272, 512, 49664, 12800, 61952,
98 3584, 52736, 15872, 65024, 256, 49408, 12544, 61696, 3328, 52480, 15616,
99 64768, 33280, 16896, 45568, 29184, 36352, 19968, 48640, 32256, 33024, 16640,
100 45312, 28928, 36096, 19712, 48384, 32000, 8704, 57856, 4608, 53760, 11776,
101 60928, 7680, 56832, 8448, 57600, 4352, 53504, 11520, 60672, 7424, 56576,
102 41472, 25088, 37376, 20992, 44544, 28160, 40448, 24064, 41216, 24832, 37120,
103 20736, 44288, 27904, 40192, 23808, 2560, 51712, 14848, 64000, 1536, 50688,
104 13824, 62976, 2304, 51456, 14592, 63744, 1280, 50432, 13568, 62720, 35328,
105 18944, 47616, 31232, 34304, 17920, 46592, 30208, 35072, 18688, 47360, 30976,
106 34048, 17664, 46336, 29952, 10752, 59904, 6656, 55808, 9728, 58880, 5632,
107 54784, 10496, 59648, 6400, 55552, 9472, 58624, 5376, 54528, 43520, 27136,
108 39424, 23040, 42496, 26112, 38400, 22016, 43264, 26880, 39168, 22784, 42240,
112 const extern sal_uLong nVCLLut
[ 256 ] =
114 0, 1286, 2572, 3858, 5144, 6430, 7716, 9002,
115 10288, 11574, 12860, 14146, 15432, 16718, 18004, 19290,
116 20576, 21862, 23148, 24434, 25720, 27006, 28292, 29578,
117 30864, 32150, 33436, 34722, 36008, 37294, 38580, 39866,
118 41152, 42438, 43724, 45010, 46296, 47582, 48868, 50154,
119 51440, 52726, 54012, 55298, 56584, 57870, 59156, 60442,
120 61728, 63014, 64300, 65586, 66872, 68158, 69444, 70730,
121 72016, 73302, 74588, 75874, 77160, 78446, 79732, 81018,
122 82304, 83590, 84876, 86162, 87448, 88734, 90020, 91306,
123 92592, 93878, 95164, 96450, 97736, 99022,100308,101594,
124 102880,104166,105452,106738,108024,109310,110596,111882,
125 113168,114454,115740,117026,118312,119598,120884,122170,
126 123456,124742,126028,127314,128600,129886,131172,132458,
127 133744,135030,136316,137602,138888,140174,141460,142746,
128 144032,145318,146604,147890,149176,150462,151748,153034,
129 154320,155606,156892,158178,159464,160750,162036,163322,
130 164608,165894,167180,168466,169752,171038,172324,173610,
131 174896,176182,177468,178754,180040,181326,182612,183898,
132 185184,186470,187756,189042,190328,191614,192900,194186,
133 195472,196758,198044,199330,200616,201902,203188,204474,
134 205760,207046,208332,209618,210904,212190,213476,214762,
135 216048,217334,218620,219906,221192,222478,223764,225050,
136 226336,227622,228908,230194,231480,232766,234052,235338,
137 236624,237910,239196,240482,241768,243054,244340,245626,
138 246912,248198,249484,250770,252056,253342,254628,255914,
139 257200,258486,259772,261058,262344,263630,264916,266202,
140 267488,268774,270060,271346,272632,273918,275204,276490,
141 277776,279062,280348,281634,282920,284206,285492,286778,
142 288064,289350,290636,291922,293208,294494,295780,297066,
143 298352,299638,300924,302210,303496,304782,306068,307354,
144 308640,309926,311212,312498,313784,315070,316356,317642,
145 318928,320214,321500,322786,324072,325358,326644,327930
148 const long FloydMap
[256] =
150 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
151 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
152 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
153 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
154 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
155 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
156 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
157 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
158 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
159 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
160 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
161 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
162 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
163 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
164 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
165 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
168 const long FloydError1
[61] =
170 -7680, -7424, -7168, -6912, -6656, -6400, -6144,
171 -5888, -5632, -5376, -5120, -4864, -4608, -4352,
172 -4096, -3840, -3584, -3328, -3072, -2816, -2560,
173 -2304, -2048, -1792, -1536, -1280, -1024, -768,
174 -512, -256, 0, 256, 512, 768, 1024, 1280, 1536,
175 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
176 3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632,
177 5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680
180 const long FloydError3
[61] =
182 -23040, -22272, -21504, -20736, -19968, -19200,
183 -18432, -17664, -16896, -16128, -15360, -14592,
184 -13824, -13056, -12288, -11520, -10752, -9984,
185 -9216, -8448, -7680, -6912, -6144, -5376, -4608,
186 -3840, -3072, -2304, -1536, -768, 0, 768, 1536,
187 2304, 3072, 3840, 4608, 5376, 6144, 6912, 7680,
188 8448, 9216, 9984, 10752, 11520, 12288, 13056,
189 13824, 14592, 15360, 16128, 16896, 17664, 18432,
190 19200, 19968, 20736, 21504, 22272, 23040
193 const long FloydError5
[61] =
195 -38400, -37120, -35840, -34560, -33280, -32000,
196 -30720, -29440, -28160, -26880, -25600, -24320,
197 -23040, -21760, -20480, -19200, -17920, -16640,
198 -15360, -14080, -12800, -11520, -10240, -8960,
199 -7680, -6400, -5120, -3840, -2560, -1280, 0,
200 1280, 2560, 3840, 5120, 6400, 7680, 8960, 10240,
201 11520, 12800, 14080, 15360, 16640, 17920, 19200,
202 20480, 21760, 23040, 24320, 25600, 26880, 28160,
203 29440, 30720, 32000, 33280, 34560, 35840, 37120,
207 const long FloydError7
[61] =
209 -53760, -51968, -50176, -48384, -46592, -44800,
210 -43008, -41216, -39424, -37632, -35840, -34048,
211 -32256, -30464, -28672, -26880, -25088, -23296,
212 -21504, -19712, -17920, -16128, -14336, -12544,
213 -10752, -8960, -7168, -5376, -3584, -1792, 0,
214 1792, 3584, 5376, 7168, 8960, 10752, 12544, 14336,
215 16128, 17920, 19712, 21504, 23296, 25088, 26880,
216 28672, 30464, 32256, 34048, 35840, 37632, 39424,
217 41216, 43008, 44800, 46592, 48384, 50176, 51968,
221 const long FloydIndexMap
[6] =
223 -30, 21, 72, 123, 174, 225
226 bool Bitmap::Convert( BmpConversion eConversion
)
228 // try to convert in backend
231 // avoid large chunk of obsolete and hopefully rarely used conversions.
232 if (eConversion
== BmpConversion::N8BitGreys
)
234 std::shared_ptr
<SalBitmap
> xImpBmp(ImplGetSVData()->mpDefInst
->CreateSalBitmap());
235 // frequently used conversion for creating alpha masks
236 if (xImpBmp
->Create(*mxSalBmp
) && xImpBmp
->ConvertToGreyscale())
238 ImplSetSalBitmap(xImpBmp
);
239 SAL_INFO( "vcl.opengl", "Ref count: " << mxSalBmp
.use_count() );
245 const sal_uInt16 nBitCount
= GetBitCount ();
248 switch( eConversion
)
250 case BmpConversion::N1BitThreshold
:
252 BitmapEx
aBmpEx(*this);
253 bRet
= BitmapFilter::Filter(aBmpEx
, BitmapMonochromeFilter(128));
254 *this = aBmpEx
.GetBitmap();
258 case BmpConversion::N4BitGreys
:
259 bRet
= ImplMakeGreyscales( 16 );
262 case BmpConversion::N4BitColors
:
265 bRet
= ImplConvertUp( 4 );
266 else if( nBitCount
> 4 )
267 bRet
= ImplConvertDown( 4 );
273 case BmpConversion::N8BitGreys
:
274 bRet
= ImplMakeGreyscales( 256 );
277 case BmpConversion::N8BitColors
:
280 bRet
= ImplConvertUp( 8 );
281 else if( nBitCount
> 8 )
282 bRet
= ImplConvertDown( 8 );
288 case BmpConversion::N8BitTrans
:
290 Color
aTrans( BMP_COL_TRANS
);
293 bRet
= ImplConvertUp( 8, &aTrans
);
295 bRet
= ImplConvertDown( 8, &aTrans
);
299 case BmpConversion::N24Bit
:
302 bRet
= ImplConvertUp( 24 );
308 case BmpConversion::Ghosted
:
309 bRet
= ImplConvertGhosted();
313 OSL_FAIL( "Bitmap::Convert(): Unsupported conversion" );
320 bool Bitmap::ImplMakeGreyscales( sal_uInt16 nGreys
)
322 SAL_WARN_IF( nGreys
!= 16 && nGreys
!= 256, "vcl", "Only 16 or 256 greyscales are supported!" );
324 ScopedReadAccess
pReadAcc(*this);
329 const BitmapPalette
& rPal
= GetGreyPalette( nGreys
);
330 sal_uLong nShift
= ( ( nGreys
== 16 ) ? 4UL : 0UL );
331 bool bPalDiffers
= !pReadAcc
->HasPalette() || ( rPal
.GetEntryCount() != pReadAcc
->GetPaletteEntryCount() );
334 bPalDiffers
= ( rPal
!= pReadAcc
->GetPalette() );
338 Bitmap
aNewBmp( GetSizePixel(), ( nGreys
== 16 ) ? 4 : 8, &rPal
);
339 BitmapScopedWriteAccess
pWriteAcc(aNewBmp
);
343 const long nWidth
= pWriteAcc
->Width();
344 const long nHeight
= pWriteAcc
->Height();
346 if( pReadAcc
->HasPalette() )
348 for( long nY
= 0; nY
< nHeight
; nY
++ )
350 Scanline pScanline
= pWriteAcc
->GetScanline(nY
);
351 Scanline pScanlineRead
= pReadAcc
->GetScanline(nY
);
352 for( long nX
= 0; nX
< nWidth
; nX
++ )
354 const sal_uInt8 cIndex
= pReadAcc
->GetIndexFromData( pScanlineRead
, nX
);
355 pWriteAcc
->SetPixelOnData( pScanline
, nX
,
356 BitmapColor(pReadAcc
->GetPaletteColor( cIndex
).GetLuminance() >> nShift
) );
360 else if( pReadAcc
->GetScanlineFormat() == ScanlineFormat::N24BitTcBgr
&&
361 pWriteAcc
->GetScanlineFormat() == ScanlineFormat::N8BitPal
)
365 for( long nY
= 0; nY
< nHeight
; nY
++ )
367 Scanline pReadScan
= pReadAcc
->GetScanline( nY
);
368 Scanline pWriteScan
= pWriteAcc
->GetScanline( nY
);
370 for( long nX
= 0; nX
< nWidth
; nX
++ )
372 const sal_uLong nB
= *pReadScan
++;
373 const sal_uLong nG
= *pReadScan
++;
374 const sal_uLong nR
= *pReadScan
++;
376 *pWriteScan
++ = static_cast<sal_uInt8
>( ( nB
* 28UL + nG
* 151UL + nR
* 77UL ) >> nShift
);
380 else if( pReadAcc
->GetScanlineFormat() == ScanlineFormat::N24BitTcRgb
&&
381 pWriteAcc
->GetScanlineFormat() == ScanlineFormat::N8BitPal
)
385 for( long nY
= 0; nY
< nHeight
; nY
++ )
387 Scanline pReadScan
= pReadAcc
->GetScanline( nY
);
388 Scanline pWriteScan
= pWriteAcc
->GetScanline( nY
);
390 for( long nX
= 0; nX
< nWidth
; nX
++ )
392 const sal_uLong nR
= *pReadScan
++;
393 const sal_uLong nG
= *pReadScan
++;
394 const sal_uLong nB
= *pReadScan
++;
396 *pWriteScan
++ = static_cast<sal_uInt8
>( ( nB
* 28UL + nG
* 151UL + nR
* 77UL ) >> nShift
);
402 for( long nY
= 0; nY
< nHeight
; nY
++ )
404 Scanline pScanline
= pWriteAcc
->GetScanline(nY
);
405 Scanline pScanlineRead
= pReadAcc
->GetScanline(nY
);
406 for( long nX
= 0; nX
< nWidth
; nX
++ )
407 pWriteAcc
->SetPixelOnData( pScanline
, nX
, BitmapColor(pReadAcc
->GetPixelFromData( pScanlineRead
, nX
).GetLuminance() >> nShift
) );
419 const MapMode
aMap( maPrefMapMode
);
420 const Size
aSize( maPrefSize
);
424 maPrefMapMode
= aMap
;
438 bool Bitmap::ImplConvertUp(sal_uInt16 nBitCount
, Color
const * pExtColor
)
440 SAL_WARN_IF( nBitCount
<= GetBitCount(), "vcl", "New BitCount must be greater!" );
442 Bitmap::ScopedReadAccess
pReadAcc(*this);
447 BitmapPalette aPalette
;
448 Bitmap
aNewBmp(GetSizePixel(), nBitCount
, pReadAcc
->HasPalette() ? &pReadAcc
->GetPalette() : &aPalette
);
449 BitmapScopedWriteAccess
pWriteAcc(aNewBmp
);
453 const long nWidth
= pWriteAcc
->Width();
454 const long nHeight
= pWriteAcc
->Height();
456 if (pWriteAcc
->HasPalette())
458 const BitmapPalette
& rOldPalette
= pReadAcc
->GetPalette();
459 const sal_uInt16 nOldCount
= rOldPalette
.GetEntryCount();
460 assert(nOldCount
<= (1 << GetBitCount()));
462 aPalette
.SetEntryCount(1 << nBitCount
);
464 for (sal_uInt16 i
= 0; i
< nOldCount
; i
++)
465 aPalette
[i
] = rOldPalette
[i
];
468 aPalette
[aPalette
.GetEntryCount() - 1] = *pExtColor
;
470 pWriteAcc
->SetPalette(aPalette
);
472 for (long nY
= 0; nY
< nHeight
; nY
++)
474 Scanline pScanline
= pWriteAcc
->GetScanline(nY
);
475 Scanline pScanlineRead
= pReadAcc
->GetScanline(nY
);
476 for (long nX
= 0; nX
< nWidth
; nX
++)
478 pWriteAcc
->SetPixelOnData(pScanline
, nX
, pReadAcc
->GetPixelFromData(pScanlineRead
, nX
));
484 if (pReadAcc
->HasPalette())
486 for (long nY
= 0; nY
< nHeight
; nY
++)
488 Scanline pScanline
= pWriteAcc
->GetScanline(nY
);
489 Scanline pScanlineRead
= pReadAcc
->GetScanline(nY
);
490 for (long nX
= 0; nX
< nWidth
; nX
++)
492 pWriteAcc
->SetPixelOnData(pScanline
, nX
, pReadAcc
->GetPaletteColor(pReadAcc
->GetIndexFromData(pScanlineRead
, nX
)));
498 for (long nY
= 0; nY
< nHeight
; nY
++)
500 Scanline pScanline
= pWriteAcc
->GetScanline(nY
);
501 Scanline pScanlineRead
= pReadAcc
->GetScanline(nY
);
502 for (long nX
= 0; nX
< nWidth
; nX
++)
504 pWriteAcc
->SetPixelOnData(pScanline
, nX
, pReadAcc
->GetPixelFromData(pScanlineRead
, nX
));
514 const MapMode
aMap(maPrefMapMode
);
515 const Size
aSize(maPrefSize
);
519 maPrefMapMode
= aMap
;
527 bool Bitmap::ImplConvertDown(sal_uInt16 nBitCount
, Color
const * pExtColor
)
529 SAL_WARN_IF(nBitCount
> GetBitCount(), "vcl", "New BitCount must be lower ( or equal when pExtColor is set )!");
531 Bitmap::ScopedReadAccess
pReadAcc(*this);
536 BitmapPalette aPalette
;
537 Bitmap
aNewBmp(GetSizePixel(), nBitCount
, &aPalette
);
538 BitmapScopedWriteAccess
pWriteAcc(aNewBmp
);
542 const sal_uInt16 nCount
= 1 << nBitCount
;
543 const long nWidth
= pWriteAcc
->Width();
544 const long nWidth1
= nWidth
- 1;
545 const long nHeight
= pWriteAcc
->Height();
546 Octree
aOctree(*pReadAcc
, pExtColor
? (nCount
- 1) : nCount
);
547 aPalette
= aOctree
.GetPalette();
548 InverseColorMap
aColorMap(aPalette
);
550 ImpErrorQuad aErrQuad
;
551 std::vector
<ImpErrorQuad
> aErrQuad1(nWidth
);
552 std::vector
<ImpErrorQuad
> aErrQuad2(nWidth
);
553 ImpErrorQuad
* pQLine1
= aErrQuad1
.data();
554 ImpErrorQuad
* pQLine2
= nullptr;
561 aPalette
.SetEntryCount(aPalette
.GetEntryCount() + 1);
562 aPalette
[aPalette
.GetEntryCount() - 1] = *pExtColor
;
565 // set Black/White always, if we have enough space
566 if (aPalette
.GetEntryCount() < (nCount
- 1))
568 aPalette
.SetEntryCount(aPalette
.GetEntryCount() + 2);
569 aPalette
[aPalette
.GetEntryCount() - 2] = COL_BLACK
;
570 aPalette
[aPalette
.GetEntryCount() - 1] = COL_WHITE
;
573 pWriteAcc
->SetPalette(aPalette
);
575 for (long nY
= 0; nY
< std::min(nHeight
, 2L); nY
++, nYTmp
++)
577 pQLine2
= !nY
? aErrQuad1
.data() : aErrQuad2
.data();
578 Scanline pScanlineRead
= pReadAcc
->GetScanline(nYTmp
);
579 for (long nX
= 0; nX
< nWidth
; nX
++)
581 if (pReadAcc
->HasPalette())
582 pQLine2
[nX
] = pReadAcc
->GetPaletteColor(pReadAcc
->GetIndexFromData(pScanlineRead
, nX
));
584 pQLine2
[nX
] = pReadAcc
->GetPixelFromData(pScanlineRead
, nX
);
588 assert(pQLine2
|| nHeight
== 0);
590 for (long nY
= 0; nY
< nHeight
; nY
++, nYTmp
++)
592 // first pixel in the line
593 cIndex
= static_cast<sal_uInt8
>(aColorMap
.GetBestPaletteIndex(pQLine1
[0].ImplGetColor()));
594 Scanline pScanline
= pWriteAcc
->GetScanline(nY
);
595 pWriteAcc
->SetPixelOnData(pScanline
, 0, BitmapColor(cIndex
));
598 for (nX
= 1; nX
< nWidth1
; nX
++)
600 aColor
= pQLine1
[nX
].ImplGetColor();
601 cIndex
= static_cast<sal_uInt8
>(aColorMap
.GetBestPaletteIndex(aColor
));
602 aErrQuad
= (ImpErrorQuad(aColor
) -= pWriteAcc
->GetPaletteColor(cIndex
));
603 pQLine1
[++nX
].ImplAddColorError7(aErrQuad
);
604 pQLine2
[nX
--].ImplAddColorError1(aErrQuad
);
605 pQLine2
[nX
--].ImplAddColorError5(aErrQuad
);
606 pQLine2
[nX
++].ImplAddColorError3(aErrQuad
);
607 pWriteAcc
->SetPixelOnData(pScanline
, nX
, BitmapColor(cIndex
));
613 cIndex
= static_cast<sal_uInt8
>(aColorMap
.GetBestPaletteIndex(pQLine1
[nWidth1
].ImplGetColor()));
614 pWriteAcc
->SetPixelOnData(pScanline
, nX
, BitmapColor(cIndex
));
617 // Refill/copy row buffer
620 pQLine2
= bQ1
? aErrQuad2
.data() : aErrQuad1
.data();
624 Scanline pScanlineRead
= pReadAcc
->GetScanline(nYTmp
);
625 for (nX
= 0; nX
< nWidth
; nX
++)
627 if (pReadAcc
->HasPalette())
628 pQLine2
[nX
] = pReadAcc
->GetPaletteColor(pReadAcc
->GetIndexFromData(pScanlineRead
, nX
));
630 pQLine2
[nX
] = pReadAcc
->GetPixelFromData(pScanlineRead
, nX
);
640 const MapMode
aMap(maPrefMapMode
);
641 const Size
aSize(maPrefSize
);
645 maPrefMapMode
= aMap
;
653 bool Bitmap::ImplConvertGhosted()
656 ScopedReadAccess
pR(*this);
661 if( pR
->HasPalette() )
663 BitmapPalette
aNewPal( pR
->GetPaletteEntryCount() );
665 for( long i
= 0, nCount
= aNewPal
.GetEntryCount(); i
< nCount
; i
++ )
667 const BitmapColor
& rOld
= pR
->GetPaletteColor( static_cast<sal_uInt16
>(i
) );
668 aNewPal
[ static_cast<sal_uInt16
>(i
) ] = BitmapColor( ( rOld
.GetRed() >> 1 ) | 0x80,
669 ( rOld
.GetGreen() >> 1 ) | 0x80,
670 ( rOld
.GetBlue() >> 1 ) | 0x80 );
673 aNewBmp
= Bitmap( GetSizePixel(), GetBitCount(), &aNewPal
);
674 BitmapScopedWriteAccess
pW(aNewBmp
);
678 pW
->CopyBuffer( *pR
);
684 aNewBmp
= Bitmap( GetSizePixel(), 24 );
686 BitmapScopedWriteAccess
pW(aNewBmp
);
690 const long nWidth
= pR
->Width(), nHeight
= pR
->Height();
692 for( long nY
= 0; nY
< nHeight
; nY
++ )
694 Scanline pScanline
= pW
->GetScanline(nY
);
695 Scanline pScanlineRead
= pR
->GetScanline(nY
);
696 for( long nX
= 0; nX
< nWidth
; nX
++ )
698 const BitmapColor
aOld( pR
->GetPixelFromData( pScanlineRead
, nX
) );
699 pW
->SetPixelOnData( pScanline
, nX
, BitmapColor( ( aOld
.GetRed() >> 1 ) | 0x80,
700 ( aOld
.GetGreen() >> 1 ) | 0x80,
701 ( aOld
.GetBlue() >> 1 ) | 0x80 ) );
715 const MapMode
aMap( maPrefMapMode
);
716 const Size
aSize( maPrefSize
);
720 maPrefMapMode
= aMap
;
727 bool Bitmap::Scale( const double& rScaleX
, const double& rScaleY
, BmpScaleFlag nScaleFlag
)
729 if(basegfx::fTools::equalZero(rScaleX
) || basegfx::fTools::equalZero(rScaleY
))
735 if(basegfx::fTools::equal(rScaleX
, 1.0) && basegfx::fTools::equal(rScaleY
, 1.0))
741 const sal_uInt16
nStartCount(GetBitCount());
743 if (mxSalBmp
&& mxSalBmp
->ScalingSupported())
745 // implementation specific scaling
746 std::shared_ptr
<SalBitmap
> xImpBmp(ImplGetSVData()->mpDefInst
->CreateSalBitmap());
747 if (xImpBmp
->Create(*mxSalBmp
) && xImpBmp
->Scale(rScaleX
, rScaleY
, nScaleFlag
))
749 ImplSetSalBitmap(xImpBmp
);
750 SAL_INFO( "vcl.opengl", "Ref count: " << mxSalBmp
.use_count() );
751 maPrefMapMode
= MapMode( MapUnit::MapPixel
);
752 maPrefSize
= xImpBmp
->GetSize();
759 // If we start with a 1 bit image, then after scaling it in any mode except
760 // BmpScaleFlag::Fast we have a 24bit image which is perfectly correct, but we
761 // are going to down-shift it to mono again and Bitmap::MakeMonochrome just
762 // has "Bitmap aNewBmp( GetSizePixel(), 1 );" to create a 1 bit bitmap which
763 // will default to black/white and the colors mapped to which ever is closer
766 // So the easiest thing to do to retain the colors of 1 bit bitmaps is to
767 // just use the fast scale rather than attempting to count unique colors in
768 // the other converters and pass all the info down through
769 // Bitmap::MakeMonochrome
770 if (nStartCount
== 1)
771 nScaleFlag
= BmpScaleFlag::Fast
;
773 BitmapEx
aBmpEx(*this);
778 case BmpScaleFlag::Default
:
779 if (GetSizePixel().Width() < 2 || GetSizePixel().Height() < 2)
780 bRetval
= BitmapFilter::Filter(aBmpEx
, BitmapFastScaleFilter(rScaleX
, rScaleY
));
782 bRetval
= BitmapFilter::Filter(aBmpEx
, BitmapScaleSuperFilter(rScaleX
, rScaleY
));
785 case BmpScaleFlag::Fast
:
786 case BmpScaleFlag::NearestNeighbor
:
787 bRetval
= BitmapFilter::Filter(aBmpEx
, BitmapFastScaleFilter(rScaleX
, rScaleY
));
790 case BmpScaleFlag::Interpolate
:
791 bRetval
= BitmapFilter::Filter(aBmpEx
, BitmapInterpolateScaleFilter(rScaleX
, rScaleY
));
794 case BmpScaleFlag::Super
:
795 bRetval
= BitmapFilter::Filter(aBmpEx
, BitmapScaleSuperFilter(rScaleX
, rScaleY
));
797 case BmpScaleFlag::BestQuality
:
798 case BmpScaleFlag::Lanczos
:
799 bRetval
= BitmapFilter::Filter(aBmpEx
, vcl::BitmapScaleLanczos3Filter(rScaleX
, rScaleY
));
802 case BmpScaleFlag::BiCubic
:
803 bRetval
= BitmapFilter::Filter(aBmpEx
, vcl::BitmapScaleBicubicFilter(rScaleX
, rScaleY
));
806 case BmpScaleFlag::BiLinear
:
807 bRetval
= BitmapFilter::Filter(aBmpEx
, vcl::BitmapScaleBilinearFilter(rScaleX
, rScaleY
));
812 *this = aBmpEx
.GetBitmapRef();
814 OSL_ENSURE(!bRetval
|| nStartCount
== GetBitCount(), "Bitmap::Scale has changed the ColorDepth, this should *not* happen (!)");
818 bool Bitmap::Scale( const Size
& rNewSize
, BmpScaleFlag nScaleFlag
)
820 const Size
aSize( GetSizePixel() );
823 if( aSize
.Width() && aSize
.Height() )
825 bRet
= Scale( static_cast<double>(rNewSize
.Width()) / aSize
.Width(),
826 static_cast<double>(rNewSize
.Height()) / aSize
.Height(),
835 bool Bitmap::HasFastScale()
837 #if HAVE_FEATURE_OPENGL
838 return OpenGLHelper::isVCLOpenGLEnabled();
844 void Bitmap::AdaptBitCount(Bitmap
& rNew
) const
846 // aNew is the result of some operation; adapt it's BitCount to the original (this)
847 if(GetBitCount() != rNew
.GetBitCount())
849 switch(GetBitCount())
853 rNew
.Convert(BmpConversion::N1BitThreshold
);
860 rNew
.Convert(BmpConversion::N4BitGreys
);
864 rNew
.Convert(BmpConversion::N4BitColors
);
872 rNew
.Convert(BmpConversion::N8BitGreys
);
876 rNew
.Convert(BmpConversion::N8BitColors
);
882 rNew
.Convert(BmpConversion::N24Bit
);
887 OSL_ENSURE(false, "BitDepth adaptation failed (!)");
894 bool Bitmap::Dither()
896 const Size
aSize( GetSizePixel() );
898 if( aSize
.Width() == 1 || aSize
.Height() == 1 )
903 if( ( aSize
.Width() > 3 ) && ( aSize
.Height() > 2 ) )
905 ScopedReadAccess
pReadAcc(*this);
906 Bitmap
aNewBmp( GetSizePixel(), 8 );
907 BitmapScopedWriteAccess
pWriteAcc(aNewBmp
);
909 if( pReadAcc
&& pWriteAcc
)
912 long nWidth
= pReadAcc
->Width();
913 long nWidth1
= nWidth
- 1;
914 long nHeight
= pReadAcc
->Height();
916 long nW
= nWidth
* 3;
918 long nRErr
, nGErr
, nBErr
;
920 std::unique_ptr
<long[]> p1(new long[ nW
]);
921 std::unique_ptr
<long[]> p2(new long[ nW
]);
922 long* p1T
= p1
.get();
923 long* p2T
= p2
.get();
925 bool bPal
= pReadAcc
->HasPalette();
931 Scanline pScanlineRead
= pReadAcc
->GetScanline(0);
932 for( long nZ
= 0; nZ
< nWidth
; nZ
++ )
934 aColor
= pReadAcc
->GetPaletteColor( pReadAcc
->GetIndexFromData( pScanlineRead
, nZ
) );
936 *pTmp
++ = static_cast<long>(aColor
.GetBlue()) << 12;
937 *pTmp
++ = static_cast<long>(aColor
.GetGreen()) << 12;
938 *pTmp
++ = static_cast<long>(aColor
.GetRed()) << 12;
943 Scanline pScanlineRead
= pReadAcc
->GetScanline(0);
944 for( long nZ
= 0; nZ
< nWidth
; nZ
++ )
946 aColor
= pReadAcc
->GetPixelFromData( pScanlineRead
, nZ
);
948 *pTmp
++ = static_cast<long>(aColor
.GetBlue()) << 12;
949 *pTmp
++ = static_cast<long>(aColor
.GetGreen()) << 12;
950 *pTmp
++ = static_cast<long>(aColor
.GetRed()) << 12;
954 for( long nY
= 1, nYAcc
= 0; nY
<= nHeight
; nY
++, nYAcc
++ )
964 Scanline pScanlineRead
= pReadAcc
->GetScanline(nY
);
965 for( long nZ
= 0; nZ
< nWidth
; nZ
++ )
967 aColor
= pReadAcc
->GetPaletteColor( pReadAcc
->GetIndexFromData( pScanlineRead
, nZ
) );
969 *pTmp
++ = static_cast<long>(aColor
.GetBlue()) << 12;
970 *pTmp
++ = static_cast<long>(aColor
.GetGreen()) << 12;
971 *pTmp
++ = static_cast<long>(aColor
.GetRed()) << 12;
976 Scanline pScanlineRead
= pReadAcc
->GetScanline(nY
);
977 for( long nZ
= 0; nZ
< nWidth
; nZ
++ )
979 aColor
= pReadAcc
->GetPixelFromData( pScanlineRead
, nZ
);
981 *pTmp
++ = static_cast<long>(aColor
.GetBlue()) << 12;
982 *pTmp
++ = static_cast<long>(aColor
.GetGreen()) << 12;
983 *pTmp
++ = static_cast<long>(aColor
.GetRed()) << 12;
988 // Examine first Pixel separately
995 Scanline pScanline
= pWriteAcc
->GetScanline(nYAcc
);
996 pWriteAcc
->SetPixelOnData( pScanline
, 0, BitmapColor(static_cast<sal_uInt8
>(nVCLBLut
[ nBC
] + nVCLGLut
[nGC
] + nVCLRLut
[nRC
])) );
998 // Get middle Pixels using a loop
1000 for ( nX
= 3, nXAcc
= 1; nX
< nW2
; nXAcc
++ )
1007 pWriteAcc
->SetPixelOnData( pScanline
, nXAcc
, BitmapColor(static_cast<sal_uInt8
>(nVCLBLut
[ nBC
] + nVCLGLut
[nGC
] + nVCLRLut
[nRC
])) );
1010 // Treat last Pixel separately
1015 pWriteAcc
->SetPixelOnData( pScanline
, nWidth1
, BitmapColor(static_cast<sal_uInt8
>(nVCLBLut
[ nBC
] + nVCLGLut
[nGC
] + nVCLRLut
[nRC
])) );
1026 const MapMode
aMap( maPrefMapMode
);
1027 const Size
aPrefSize( maPrefSize
);
1031 maPrefMapMode
= aMap
;
1032 maPrefSize
= aPrefSize
;
1039 void Bitmap::Vectorize( GDIMetaFile
& rMtf
, sal_uInt8 cReduce
, const Link
<long,void>* pProgress
)
1041 ImplVectorizer::ImplVectorize( *this, rMtf
, cReduce
, pProgress
);
1044 bool Bitmap::Adjust( short nLuminancePercent
, short nContrastPercent
,
1045 short nChannelRPercent
, short nChannelGPercent
, short nChannelBPercent
,
1046 double fGamma
, bool bInvert
, bool msoBrightness
)
1050 // nothing to do => return quickly
1051 if( !nLuminancePercent
&& !nContrastPercent
&&
1052 !nChannelRPercent
&& !nChannelGPercent
&& !nChannelBPercent
&&
1053 ( fGamma
== 1.0 ) && !bInvert
)
1059 BitmapScopedWriteAccess
pAcc(*this);
1064 const long nW
= pAcc
->Width();
1065 const long nH
= pAcc
->Height();
1066 std::unique_ptr
<sal_uInt8
[]> cMapR(new sal_uInt8
[ 256 ]);
1067 std::unique_ptr
<sal_uInt8
[]> cMapG(new sal_uInt8
[ 256 ]);
1068 std::unique_ptr
<sal_uInt8
[]> cMapB(new sal_uInt8
[ 256 ]);
1069 double fM
, fROff
, fGOff
, fBOff
, fOff
;
1072 if( nContrastPercent
>= 0 )
1073 fM
= 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent
, 0, 100 ) );
1075 fM
= ( 128.0 + 1.27 * MinMax( nContrastPercent
, -100, 0 ) ) / 128.0;
1078 // total offset = luminance offset + contrast offset
1079 fOff
= MinMax( nLuminancePercent
, -100, 100 ) * 2.55 + 128.0 - fM
* 128.0;
1081 fOff
= MinMax( nLuminancePercent
, -100, 100 ) * 2.55;
1083 // channel offset = channel offset + total offset
1084 fROff
= nChannelRPercent
* 2.55 + fOff
;
1085 fGOff
= nChannelGPercent
* 2.55 + fOff
;
1086 fBOff
= nChannelBPercent
* 2.55 + fOff
;
1088 // calculate gamma value
1089 fGamma
= ( fGamma
<= 0.0 || fGamma
> 10.0 ) ? 1.0 : ( 1.0 / fGamma
);
1090 const bool bGamma
= ( fGamma
!= 1.0 );
1092 // create mapping table
1093 for( long nX
= 0; nX
< 256; nX
++ )
1097 cMapR
[ nX
] = static_cast<sal_uInt8
>(MinMax( FRound( nX
* fM
+ fROff
), 0, 255 ));
1098 cMapG
[ nX
] = static_cast<sal_uInt8
>(MinMax( FRound( nX
* fM
+ fGOff
), 0, 255 ));
1099 cMapB
[ nX
] = static_cast<sal_uInt8
>(MinMax( FRound( nX
* fM
+ fBOff
), 0, 255 ));
1103 // LO simply uses (in a somewhat optimized form) "newcolor = (oldcolor-128)*contrast+brightness+128"
1104 // as the formula, i.e. contrast first, brightness afterwards. MSOffice, for whatever weird reason,
1105 // use neither first, but apparently it applies half of brightness before contrast and half afterwards.
1106 cMapR
[ nX
] = static_cast<sal_uInt8
>(MinMax( FRound( (nX
+fROff
/2-128) * fM
+ 128 + fROff
/2 ), 0, 255 ));
1107 cMapG
[ nX
] = static_cast<sal_uInt8
>(MinMax( FRound( (nX
+fGOff
/2-128) * fM
+ 128 + fGOff
/2 ), 0, 255 ));
1108 cMapB
[ nX
] = static_cast<sal_uInt8
>(MinMax( FRound( (nX
+fBOff
/2-128) * fM
+ 128 + fBOff
/2 ), 0, 255 ));
1112 cMapR
[ nX
] = GAMMA( cMapR
[ nX
], fGamma
);
1113 cMapG
[ nX
] = GAMMA( cMapG
[ nX
], fGamma
);
1114 cMapB
[ nX
] = GAMMA( cMapB
[ nX
], fGamma
);
1119 cMapR
[ nX
] = ~cMapR
[ nX
];
1120 cMapG
[ nX
] = ~cMapG
[ nX
];
1121 cMapB
[ nX
] = ~cMapB
[ nX
];
1126 if( pAcc
->HasPalette() )
1128 BitmapColor aNewCol
;
1130 for( sal_uInt16 i
= 0, nCount
= pAcc
->GetPaletteEntryCount(); i
< nCount
; i
++ )
1132 const BitmapColor
& rCol
= pAcc
->GetPaletteColor( i
);
1133 aNewCol
.SetRed( cMapR
[ rCol
.GetRed() ] );
1134 aNewCol
.SetGreen( cMapG
[ rCol
.GetGreen() ] );
1135 aNewCol
.SetBlue( cMapB
[ rCol
.GetBlue() ] );
1136 pAcc
->SetPaletteColor( i
, aNewCol
);
1139 else if( pAcc
->GetScanlineFormat() == ScanlineFormat::N24BitTcBgr
)
1141 for( long nY
= 0; nY
< nH
; nY
++ )
1143 Scanline pScan
= pAcc
->GetScanline( nY
);
1145 for( long nX
= 0; nX
< nW
; nX
++ )
1147 *pScan
= cMapB
[ *pScan
]; pScan
++;
1148 *pScan
= cMapG
[ *pScan
]; pScan
++;
1149 *pScan
= cMapR
[ *pScan
]; pScan
++;
1153 else if( pAcc
->GetScanlineFormat() == ScanlineFormat::N24BitTcRgb
)
1155 for( long nY
= 0; nY
< nH
; nY
++ )
1157 Scanline pScan
= pAcc
->GetScanline( nY
);
1159 for( long nX
= 0; nX
< nW
; nX
++ )
1161 *pScan
= cMapR
[ *pScan
]; pScan
++;
1162 *pScan
= cMapG
[ *pScan
]; pScan
++;
1163 *pScan
= cMapB
[ *pScan
]; pScan
++;
1169 for( long nY
= 0; nY
< nH
; nY
++ )
1171 Scanline pScanline
= pAcc
->GetScanline(nY
);
1172 for( long nX
= 0; nX
< nW
; nX
++ )
1174 aCol
= pAcc
->GetPixelFromData( pScanline
, nX
);
1175 aCol
.SetRed( cMapR
[ aCol
.GetRed() ] );
1176 aCol
.SetGreen( cMapG
[ aCol
.GetGreen() ] );
1177 aCol
.SetBlue( cMapB
[ aCol
.GetBlue() ] );
1178 pAcc
->SetPixelOnData( pScanline
, nX
, aCol
);
1191 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */