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: */
|