Allow rounding with different radius per corner.

This commit is contained in:
John Preston 2022-09-30 18:42:14 +04:00
parent 80445f2bd3
commit f49ec866c1

View file

@ -1017,13 +1017,8 @@ QImage Round(
} else { } else {
Assert(QRect(QPoint(), image.size()).contains(target)); Assert(QRect(QPoint(), image.size()).contains(target));
} }
auto cornerWidth = cornerMasks[0].width(); const auto targetWidth = target.width();
auto cornerHeight = cornerMasks[0].height(); const auto targetHeight = target.height();
auto targetWidth = target.width();
auto targetHeight = target.height();
if (targetWidth < cornerWidth || targetHeight < cornerHeight) {
return std::move(image);
}
image = std::move(image).convertToFormat( image = std::move(image).convertToFormat(
QImage::Format_ARGB32_Premultiplied); QImage::Format_ARGB32_Premultiplied);
@ -1035,40 +1030,59 @@ QImage Round(
// Real image bytesPerLine is smaller than the one we use for offsets. // Real image bytesPerLine is smaller than the one we use for offsets.
auto ints = reinterpret_cast<uint32*>(image.bits()); auto ints = reinterpret_cast<uint32*>(image.bits());
constexpr auto imageIntsPerPixel = 1; constexpr auto kImageIntsPerPixel = 1;
auto imageIntsPerLine = (image.bytesPerLine() >> 2); const auto imageIntsPerLine = (image.bytesPerLine() >> 2);
Assert(image.depth() == static_cast<int>((imageIntsPerPixel * sizeof(uint32)) << 3)); Assert(image.depth() == ((kImageIntsPerPixel * sizeof(uint32)) << 3));
Assert(image.bytesPerLine() == (imageIntsPerLine << 2)); Assert(image.bytesPerLine() == (imageIntsPerLine << 2));
auto intsTopLeft = ints + target.x() + target.y() * imageIntsPerLine; const auto maskCorner = [&](
auto intsTopRight = ints + target.x() + targetWidth - cornerWidth + target.y() * imageIntsPerLine; const QImage &mask,
auto intsBottomLeft = ints + target.x() + (target.y() + targetHeight - cornerHeight) * imageIntsPerLine; bool right = false,
auto intsBottomRight = ints + target.x() + targetWidth - cornerWidth + (target.y() + targetHeight - cornerHeight) * imageIntsPerLine; bool bottom = false) {
auto maskCorner = [&](uint32 *imageInts, const QImage &mask) { const auto maskWidth = mask.width();
auto maskWidth = mask.width(); const auto maskHeight = mask.height();
auto maskHeight = mask.height(); if (mask.isNull()
auto maskBytesPerPixel = (mask.depth() >> 3); || targetWidth < maskWidth
auto maskBytesPerLine = mask.bytesPerLine(); || targetHeight < maskHeight) {
auto maskBytesAdded = maskBytesPerLine - maskWidth * maskBytesPerPixel; return;
auto maskBytes = mask.constBits(); }
const auto maskBytesPerPixel = (mask.depth() >> 3);
const auto maskBytesPerLine = mask.bytesPerLine();
const auto maskBytesAdded = maskBytesPerLine
- maskWidth * maskBytesPerPixel;
Assert(maskBytesAdded >= 0); Assert(maskBytesAdded >= 0);
Assert(mask.depth() == (maskBytesPerPixel << 3)); Assert(mask.depth() == (maskBytesPerPixel << 3));
auto imageIntsAdded = imageIntsPerLine - maskWidth * imageIntsPerPixel; const auto imageIntsAdded = imageIntsPerLine
- maskWidth * kImageIntsPerPixel;
Assert(imageIntsAdded >= 0); Assert(imageIntsAdded >= 0);
auto imageInts = ints + target.x() + target.y() * imageIntsPerLine;
if (right) {
imageInts += targetWidth - maskWidth;
}
if (bottom) {
imageInts += (targetHeight - maskHeight) * imageIntsPerLine;
}
auto maskBytes = mask.constBits();
for (auto y = 0; y != maskHeight; ++y) { for (auto y = 0; y != maskHeight; ++y) {
for (auto x = 0; x != maskWidth; ++x) { for (auto x = 0; x != maskWidth; ++x) {
auto opacity = static_cast<anim::ShiftedMultiplier>(*maskBytes) + 1; auto opacity = static_cast<anim::ShiftedMultiplier>(*maskBytes) + 1;
*imageInts = anim::unshifted(anim::shifted(*imageInts) * opacity); *imageInts = anim::unshifted(anim::shifted(*imageInts) * opacity);
maskBytes += maskBytesPerPixel; maskBytes += maskBytesPerPixel;
imageInts += imageIntsPerPixel; imageInts += kImageIntsPerPixel;
} }
maskBytes += maskBytesAdded; maskBytes += maskBytesAdded;
imageInts += imageIntsAdded; imageInts += imageIntsAdded;
} }
}; };
if (corners & RectPart::TopLeft) maskCorner(intsTopLeft, cornerMasks[0]);
if (corners & RectPart::TopRight) maskCorner(intsTopRight, cornerMasks[1]); if (corners & RectPart::TopLeft) maskCorner(cornerMasks[0]);
if (corners & RectPart::BottomLeft) maskCorner(intsBottomLeft, cornerMasks[2]); if (corners & RectPart::TopRight) maskCorner(cornerMasks[1], true);
if (corners & RectPart::BottomRight) maskCorner(intsBottomRight, cornerMasks[3]); if (corners & RectPart::BottomLeft) {
maskCorner(cornerMasks[2], false, true);
}
if (corners & RectPart::BottomRight) {
maskCorner(cornerMasks[3], true, true);
}
return std::move(image); return std::move(image);
} }