[img-editor] Locked crop frame as stencil and clipped output by shape.

This commit is contained in:
23rd
2026-04-13 20:10:35 +03:00
parent 1d035109ea
commit 58c7467720
5 changed files with 71 additions and 13 deletions
@@ -475,6 +475,7 @@ void OpenPhotoEditorForSticker(
.exactSize = QSize(kStickerSide, kStickerSide),
.cropType = Editor::EditorData::CropType::RoundedRect,
.keepAspectRatio = true,
.fixedCrop = true,
});
const auto raw = editor.get();
@@ -177,6 +177,10 @@ void Crop::paintFrame(QPainter &p) {
p.save();
p.setRenderHint(QPainter::Antialiasing, true);
p.fillPath(frameShape, st::photoCropPointFg);
if (_data.fixedCrop) {
p.restore();
return;
}
{
const auto cornerLength = std::min(
float64(st::photoEditorCropPointSize * 2),
@@ -286,6 +290,10 @@ void Crop::convertCropPaintToOriginal() {
}
void Crop::updateEdges() {
if (_data.fixedCrop) {
_edges.clear();
return;
}
const auto &s = _pointSize;
const auto &m = _edgePointMargins;
const auto &r = _cropPaint;
@@ -338,6 +346,9 @@ Qt::Edges Crop::mouseState(const QPoint &p) {
}
void Crop::mousePressEvent(QMouseEvent *e) {
if (_data.fixedCrop) {
return;
}
computeDownState(e->pos());
if (_down.edge) {
setGridVisible(true, false);
@@ -345,6 +356,9 @@ void Crop::mousePressEvent(QMouseEvent *e) {
}
void Crop::mouseReleaseEvent(QMouseEvent *e) {
if (_data.fixedCrop) {
return;
}
const auto hadEdge = bool(_down.edge);
if (hadEdge) {
setGridVisible(false, true);
@@ -474,6 +488,9 @@ void Crop::performMove(const QPoint &pos) {
}
void Crop::mouseMoveEvent(QMouseEvent *e) {
if (_data.fixedCrop) {
return;
}
const auto pos = e->pos();
const auto pressedEdge = _down.edge;
@@ -237,6 +237,7 @@ PhotoEditor::PhotoEditor(
std::move(show),
_brushes,
_brushTool)) {
_modifications.cropType = data.cropType;
sizeValue(
) | rpl::on_next([=](const QSize &size) {
@@ -9,8 +9,40 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "editor/scene/scene.h"
#include "ui/painter.h"
#include "ui/userpic_view.h"
namespace Editor {
namespace {
void ApplyShapeMask(QImage &image, EditorData::CropType type) {
if (type == EditorData::CropType::Rect) {
return;
}
if (image.format() != QImage::Format_ARGB32_Premultiplied) {
image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
}
auto mask = QImage(image.size(), QImage::Format_ARGB32_Premultiplied);
mask.fill(Qt::transparent);
{
auto p = QPainter(&mask);
auto hq = PainterHighQualityEnabler(p);
p.setPen(Qt::NoPen);
p.setBrush(Qt::white);
const auto rect = QRectF(QPointF(), QSizeF(image.size()));
if (type == EditorData::CropType::Ellipse) {
p.drawEllipse(rect);
} else {
const auto radius = std::min(rect.width(), rect.height())
* Ui::ForumUserpicRadiusMultiplier();
p.drawRoundedRect(rect, radius, radius);
}
}
auto p = QPainter(&image);
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
p.drawImage(0, 0, mask);
}
} // namespace
QImage ImageModified(QImage image, const PhotoModifications &mods) {
Expects(!image.isNull());
@@ -32,6 +64,7 @@ QImage ImageModified(QImage image, const PhotoModifications &mods) {
auto cropped = mods.crop.isValid()
? image.copy(mods.crop)
: image;
ApplyShapeMask(cropped, mods.cropType);
QTransform transform;
if (mods.flipped) {
transform.scale(-1, 1);
@@ -43,7 +76,11 @@ QImage ImageModified(QImage image, const PhotoModifications &mods) {
}
bool PhotoModifications::empty() const {
return !angle && !flipped && !crop.isValid() && !paint;
return !angle
&& !flipped
&& !crop.isValid()
&& cropType == EditorData::CropType::Rect
&& !paint;
}
PhotoModifications::operator bool() const {
@@ -11,18 +11,6 @@ namespace Editor {
class Scene;
struct PhotoModifications {
int angle = 0;
bool flipped = false;
QRect crop;
std::shared_ptr<Scene> paint = nullptr;
[[nodiscard]] bool empty() const;
[[nodiscard]] explicit operator bool() const;
~PhotoModifications();
};
struct EditorData {
enum class CropType {
Rect,
@@ -35,6 +23,20 @@ struct EditorData {
QSize exactSize;
CropType cropType = CropType::Rect;
bool keepAspectRatio = false;
bool fixedCrop = false;
};
struct PhotoModifications {
int angle = 0;
bool flipped = false;
QRect crop;
EditorData::CropType cropType = EditorData::CropType::Rect;
std::shared_ptr<Scene> paint = nullptr;
[[nodiscard]] bool empty() const;
[[nodiscard]] explicit operator bool() const;
~PhotoModifications();
};
[[nodiscard]] QImage ImageModified(