英文:
When modifying a QImage using scanLine, artifacts show up. Why?
问题
这段代码在输出中生成了奇怪的图像伪影,这是由于paint
函数的渲染方法引起的。它在渲染图标时使用了源SVG图像的不透明度(alpha通道),这可能导致额外的矩形部分。要解决这个问题,您可以尝试以下方法:
class Icon {
public:
// ...
/// renders a pixmap that uses primary where the mask is black,
/// secondary where the mask is white. Mask defines transparency.
QPixmap paint(const QColor &primary, const QColor &secondary) const {
QImage buffer(mask.size(), QImage::Format_ARGB32_Premultiplied);
Gradient gradient{primary.rgb(), secondary.rgb()};
for (int y = 0; y < mask.height(); ++y) {
const QRgb *srcLine = reinterpret_cast<const QRgb*>(mask.constScanLine(y));
QRgb *destLine = reinterpret_cast<QRgb*>(buffer.scanLine(y));
for (int x = 0; x < mask.width(); ++x) {
const QRgb &src = srcLine[x];
int gray = qGray(src); // Calculate grayscale value
int alpha = qAlpha(src);
destLine[x] = gradient.at(gray, alpha); // Use grayscale as index
}
}
// Create a new image with transparency
QImage finalImage(mask.size(), QImage::Format_ARGB32_Premultiplied);
finalImage.fill(Qt::transparent);
QPainter finalPainter(&finalImage);
finalPainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
finalPainter.drawImage(0, 0, buffer);
QPixmap pixmap;
pixmap.convertFromImage(finalImage);
return pixmap;
}
// ...
};
通过这种方式,您首先计算源SVG图像的灰度值,并使用该值作为索引来获得渐变颜色,然后将它们合成到一个具有透明度的最终图像中。这应该可以解决生成额外矩形部分的问题。
英文:
My application has different color modes. Therefore, I need to render my icons in different colors.
My icons are grayscale SVGs. Each color mode defines two colors for icons. One color shall replace black, the other shall replace white.
The code I use to implement this is as follows:
struct Gradient {
QRgb a, b;
/// index in [0, 255]. alpha from mask modifies dest alpha.
QRgb at(int index, int alpha) const {
const int rindex = 255 - index;
return qRgba(
(qRed(a) * rindex + qRed(b) * index) / 255,
(qGreen(a) * rindex + qGreen(b) * index) / 255,
(qBlue(a) * rindex + qBlue(b) * index) / 255,
(((qAlpha(a) * rindex + qAlpha(b) * index) / 255) * alpha) / 255
);
}
};
class Icon {
public:
explicit Icon(const QString &path): path{path} {}
/// must set once before rendering pixmaps.
/// generates a mask image from the source SVG with the given size.
void setSize(QSize size) {
if (mask.size() != size) {
QSvgRenderer renderer(path);
if (renderer.isValid()) {
mask = QImage(size, QImage::Format_ARGB32_Premultiplied);
mask.fill(Qt::transparent);
QPainter svgPainter(&mask);
renderer.render(&svgPainter);
}
}
}
/// renders a pixmap that uses primary where the mask is black,
/// secondary where the mask is white. Mask defines transparency.
QPixmap paint(const QColor &primary, const QColor &secondary) const {
QImage buffer(mask.size(), QImage::Format_ARGB32_Premultiplied);
Gradient gradient{primary.rgb(), secondary.rgb()};
for (int y = 0; y < mask.height(); ++y) {
const QRgb *srcLine = reinterpret_cast<const QRgb*>(mask.constScanLine(y));
QRgb *destLine = reinterpret_cast<QRgb*>(buffer.scanLine(y));
for (int x = 0; x < mask.width(); ++x) {
const QRgb &src = srcLine[x];
// using red as indicator for the grayscale color.
destLine[x] = gradient.at(qRed(src), qAlpha(src));
}
}
QPixmap pixmap;
pixmap.convertFromImage(buffer);
return pixmap;
}
bool isNull() const {
return mask.isNull();
}
private:
QString path;
QImage mask;
};
This code generates strange artifacts in the output:
From this input:
This is rendered with primary and secondary colors both #657590
. The dark blue is the backing widget's background color. The original icon just has the cog outline.
Why are the additional rectangular parts created? They are not part of the source image. I tried to use buffer.setPixel
instead of scanLine
, but that produced the same output.
答案1
得分: 0
问题出在图像格式QImage::Format_ARGB32_Premultiplied
上。我修改图像的方式,QImage::Format_ARGB32
更合适。使用这种格式解决了问题。
英文:
The problem was the image format QImage::Format_ARGB32_Premultiplied
. The way I modified the image, QImage::Format_ARGB32
was appropriate. Using that format solved the problem.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论