28inline void qt_blurinner(uchar *bptr,
int &zR,
int &zG,
int &zB,
int &zA,
int alpha)
30 QRgb *pixel = (QRgb *)bptr;
32#define Z_MASK (0xff
<< zprec)
33 const int A_zprec = qt_static_shift<zprec - 24>(*pixel) &
Z_MASK;
34 const int R_zprec = qt_static_shift<zprec - 16>(*pixel) &
Z_MASK;
35 const int G_zprec = qt_static_shift<zprec - 8>(*pixel) &
Z_MASK;
36 const int B_zprec = qt_static_shift<zprec>(*pixel) &
Z_MASK;
39 const int zR_zprec = zR >> aprec;
40 const int zG_zprec = zG >> aprec;
41 const int zB_zprec = zB >> aprec;
42 const int zA_zprec = zA >> aprec;
44 zR += alpha * (R_zprec - zR_zprec);
45 zG += alpha * (G_zprec - zG_zprec);
46 zB += alpha * (B_zprec - zB_zprec);
47 zA += alpha * (A_zprec - zA_zprec);
49#define ZA_MASK (0xff
<< (zprec + aprec))
51 qt_static_shift<24 - zprec - aprec>(zA &
ZA_MASK)
52 | qt_static_shift<16 - zprec - aprec>(zR &
ZA_MASK)
53 | qt_static_shift<8 - zprec - aprec>(zG &
ZA_MASK)
54 | qt_static_shift<-zprec - aprec>(zB &
ZA_MASK);
72 uchar *bptr = im.scanLine(line);
74 int zR = 0, zG = 0, zB = 0, zA = 0;
76 if (alphaOnly && im.format() != QImage::Format_Indexed8)
79 const int stride = im.depth() >> 3;
80 const int im_width = im.width();
81 for (
int index = 0; index < im_width; ++index) {
83 qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
85 qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
91 for (
int index = im_width - 2; index >= 0; --index) {
94 qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
96 qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
118void expblur(QImage &img, qreal radius,
bool improvedQuality =
false,
int transposed = 0)
122 radius *= qreal(0.5);
124 Q_ASSERT(img.format() == QImage::Format_ARGB32_Premultiplied
125 || img.format() == QImage::Format_RGB32
126 || img.format() == QImage::Format_Indexed8
127 || img.format() == QImage::Format_Grayscale8);
132 const qreal cutOffIntensity = 2;
133 int alpha = radius <= qreal(1e-5)
135 : qRound((1<<aprec)*(1 - qPow(cutOffIntensity * (1 / qreal(255)), 1 / radius)));
137 int img_height = img.height();
138 for (
int row = 0; row < img_height; ++row) {
139 for (
int i = 0; i <=
int(improvedQuality); ++i)
140 qt_blurrow<aprec, zprec, alphaOnly>(img, row, alpha);
143 QImage temp(img.height(), img.width(), img.format());
144 temp.setDevicePixelRatio(img.devicePixelRatio());
145 if (transposed >= 0) {
146 if (img.depth() == 8) {
147 qt_memrotate270(
reinterpret_cast<
const quint8*>(img.bits()),
148 img.width(), img.height(), img.bytesPerLine(),
149 reinterpret_cast<quint8*>(temp.bits()),
150 temp.bytesPerLine());
152 qt_memrotate270(
reinterpret_cast<
const quint32*>(img.bits()),
153 img.width(), img.height(), img.bytesPerLine(),
154 reinterpret_cast<quint32*>(temp.bits()),
155 temp.bytesPerLine());
158 if (img.depth() == 8) {
159 qt_memrotate90(
reinterpret_cast<
const quint8*>(img.bits()),
160 img.width(), img.height(), img.bytesPerLine(),
161 reinterpret_cast<quint8*>(temp.bits()),
162 temp.bytesPerLine());
164 qt_memrotate90(
reinterpret_cast<
const quint32*>(img.bits()),
165 img.width(), img.height(), img.bytesPerLine(),
166 reinterpret_cast<quint32*>(temp.bits()),
167 temp.bytesPerLine());
171 img_height = temp.height();
172 for (
int row = 0; row < img_height; ++row) {
173 for (
int i = 0; i <=
int(improvedQuality); ++i)
174 qt_blurrow<aprec, zprec, alphaOnly>(temp, row, alpha);
177 if (transposed == 0) {
178 if (img.depth() == 8) {
179 qt_memrotate90(
reinterpret_cast<
const quint8*>(temp.bits()),
180 temp.width(), temp.height(), temp.bytesPerLine(),
181 reinterpret_cast<quint8*>(img.bits()),
184 qt_memrotate90(
reinterpret_cast<
const quint32*>(temp.bits()),
185 temp.width(), temp.height(), temp.bytesPerLine(),
186 reinterpret_cast<quint32*>(img.bits()),
201 if (source.width() < 2 || source.height() < 2)
204 QImage srcImage = source;
206 if (source.format() == QImage::Format_Indexed8 || source.format() == QImage::Format_Grayscale8) {
208 QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
209 dest.setDevicePixelRatio(source.devicePixelRatio());
211 const uchar *src =
reinterpret_cast<
const uchar*>(
const_cast<
const QImage &>(srcImage).bits());
212 qsizetype sx = srcImage.bytesPerLine();
213 qsizetype sx2 = sx << 1;
215 uchar *dst =
reinterpret_cast<uchar*>(dest.bits());
216 qsizetype dx = dest.bytesPerLine();
217 int ww = dest.width();
218 int hh = dest.height();
220 for (
int y = hh; y; --y, dst += dx, src += sx2) {
221 const uchar *p1 = src;
222 const uchar *p2 = src + sx;
224 for (
int x = ww; x; --x, ++q, p1 += 2, p2 += 2)
225 *q = ((
int(p1[0]) +
int(p1[1]) +
int(p2[0]) +
int(p2[1])) + 2) >> 2;
229 }
else if (source.format() == QImage::Format_ARGB8565_Premultiplied) {
230 QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
231 dest.setDevicePixelRatio(source.devicePixelRatio());
233 const uchar *src =
reinterpret_cast<
const uchar*>(
const_cast<
const QImage &>(srcImage).bits());
234 qsizetype sx = srcImage.bytesPerLine();
235 qsizetype sx2 = sx << 1;
237 uchar *dst =
reinterpret_cast<uchar*>(dest.bits());
238 qsizetype dx = dest.bytesPerLine();
239 int ww = dest.width();
240 int hh = dest.height();
242 for (
int y = hh; y; --y, dst += dx, src += sx2) {
243 const uchar *p1 = src;
244 const uchar *p2 = src + sx;
246 for (
int x = ww; x; --x, q += 3, p1 += 6, p2 += 6) {
248 q[0] =
AVG(
AVG(p1[0], p1[3]),
AVG(p2[0], p2[3]));
250 const quint16 p16_1 = (p1[2] << 8) | p1[1];
251 const quint16 p16_2 = (p1[5] << 8) | p1[4];
252 const quint16 p16_3 = (p2[2] << 8) | p2[1];
253 const quint16 p16_4 = (p2[5] << 8) | p2[4];
254 const quint16 result =
AVG16(
AVG16(p16_1, p16_2),
AVG16(p16_3, p16_4));
255 q[1] = result & 0xff;
261 }
else if (source.format() != QImage::Format_ARGB32_Premultiplied
262 && source.format() != QImage::Format_RGB32)
264 srcImage = source.convertToFormat(QImage::Format_ARGB32_Premultiplied);
267 QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
268 dest.setDevicePixelRatio(source.devicePixelRatio());
270 const quint32 *src =
reinterpret_cast<
const quint32*>(
const_cast<
const QImage &>(srcImage).bits());
271 qsizetype sx = srcImage.bytesPerLine() >> 2;
272 qsizetype sx2 = sx << 1;
274 quint32 *dst =
reinterpret_cast<quint32*>(dest.bits());
275 qsizetype dx = dest.bytesPerLine() >> 2;
276 int ww = dest.width();
277 int hh = dest.height();
279 for (
int y = hh; y; --y, dst += dx, src += sx2) {
280 const quint32 *p1 = src;
281 const quint32 *p2 = src + sx;
283 for (
int x = ww; x; --x, q++, p1 += 2, p2 += 2)
284 *q =
AVG(
AVG(p1[0], p1[1]),
AVG(p2[0], p2[1]));
293Q_GUI_EXPORT
void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius,
bool quality,
bool alphaOnly,
int transposed = 0)
295 if (blurImage.format() != QImage::Format_ARGB32_Premultiplied
296 && blurImage.format() != QImage::Format_RGB32)
298 blurImage = std::move(blurImage).convertToFormat(QImage::Format_ARGB32_Premultiplied);
302 if (radius >= 4 && blurImage.width() >= 2 && blurImage.height() >= 2) {
303 blurImage = qt_halfScaled(blurImage);
305 radius *= qreal(0.5);
309 expblur<12, 10,
true>(blurImage, radius, quality, transposed);
311 expblur<12, 10,
false>(blurImage, radius, quality, transposed);
314 p->scale(scale, scale);
315 p->setRenderHint(QPainter::SmoothPixmapTransform);
316 p->drawImage(QRect(QPoint(0, 0), blurImage.deviceIndependentSize().toSize()), blurImage);
320Q_GUI_EXPORT
void qt_blurImage(QImage &blurImage, qreal radius,
bool quality,
int transposed = 0)
322 if (blurImage.format() == QImage::Format_Indexed8 || blurImage.format() == QImage::Format_Grayscale8)
323 expblur<12, 10,
true>(blurImage, radius, quality, transposed);
325 expblur<12, 10,
false>(blurImage, radius, quality, transposed);