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 .
20 #include "BitmapScaleConvolution.hxx"
21 #include "ResampleKernel.hxx"
23 #include <vcl/bitmapaccess.hxx>
24 #include <osl/diagnose.h>
35 void ImplCalculateContributions(
36 const long aSourceSize
,
37 const long aDestinationSize
,
38 long& aNumberOfContributions
,
42 const Kernel
& aKernel
)
44 const double fSamplingRadius(aKernel
.GetWidth());
45 const double fScale(aDestinationSize
/ static_cast< double >(aSourceSize
));
46 const double fScaledRadius((fScale
< 1.0) ? fSamplingRadius
/ fScale
: fSamplingRadius
);
47 const double fFilterFactor((fScale
< 1.0) ? fScale
: 1.0);
49 aNumberOfContributions
= (long(fabs(ceil(fScaledRadius
))) * 2) + 1;
50 const long nAllocSize(aDestinationSize
* aNumberOfContributions
);
51 pWeights
= new double[nAllocSize
];
52 pPixels
= new long[nAllocSize
];
53 pCount
= new long[aDestinationSize
];
55 for(long i(0); i
< aDestinationSize
; i
++)
57 const long aIndex(i
* aNumberOfContributions
);
58 const double aCenter(i
/ fScale
);
59 const sal_Int32
aLeft(static_cast< sal_Int32
>(floor(aCenter
- fScaledRadius
)));
60 const sal_Int32
aRight(static_cast< sal_Int32
>(ceil(aCenter
+ fScaledRadius
)));
61 long aCurrentCount(0);
63 for(sal_Int32
j(aLeft
); j
<= aRight
; j
++)
65 const double aWeight(aKernel
.Calculate(fFilterFactor
* (aCenter
- static_cast< double>(j
))));
67 // Reduce calculations with ignoring weights of 0.0
68 if(fabs(aWeight
) < 0.0001)
74 const long aPixelIndex(MinMax(j
, 0, aSourceSize
- 1));
75 const long nIndex(aIndex
+ aCurrentCount
);
77 pWeights
[nIndex
] = aWeight
;
78 pPixels
[nIndex
] = aPixelIndex
;
83 pCount
[i
] = aCurrentCount
;
87 bool ImplScaleConvolutionHor(Bitmap
& rSource
, Bitmap
& rTarget
, const double& rScaleX
, const Kernel
& aKernel
)
89 // Do horizontal filtering
90 OSL_ENSURE(rScaleX
> 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
91 const long nWidth(rSource
.GetSizePixel().Width());
92 const long nNewWidth(FRound(nWidth
* rScaleX
));
94 if(nWidth
== nNewWidth
)
99 Bitmap::ScopedReadAccess
pReadAcc(rSource
);
103 double* pWeights
= nullptr;
104 long* pPixels
= nullptr;
105 long* pCount
= nullptr;
106 long aNumberOfContributions(0);
108 const long nHeight(rSource
.GetSizePixel().Height());
109 ImplCalculateContributions(nWidth
, nNewWidth
, aNumberOfContributions
, pWeights
, pPixels
, pCount
, aKernel
);
110 rTarget
= Bitmap(Size(nNewWidth
, nHeight
), 24);
111 Bitmap::ScopedWriteAccess
pWriteAcc(rTarget
);
112 bool bResult(nullptr != pWriteAcc
);
116 for(long y(0); y
< nHeight
; y
++)
118 for(long x(0); x
< nNewWidth
; x
++)
120 const long aBaseIndex(x
* aNumberOfContributions
);
122 double aValueRed(0.0);
123 double aValueGreen(0.0);
124 double aValueBlue(0.0);
126 for(long j(0); j
< pCount
[x
]; j
++)
128 const long aIndex(aBaseIndex
+ j
);
129 const double aWeight(pWeights
[aIndex
]);
134 if(pReadAcc
->HasPalette())
136 aColor
= pReadAcc
->GetPaletteColor(pReadAcc
->GetPixelIndex(y
, pPixels
[aIndex
]));
140 aColor
= pReadAcc
->GetPixel(y
, pPixels
[aIndex
]);
143 aValueRed
+= aWeight
* aColor
.GetRed();
144 aValueGreen
+= aWeight
* aColor
.GetGreen();
145 aValueBlue
+= aWeight
* aColor
.GetBlue();
148 const BitmapColor
aResultColor(
149 static_cast< sal_uInt8
>(MinMax(static_cast< sal_Int32
>(aValueRed
/ aSum
), 0, 255)),
150 static_cast< sal_uInt8
>(MinMax(static_cast< sal_Int32
>(aValueGreen
/ aSum
), 0, 255)),
151 static_cast< sal_uInt8
>(MinMax(static_cast< sal_Int32
>(aValueBlue
/ aSum
), 0, 255)));
153 pWriteAcc
->SetPixel(y
, x
, aResultColor
);
173 bool ImplScaleConvolutionVer(Bitmap
& rSource
, Bitmap
& rTarget
, const double& rScaleY
, const Kernel
& aKernel
)
175 // Do vertical filtering
176 OSL_ENSURE(rScaleY
> 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
177 const long nHeight(rSource
.GetSizePixel().Height());
178 const long nNewHeight(FRound(nHeight
* rScaleY
));
180 if(nHeight
== nNewHeight
)
185 Bitmap::ScopedReadAccess
pReadAcc(rSource
);
189 double* pWeights
= nullptr;
190 long* pPixels
= nullptr;
191 long* pCount
= nullptr;
192 long aNumberOfContributions(0);
194 const long nWidth(rSource
.GetSizePixel().Width());
195 ImplCalculateContributions(nHeight
, nNewHeight
, aNumberOfContributions
, pWeights
, pPixels
, pCount
, aKernel
);
196 rTarget
= Bitmap(Size(nWidth
, nNewHeight
), 24);
197 Bitmap::ScopedWriteAccess
pWriteAcc(rTarget
);
198 bool bResult(nullptr != pWriteAcc
);
202 for(long x(0); x
< nWidth
; x
++)
204 for(long y(0); y
< nNewHeight
; y
++)
206 const long aBaseIndex(y
* aNumberOfContributions
);
208 double aValueRed(0.0);
209 double aValueGreen(0.0);
210 double aValueBlue(0.0);
212 for(long j(0); j
< pCount
[y
]; j
++)
214 const long aIndex(aBaseIndex
+ j
);
215 const double aWeight(pWeights
[aIndex
]);
220 if(pReadAcc
->HasPalette())
222 aColor
= pReadAcc
->GetPaletteColor(pReadAcc
->GetPixelIndex(pPixels
[aIndex
], x
));
226 aColor
= pReadAcc
->GetPixel(pPixels
[aIndex
], x
);
229 aValueRed
+= aWeight
* aColor
.GetRed();
230 aValueGreen
+= aWeight
* aColor
.GetGreen();
231 aValueBlue
+= aWeight
* aColor
.GetBlue();
234 const BitmapColor
aResultColor(
235 static_cast< sal_uInt8
>(MinMax(static_cast< sal_Int32
>(aValueRed
/ aSum
), 0, 255)),
236 static_cast< sal_uInt8
>(MinMax(static_cast< sal_Int32
>(aValueGreen
/ aSum
), 0, 255)),
237 static_cast< sal_uInt8
>(MinMax(static_cast< sal_Int32
>(aValueBlue
/ aSum
), 0, 255)));
239 if(pWriteAcc
->HasPalette())
241 pWriteAcc
->SetPixelIndex(y
, x
, static_cast< sal_uInt8
>(pWriteAcc
->GetBestPaletteIndex(aResultColor
)));
245 pWriteAcc
->SetPixel(y
, x
, aResultColor
);
264 bool ImplScaleConvolution(Bitmap
& rBitmap
, const double& rScaleX
, const double& rScaleY
, const Kernel
& aKernel
)
266 const bool bMirrorHor(rScaleX
< 0.0);
267 const bool bMirrorVer(rScaleY
< 0.0);
268 const double fScaleX(bMirrorHor
? -rScaleX
: rScaleX
);
269 const double fScaleY(bMirrorVer
? -rScaleY
: rScaleY
);
270 const long nWidth(rBitmap
.GetSizePixel().Width());
271 const long nHeight(rBitmap
.GetSizePixel().Height());
272 const long nNewWidth(FRound(nWidth
* fScaleX
));
273 const long nNewHeight(FRound(nHeight
* fScaleY
));
274 const bool bScaleHor(nWidth
!= nNewWidth
);
275 const bool bScaleVer(nHeight
!= nNewHeight
);
276 const bool bMirror(bMirrorHor
|| bMirrorVer
);
278 if (!bMirror
&& !bScaleHor
&& !bScaleVer
)
284 BmpMirrorFlags
nMirrorFlags(BmpMirrorFlags::NONE
);
285 bool bMirrorAfter(false);
291 nMirrorFlags
|= BmpMirrorFlags::Horizontal
;
296 nMirrorFlags
|= BmpMirrorFlags::Vertical
;
299 const long nStartSize(nWidth
* nHeight
);
300 const long nEndSize(nNewWidth
* nNewHeight
);
302 bMirrorAfter
= nStartSize
> nEndSize
;
306 bResult
= rBitmap
.Mirror(nMirrorFlags
);
314 const long nInBetweenSizeHorFirst(nHeight
* nNewWidth
);
315 const long nInBetweenSizeVerFirst(nNewHeight
* nWidth
);
316 Bitmap
aSource(rBitmap
);
318 if(nInBetweenSizeHorFirst
< nInBetweenSizeVerFirst
)
322 bResult
= ImplScaleConvolutionHor(aSource
, aResult
, fScaleX
, aKernel
);
325 if(bResult
&& bScaleVer
)
329 // copy partial result, independent of color depth
333 bResult
= ImplScaleConvolutionVer(aSource
, aResult
, fScaleY
, aKernel
);
340 bResult
= ImplScaleConvolutionVer(aSource
, aResult
, fScaleY
, aKernel
);
343 if(bResult
&& bScaleHor
)
347 // copy partial result, independent of color depth
351 bResult
= ImplScaleConvolutionHor(aSource
, aResult
, fScaleX
, aKernel
);
356 if(bResult
&& bMirrorAfter
)
358 bResult
= aResult
.Mirror(nMirrorFlags
);
363 rBitmap
.ImplAdaptBitCount(aResult
);
370 } // end anonymous namespace
372 bool BitmapScaleConvolution::filter(Bitmap
& rBitmap
)
377 case ConvolutionKernelType::Box
:
378 return ImplScaleConvolution(rBitmap
, mrScaleX
, mrScaleY
, BoxKernel());
379 case ConvolutionKernelType::BiLinear
:
380 return ImplScaleConvolution(rBitmap
, mrScaleX
, mrScaleY
, BilinearKernel());
381 case ConvolutionKernelType::BiCubic
:
382 return ImplScaleConvolution(rBitmap
, mrScaleX
, mrScaleY
, BicubicKernel());
383 case ConvolutionKernelType::Lanczos3
:
384 return ImplScaleConvolution(rBitmap
, mrScaleX
, mrScaleY
, Lanczos3Kernel());
393 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */