Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * This file is part of the LibreOffice project.
4 : : *
5 : : * This Source Code Form is subject to the terms of the Mozilla Public
6 : : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : : *
9 : : * This file incorporates work covered by the following license notice:
10 : : *
11 : : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : : * contributor license agreements. See the NOTICE file distributed
13 : : * with this work for additional information regarding copyright
14 : : * ownership. The ASF licenses this file to you under the Apache
15 : : * License, Version 2.0 (the "License"); you may not use this file
16 : : * except in compliance with the License. You may obtain a copy of
17 : : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : : */
19 : :
20 : : #include <vclhelperbitmaptransform.hxx>
21 : : #include <vcl/bmpacc.hxx>
22 : : #include <basegfx/point/b2dpoint.hxx>
23 : : #include <basegfx/color/bcolormodifier.hxx>
24 : :
25 : : //////////////////////////////////////////////////////////////////////////////
26 : : // support for rendering Bitmap and BitmapEx contents
27 : :
28 : : namespace drawinglayer
29 : : {
30 : : namespace
31 : : {
32 : 0 : void impSmoothPoint(BitmapColor& rValue, const basegfx::B2DPoint& rSource, sal_Int32 nIntX, sal_Int32 nIntY, BitmapReadAccess& rRead)
33 : : {
34 : 0 : double fDeltaX(rSource.getX() - nIntX);
35 : 0 : double fDeltaY(rSource.getY() - nIntY);
36 : 0 : sal_Int32 nIndX(0L);
37 : 0 : sal_Int32 nIndY(0L);
38 : :
39 [ # # ][ # # ]: 0 : if(fDeltaX > 0.0 && nIntX + 1L < rRead.Width())
[ # # ]
40 : : {
41 : 0 : nIndX++;
42 : : }
43 [ # # ][ # # ]: 0 : else if(fDeltaX < 0.0 && nIntX >= 1L)
44 : : {
45 : 0 : fDeltaX = -fDeltaX;
46 : 0 : nIndX--;
47 : : }
48 : :
49 [ # # ][ # # ]: 0 : if(fDeltaY > 0.0 && nIntY + 1L < rRead.Height())
[ # # ]
50 : : {
51 : 0 : nIndY++;
52 : : }
53 [ # # ][ # # ]: 0 : else if(fDeltaY < 0.0 && nIntY >= 1L)
54 : : {
55 : 0 : fDeltaY = -fDeltaY;
56 : 0 : nIndY--;
57 : : }
58 : :
59 [ # # ][ # # ]: 0 : if(nIndX || nIndY)
60 : : {
61 : 0 : const double fColorToReal(1.0 / 255.0);
62 : 0 : double fR(rValue.GetRed() * fColorToReal);
63 : 0 : double fG(rValue.GetGreen() * fColorToReal);
64 : 0 : double fB(rValue.GetBlue() * fColorToReal);
65 : 0 : double fRBottom(0.0), fGBottom(0.0), fBBottom(0.0);
66 : :
67 [ # # ]: 0 : if(nIndX)
68 : : {
69 : 0 : const double fMulA(fDeltaX * fColorToReal);
70 : 0 : double fMulB(1.0 - fDeltaX);
71 [ # # ]: 0 : const BitmapColor aTopPartner(rRead.GetColor(nIntY, nIntX + nIndX));
72 : :
73 : 0 : fR = (fR * fMulB) + (aTopPartner.GetRed() * fMulA);
74 : 0 : fG = (fG * fMulB) + (aTopPartner.GetGreen() * fMulA);
75 : 0 : fB = (fB * fMulB) + (aTopPartner.GetBlue() * fMulA);
76 : :
77 [ # # ]: 0 : if(nIndY)
78 : : {
79 : 0 : fMulB *= fColorToReal;
80 [ # # ]: 0 : const BitmapColor aBottom(rRead.GetColor(nIntY + nIndY, nIntX));
81 [ # # ]: 0 : const BitmapColor aBottomPartner(rRead.GetColor(nIntY + nIndY, nIntX + nIndX));
82 : :
83 : 0 : fRBottom = (aBottom.GetRed() * fMulB) + (aBottomPartner.GetRed() * fMulA);
84 : 0 : fGBottom = (aBottom.GetGreen() * fMulB) + (aBottomPartner.GetGreen() * fMulA);
85 : 0 : fBBottom = (aBottom.GetBlue() * fMulB) + (aBottomPartner.GetBlue() * fMulA);
86 : 0 : }
87 : : }
88 : :
89 [ # # ]: 0 : if(nIndY)
90 : : {
91 [ # # ]: 0 : if(!nIndX)
92 : : {
93 [ # # ]: 0 : const BitmapColor aBottom(rRead.GetColor(nIntY + nIndY, nIntX));
94 : :
95 : 0 : fRBottom = aBottom.GetRed() * fColorToReal;
96 : 0 : fGBottom = aBottom.GetGreen() * fColorToReal;
97 : 0 : fBBottom = aBottom.GetBlue() * fColorToReal;
98 : : }
99 : :
100 : 0 : const double fMulB(1.0 - fDeltaY);
101 : :
102 : 0 : fR = (fR * fMulB) + (fRBottom * fDeltaY);
103 : 0 : fG = (fG * fMulB) + (fGBottom * fDeltaY);
104 : 0 : fB = (fB * fMulB) + (fBBottom * fDeltaY);
105 : : }
106 : :
107 : 0 : rValue.SetRed((sal_uInt8)(fR * 255.0));
108 : 0 : rValue.SetGreen((sal_uInt8)(fG * 255.0));
109 : 0 : rValue.SetBlue((sal_uInt8)(fB * 255.0));
110 : : }
111 : 0 : }
112 : :
113 : 0 : void impSmoothIndex(BitmapColor& rValue, const basegfx::B2DPoint& rSource, sal_Int32 nIntX, sal_Int32 nIntY, BitmapReadAccess& rRead)
114 : : {
115 : 0 : double fDeltaX(rSource.getX() - nIntX);
116 : 0 : double fDeltaY(rSource.getY() - nIntY);
117 : 0 : sal_Int32 nIndX(0L);
118 : 0 : sal_Int32 nIndY(0L);
119 : :
120 [ # # ][ # # ]: 0 : if(fDeltaX > 0.0 && nIntX + 1L < rRead.Width())
[ # # ]
121 : : {
122 : 0 : nIndX++;
123 : : }
124 [ # # ][ # # ]: 0 : else if(fDeltaX < 0.0 && nIntX >= 1L)
125 : : {
126 : 0 : fDeltaX = -fDeltaX;
127 : 0 : nIndX--;
128 : : }
129 : :
130 [ # # ][ # # ]: 0 : if(fDeltaY > 0.0 && nIntY + 1L < rRead.Height())
[ # # ]
131 : : {
132 : 0 : nIndY++;
133 : : }
134 [ # # ][ # # ]: 0 : else if(fDeltaY < 0.0 && nIntY >= 1L)
135 : : {
136 : 0 : fDeltaY = -fDeltaY;
137 : 0 : nIndY--;
138 : : }
139 : :
140 [ # # ][ # # ]: 0 : if(nIndX || nIndY)
141 : : {
142 : 0 : const double fColorToReal(1.0 / 255.0);
143 : 0 : double fVal(rValue.GetIndex() * fColorToReal);
144 : 0 : double fValBottom(0.0);
145 : :
146 [ # # ]: 0 : if(nIndX)
147 : : {
148 : 0 : const double fMulA(fDeltaX * fColorToReal);
149 : 0 : double fMulB(1.0 - fDeltaX);
150 [ # # ]: 0 : const BitmapColor aTopPartner(rRead.GetPixel(nIntY, nIntX + nIndX));
151 : :
152 : 0 : fVal = (fVal * fMulB) + (aTopPartner.GetIndex() * fMulA);
153 : :
154 [ # # ]: 0 : if(nIndY)
155 : : {
156 : 0 : fMulB *= fColorToReal;
157 [ # # ]: 0 : const BitmapColor aBottom(rRead.GetPixel(nIntY + nIndY, nIntX));
158 [ # # ]: 0 : const BitmapColor aBottomPartner(rRead.GetPixel(nIntY + nIndY, nIntX + nIndX));
159 : :
160 : 0 : fValBottom = (aBottom.GetIndex() * fMulB) + (aBottomPartner.GetIndex() * fMulA);
161 : 0 : }
162 : : }
163 : :
164 [ # # ]: 0 : if(nIndY)
165 : : {
166 [ # # ]: 0 : if(!nIndX)
167 : : {
168 [ # # ]: 0 : const BitmapColor aBottom(rRead.GetPixel(nIntY + nIndY, nIntX));
169 : :
170 : 0 : fValBottom = aBottom.GetIndex() * fColorToReal;
171 : : }
172 : :
173 : 0 : const double fMulB(1.0 - fDeltaY);
174 : :
175 : 0 : fVal = (fVal * fMulB) + (fValBottom * fDeltaY);
176 : : }
177 : :
178 : 0 : rValue.SetIndex((sal_uInt8)(fVal * 255.0));
179 : : }
180 : 0 : }
181 : :
182 : 0 : void impTransformBitmap(const Bitmap& rSource, Bitmap& rDestination, const basegfx::B2DHomMatrix& rTransform, bool bSmooth)
183 : : {
184 : 0 : BitmapWriteAccess* pWrite = rDestination.AcquireWriteAccess();
185 : :
186 [ # # ]: 0 : if(pWrite)
187 : : {
188 [ # # ]: 0 : const Size aContentSizePixel(rSource.GetSizePixel());
189 [ # # ]: 0 : BitmapReadAccess* pRead = (const_cast< Bitmap& >(rSource)).AcquireReadAccess();
190 : :
191 [ # # ]: 0 : if(pRead)
192 : : {
193 [ # # ]: 0 : const Size aDestinationSizePixel(rDestination.GetSizePixel());
194 [ # # ]: 0 : bool bWorkWithIndex(rDestination.GetBitCount() <= 8);
195 [ # # ]: 0 : BitmapColor aOutside(pRead->GetBestMatchingColor(BitmapColor(0xff, 0xff, 0xff)));
196 : :
197 [ # # ]: 0 : for(sal_Int32 y(0L); y < aDestinationSizePixel.getHeight(); y++)
198 : : {
199 [ # # ]: 0 : for(sal_Int32 x(0L); x < aDestinationSizePixel.getWidth(); x++)
200 : : {
201 [ # # ]: 0 : const basegfx::B2DPoint aSourceCoor(rTransform * basegfx::B2DPoint(x, y));
202 : 0 : const sal_Int32 nIntX(basegfx::fround(aSourceCoor.getX()));
203 : :
204 [ # # ][ # # ]: 0 : if(nIntX >= 0L && nIntX < aContentSizePixel.getWidth())
[ # # ]
205 : : {
206 : 0 : const sal_Int32 nIntY(basegfx::fround(aSourceCoor.getY()));
207 : :
208 [ # # ][ # # ]: 0 : if(nIntY >= 0L && nIntY < aContentSizePixel.getHeight())
[ # # ]
209 : : {
210 [ # # ]: 0 : if(bWorkWithIndex)
211 : : {
212 [ # # ]: 0 : BitmapColor aValue(pRead->GetPixel(nIntY, nIntX));
213 : :
214 [ # # ]: 0 : if(bSmooth)
215 : : {
216 [ # # ]: 0 : impSmoothIndex(aValue, aSourceCoor, nIntX, nIntY, *pRead);
217 : : }
218 : :
219 [ # # ]: 0 : pWrite->SetPixel(y, x, aValue);
220 : : }
221 : : else
222 : : {
223 [ # # ]: 0 : BitmapColor aValue(pRead->GetColor(nIntY, nIntX));
224 : :
225 [ # # ]: 0 : if(bSmooth)
226 : : {
227 [ # # ]: 0 : impSmoothPoint(aValue, aSourceCoor, nIntX, nIntY, *pRead);
228 : : }
229 : :
230 [ # # ][ # # ]: 0 : pWrite->SetPixel(y, x, aValue.IsIndex() ? aValue : pWrite->GetBestMatchingColor(aValue));
[ # # ]
231 : : }
232 : :
233 : 0 : continue;
234 : : }
235 : : }
236 : :
237 : : // here are outside pixels. Complete mask
238 [ # # ]: 0 : if(bWorkWithIndex)
239 : : {
240 [ # # ]: 0 : pWrite->SetPixel(y, x, aOutside);
241 : : }
242 [ # # ]: 0 : }
243 : : }
244 : :
245 [ # # ][ # # ]: 0 : delete pRead;
246 : : }
247 : :
248 [ # # ][ # # ]: 0 : delete pWrite;
249 : : }
250 : 0 : }
251 : :
252 : 0 : Bitmap impCreateEmptyBitmapWithPattern(const Bitmap& rSource, const Size& aTargetSizePixel)
253 : : {
254 : 0 : Bitmap aRetval;
255 [ # # ]: 0 : BitmapReadAccess* pReadAccess = (const_cast< Bitmap& >(rSource)).AcquireReadAccess();
256 : :
257 [ # # ]: 0 : if(pReadAccess)
258 : : {
259 [ # # ][ # # ]: 0 : if(rSource.GetBitCount() <= 8)
260 : : {
261 [ # # ]: 0 : BitmapPalette aPalette(pReadAccess->GetPalette());
262 [ # # ][ # # ]: 0 : aRetval = Bitmap(aTargetSizePixel, rSource.GetBitCount(), &aPalette);
[ # # ][ # # ]
263 : : }
264 : : else
265 : : {
266 [ # # ][ # # ]: 0 : aRetval = Bitmap(aTargetSizePixel, rSource.GetBitCount());
[ # # ][ # # ]
267 : : }
268 : :
269 [ # # ][ # # ]: 0 : delete pReadAccess;
270 : : }
271 : :
272 : 0 : return aRetval;
273 : : }
274 : : } // end of anonymous namespace
275 : : } // end of namespace drawinglayer
276 : :
277 : : namespace drawinglayer
278 : : {
279 : 0 : BitmapEx impTransformBitmapEx(
280 : : const BitmapEx& rSource,
281 : : const Rectangle& rCroppedRectPixel,
282 : : const basegfx::B2DHomMatrix& rTransform)
283 : : {
284 : : // force destination to 24 bit, we want to smooth output
285 [ # # ]: 0 : const Size aDestinationSize(rCroppedRectPixel.GetSize());
286 [ # # ][ # # ]: 0 : Bitmap aDestination(impCreateEmptyBitmapWithPattern(rSource.GetBitmap(), aDestinationSize));
[ # # ]
287 : : static bool bDoSmoothAtAll(true);
288 [ # # ][ # # ]: 0 : impTransformBitmap(rSource.GetBitmap(), aDestination, rTransform, bDoSmoothAtAll);
[ # # ]
289 : :
290 : : // create mask
291 [ # # ][ # # ]: 0 : if(rSource.IsTransparent())
292 : : {
293 [ # # ][ # # ]: 0 : if(rSource.IsAlpha())
294 : : {
295 [ # # ][ # # ]: 0 : Bitmap aAlpha(impCreateEmptyBitmapWithPattern(rSource.GetAlpha().GetBitmap(), aDestinationSize));
[ # # ][ # # ]
[ # # ]
296 [ # # ][ # # ]: 0 : impTransformBitmap(rSource.GetAlpha().GetBitmap(), aAlpha, rTransform, bDoSmoothAtAll);
[ # # ][ # # ]
[ # # ]
297 [ # # ][ # # ]: 0 : return BitmapEx(aDestination, AlphaMask(aAlpha));
[ # # ][ # # ]
298 : : }
299 : : else
300 : : {
301 [ # # ][ # # ]: 0 : Bitmap aMask(impCreateEmptyBitmapWithPattern(rSource.GetMask(), aDestinationSize));
[ # # ]
302 [ # # ][ # # ]: 0 : impTransformBitmap(rSource.GetMask(), aMask, rTransform, false);
[ # # ]
303 [ # # ][ # # ]: 0 : return BitmapEx(aDestination, aMask);
304 : : }
305 : : }
306 : :
307 [ # # ][ # # ]: 0 : return BitmapEx(aDestination);
308 : : }
309 : :
310 : 0 : BitmapEx impModifyBitmapEx(
311 : : const basegfx::BColorModifierStack& rBColorModifierStack,
312 : : const BitmapEx& rSource)
313 : : {
314 [ # # ]: 0 : Bitmap aChangedBitmap(rSource.GetBitmap());
315 : 0 : bool bDone(false);
316 : :
317 [ # # ][ # # ]: 0 : for(sal_uInt32 a(rBColorModifierStack.count()); a && !bDone; )
[ # # ]
318 : : {
319 [ # # ]: 0 : const basegfx::BColorModifier& rModifier = rBColorModifierStack.getBColorModifier(--a);
320 : :
321 [ # # ]: 0 : switch(rModifier.getMode())
322 : : {
323 : : case basegfx::BCOLORMODIFYMODE_REPLACE :
324 : : {
325 : : // complete replace
326 [ # # ][ # # ]: 0 : if(rSource.IsTransparent())
327 : : {
328 : : // clear bitmap with dest color
329 [ # # ][ # # ]: 0 : if(aChangedBitmap.GetBitCount() <= 8)
330 : : {
331 : : // do NOT use erase; for e.g. 8bit Bitmaps, the nearest color to the given
332 : : // erase color is determined and used -> this may be different from what is
333 : : // wanted here. Better create a new bitmap with the needed color explicitly
334 [ # # ]: 0 : BitmapReadAccess* pReadAccess = aChangedBitmap.AcquireReadAccess();
335 : : OSL_ENSURE(pReadAccess, "Got no Bitmap ReadAccess ?!?");
336 : :
337 [ # # ]: 0 : if(pReadAccess)
338 : : {
339 [ # # ]: 0 : BitmapPalette aNewPalette(pReadAccess->GetPalette());
340 : 0 : aNewPalette[0] = BitmapColor(Color(rModifier.getBColor()));
341 : : aChangedBitmap = Bitmap(
342 : : aChangedBitmap.GetSizePixel(),
343 [ # # ]: 0 : aChangedBitmap.GetBitCount(),
344 [ # # ][ # # ]: 0 : &aNewPalette);
[ # # ][ # # ]
345 [ # # ][ # # ]: 0 : delete pReadAccess;
346 : : }
347 : : }
348 : : else
349 : : {
350 [ # # ]: 0 : aChangedBitmap.Erase(Color(rModifier.getBColor()));
351 : : }
352 : : }
353 : : else
354 : : {
355 : : // erase bitmap, caller will know to paint direct
356 [ # # ]: 0 : aChangedBitmap.SetEmpty();
357 : : }
358 : :
359 : 0 : bDone = true;
360 : 0 : break;
361 : : }
362 : :
363 : : default : // BCOLORMODIFYMODE_INTERPOLATE, BCOLORMODIFYMODE_GRAY, BCOLORMODIFYMODE_BLACKANDWHITE
364 : : {
365 [ # # ]: 0 : BitmapWriteAccess* pContent = aChangedBitmap.AcquireWriteAccess();
366 : :
367 [ # # ]: 0 : if(pContent)
368 : : {
369 : 0 : const double fConvertColor(1.0 / 255.0);
370 : :
371 [ # # ]: 0 : for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++)
372 : : {
373 [ # # ]: 0 : for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++)
374 : : {
375 [ # # ]: 0 : const BitmapColor aBMCol(pContent->GetColor(y, x));
376 : : const basegfx::BColor aBSource(
377 : 0 : (double)aBMCol.GetRed() * fConvertColor,
378 : 0 : (double)aBMCol.GetGreen() * fConvertColor,
379 : 0 : (double)aBMCol.GetBlue() * fConvertColor);
380 [ # # ]: 0 : const basegfx::BColor aBDest(rModifier.getModifiedColor(aBSource));
381 : :
382 [ # # ]: 0 : pContent->SetPixel(y, x, BitmapColor(Color(aBDest)));
383 : 0 : }
384 : : }
385 : :
386 [ # # ][ # # ]: 0 : delete pContent;
387 : : }
388 : :
389 : 0 : break;
390 : : }
391 : : }
392 : : }
393 : :
394 [ # # ]: 0 : if(aChangedBitmap.IsEmpty())
395 : : {
396 [ # # ]: 0 : return BitmapEx();
397 : : }
398 : : else
399 : : {
400 [ # # ][ # # ]: 0 : if(rSource.IsTransparent())
401 : : {
402 [ # # ][ # # ]: 0 : if(rSource.IsAlpha())
403 : : {
404 [ # # ][ # # ]: 0 : return BitmapEx(aChangedBitmap, rSource.GetAlpha());
[ # # ]
405 : : }
406 : : else
407 : : {
408 [ # # ][ # # ]: 0 : return BitmapEx(aChangedBitmap, rSource.GetMask());
[ # # ]
409 : : }
410 : : }
411 : : else
412 : : {
413 [ # # ]: 0 : return BitmapEx(aChangedBitmap);
414 : : }
415 [ # # ]: 0 : }
416 : : }
417 : : } // end of namespace drawinglayer
418 : :
419 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|