27inline void qt_blurinner(uchar *bptr,
int &zR,
int &zG,
int &zB,
int &zA,
int alpha)
29 QRgb *pixel = (QRgb *)bptr;
31#define Z_MASK (0xff
<< zprec)
32 const int A_zprec = qt_static_shift<zprec - 24>(*pixel) &
Z_MASK;
33 const int R_zprec = qt_static_shift<zprec - 16>(*pixel) &
Z_MASK;
34 const int G_zprec = qt_static_shift<zprec - 8>(*pixel) &
Z_MASK;
35 const int B_zprec = qt_static_shift<zprec>(*pixel) &
Z_MASK;
38 const int zR_zprec = zR >> aprec;
39 const int zG_zprec = zG >> aprec;
40 const int zB_zprec = zB >> aprec;
41 const int zA_zprec = zA >> aprec;
43 zR += alpha * (R_zprec - zR_zprec);
44 zG += alpha * (G_zprec - zG_zprec);
45 zB += alpha * (B_zprec - zB_zprec);
46 zA += alpha * (A_zprec - zA_zprec);
48#define ZA_MASK (0xff
<< (zprec + aprec))
50 qt_static_shift<24 - zprec - aprec>(zA &
ZA_MASK)
51 | qt_static_shift<16 - zprec - aprec>(zR &
ZA_MASK)
52 | qt_static_shift<8 - zprec - aprec>(zG &
ZA_MASK)
53 | qt_static_shift<-zprec - aprec>(zB &
ZA_MASK);
71 uchar *bptr = im.scanLine(line);
73 int zR = 0, zG = 0, zB = 0, zA = 0;
75 if (alphaOnly && im.format() != QImage::Format_Indexed8)
78 const int stride = im.depth() >> 3;
79 const int im_width = im.width();
80 for (
int index = 0; index < im_width; ++index) {
82 qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
84 qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
90 for (
int index = im_width - 2; index >= 0; --index) {
93 qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
95 qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
117void expblur(QImage &img, qreal radius,
bool improvedQuality =
false,
int transposed = 0)
121 radius *= qreal(0.5);
123 Q_ASSERT(img.format() == QImage::Format_ARGB32_Premultiplied
124 || img.format() == QImage::Format_RGB32
125 || img.format() == QImage::Format_Indexed8
126 || img.format() == QImage::Format_Grayscale8);
131 const qreal cutOffIntensity = 2;
132 int alpha = radius <= qreal(1e-5)
134 : qRound((1<<aprec)*(1 - qPow(cutOffIntensity * (1 / qreal(255)), 1 / radius)));
136 int img_height = img.height();
137 for (
int row = 0; row < img_height; ++row) {
138 for (
int i = 0; i <=
int(improvedQuality); ++i)
139 qt_blurrow<aprec, zprec, alphaOnly>(img, row, alpha);
142 QImage temp(img.height(), img.width(), img.format());
143 temp.setDevicePixelRatio(img.devicePixelRatio());
144 if (transposed >= 0) {
145 if (img.depth() == 8) {
146 qt_memrotate270(
reinterpret_cast<
const quint8*>(img.bits()),
147 img.width(), img.height(), img.bytesPerLine(),
148 reinterpret_cast<quint8*>(temp.bits()),
149 temp.bytesPerLine());
151 qt_memrotate270(
reinterpret_cast<
const quint32*>(img.bits()),
152 img.width(), img.height(), img.bytesPerLine(),
153 reinterpret_cast<quint32*>(temp.bits()),
154 temp.bytesPerLine());
157 if (img.depth() == 8) {
158 qt_memrotate90(
reinterpret_cast<
const quint8*>(img.bits()),
159 img.width(), img.height(), img.bytesPerLine(),
160 reinterpret_cast<quint8*>(temp.bits()),
161 temp.bytesPerLine());
163 qt_memrotate90(
reinterpret_cast<
const quint32*>(img.bits()),
164 img.width(), img.height(), img.bytesPerLine(),
165 reinterpret_cast<quint32*>(temp.bits()),
166 temp.bytesPerLine());
170 img_height = temp.height();
171 for (
int row = 0; row < img_height; ++row) {
172 for (
int i = 0; i <=
int(improvedQuality); ++i)
173 qt_blurrow<aprec, zprec, alphaOnly>(temp, row, alpha);
176 if (transposed == 0) {
177 if (img.depth() == 8) {
178 qt_memrotate90(
reinterpret_cast<
const quint8*>(temp.bits()),
179 temp.width(), temp.height(), temp.bytesPerLine(),
180 reinterpret_cast<quint8*>(img.bits()),
183 qt_memrotate90(
reinterpret_cast<
const quint32*>(temp.bits()),
184 temp.width(), temp.height(), temp.bytesPerLine(),
185 reinterpret_cast<quint32*>(img.bits()),
200 if (source.width() < 2 || source.height() < 2)
203 QImage srcImage = source;
205 if (source.format() == QImage::Format_Indexed8 || source.format() == QImage::Format_Grayscale8) {
207 QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
208 dest.setDevicePixelRatio(source.devicePixelRatio());
210 const uchar *src =
reinterpret_cast<
const uchar*>(
const_cast<
const QImage &>(srcImage).bits());
211 qsizetype sx = srcImage.bytesPerLine();
212 qsizetype sx2 = sx << 1;
214 uchar *dst =
reinterpret_cast<uchar*>(dest.bits());
215 qsizetype dx = dest.bytesPerLine();
216 int ww = dest.width();
217 int hh = dest.height();
219 for (
int y = hh; y; --y, dst += dx, src += sx2) {
220 const uchar *p1 = src;
221 const uchar *p2 = src + sx;
223 for (
int x = ww; x; --x, ++q, p1 += 2, p2 += 2)
224 *q = ((
int(p1[0]) +
int(p1[1]) +
int(p2[0]) +
int(p2[1])) + 2) >> 2;
228 }
else if (source.format() == QImage::Format_ARGB8565_Premultiplied) {
229 QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
230 dest.setDevicePixelRatio(source.devicePixelRatio());
232 const uchar *src =
reinterpret_cast<
const uchar*>(
const_cast<
const QImage &>(srcImage).bits());
233 qsizetype sx = srcImage.bytesPerLine();
234 qsizetype sx2 = sx << 1;
236 uchar *dst =
reinterpret_cast<uchar*>(dest.bits());
237 qsizetype dx = dest.bytesPerLine();
238 int ww = dest.width();
239 int hh = dest.height();
241 for (
int y = hh; y; --y, dst += dx, src += sx2) {
242 const uchar *p1 = src;
243 const uchar *p2 = src + sx;
245 for (
int x = ww; x; --x, q += 3, p1 += 6, p2 += 6) {
247 q[0] =
AVG(
AVG(p1[0], p1[3]),
AVG(p2[0], p2[3]));
249 const quint16 p16_1 = (p1[2] << 8) | p1[1];
250 const quint16 p16_2 = (p1[5] << 8) | p1[4];
251 const quint16 p16_3 = (p2[2] << 8) | p2[1];
252 const quint16 p16_4 = (p2[5] << 8) | p2[4];
253 const quint16 result =
AVG16(
AVG16(p16_1, p16_2),
AVG16(p16_3, p16_4));
254 q[1] = result & 0xff;
260 }
else if (source.format() != QImage::Format_ARGB32_Premultiplied
261 && source.format() != QImage::Format_RGB32)
263 srcImage = source.convertToFormat(QImage::Format_ARGB32_Premultiplied);
266 QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
267 dest.setDevicePixelRatio(source.devicePixelRatio());
269 const quint32 *src =
reinterpret_cast<
const quint32*>(
const_cast<
const QImage &>(srcImage).bits());
270 qsizetype sx = srcImage.bytesPerLine() >> 2;
271 qsizetype sx2 = sx << 1;
273 quint32 *dst =
reinterpret_cast<quint32*>(dest.bits());
274 qsizetype dx = dest.bytesPerLine() >> 2;
275 int ww = dest.width();
276 int hh = dest.height();
278 for (
int y = hh; y; --y, dst += dx, src += sx2) {
279 const quint32 *p1 = src;
280 const quint32 *p2 = src + sx;
282 for (
int x = ww; x; --x, q++, p1 += 2, p2 += 2)
283 *q =
AVG(
AVG(p1[0], p1[1]),
AVG(p2[0], p2[1]));
292Q_GUI_EXPORT
void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius,
bool quality,
bool alphaOnly,
int transposed = 0)
294 if (blurImage.format() != QImage::Format_ARGB32_Premultiplied
295 && blurImage.format() != QImage::Format_RGB32)
297 blurImage = std::move(blurImage).convertToFormat(QImage::Format_ARGB32_Premultiplied);
301 if (radius >= 4 && blurImage.width() >= 2 && blurImage.height() >= 2) {
302 blurImage = qt_halfScaled(blurImage);
304 radius *= qreal(0.5);
308 expblur<12, 10,
true>(blurImage, radius, quality, transposed);
310 expblur<12, 10,
false>(blurImage, radius, quality, transposed);
313 p->scale(scale, scale);
314 p->setRenderHint(QPainter::SmoothPixmapTransform);
315 p->drawImage(QRect(QPoint(0, 0), blurImage.deviceIndependentSize().toSize()), blurImage);
319Q_GUI_EXPORT
void qt_blurImage(QImage &blurImage, qreal radius,
bool quality,
int transposed = 0)
321 if (blurImage.format() == QImage::Format_Indexed8 || blurImage.format() == QImage::Format_Grayscale8)
322 expblur<12, 10,
true>(blurImage, radius, quality, transposed);
324 expblur<12, 10,
false>(blurImage, radius, quality, transposed);