update
This commit is contained in:
@@ -25,6 +25,14 @@ QPushButton* makeAlgoButton(const QString& title, QWidget* parent) {
|
||||
|
||||
} // namespace
|
||||
|
||||
QString BlackholeResolveDialog::defaultModelInpaintPrompt() {
|
||||
return QStringLiteral(
|
||||
"中国画局部,需去除人物并只补背景:请严格依据掩膜外已见的笔墨皴擦、设色层次、留白与纸绢肌理,"
|
||||
"在掩膜内自然延展,补全为山石、坡岸、云水、苔点或空灵留白等,与外缘笔法、墨色与气韵连贯衔接;"
|
||||
"禁止出现人物轮廓、肢体、衣褶、五官、手足、发丝、肤色、投影及去人后的模糊晕带、鬼影边缘与色块台阶,"
|
||||
"整体须像原画从未画入人物一样自然,不留修补感。");
|
||||
}
|
||||
|
||||
BlackholeResolveDialog::BlackholeResolveDialog(const QString& blackholeName, QWidget* parent)
|
||||
: QDialog(parent),
|
||||
m_blackholeName(blackholeName) {
|
||||
@@ -134,7 +142,8 @@ void BlackholeResolveDialog::buildDetailPage() {
|
||||
pLay->setSpacing(8);
|
||||
|
||||
m_promptEdit = new QPlainTextEdit(panel);
|
||||
m_promptEdit->setPlaceholderText(QStringLiteral("提示词(可选)"));
|
||||
m_promptEdit->setPlainText(BlackholeResolveDialog::defaultModelInpaintPrompt());
|
||||
m_promptEdit->setPlaceholderText(QStringLiteral("可按画面增删;若全部删空,请求时仍使用内置默认描述"));
|
||||
m_promptEdit->setMinimumHeight(72);
|
||||
pLay->addWidget(m_promptEdit);
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@ public:
|
||||
Algorithm selectedAlgorithm() const { return m_selectedAlgorithm; }
|
||||
QString promptText() const;
|
||||
|
||||
/// 模型补全(LaMa 等)内置正向提示:中国画去人物、补背景纹理,无人物残留。
|
||||
[[nodiscard]] static QString defaultModelInpaintPrompt();
|
||||
|
||||
private:
|
||||
void buildSelectPage();
|
||||
void buildDetailPage();
|
||||
|
||||
@@ -20,7 +20,7 @@ static QLabel* makeImageLabel(QWidget* parent) {
|
||||
static QScrollArea* wrapScroll(QWidget* child, QWidget* parent) {
|
||||
auto* sc = new QScrollArea(parent);
|
||||
sc->setWidget(child);
|
||||
sc->setWidgetResizable(true);
|
||||
sc->setWidgetResizable(false);
|
||||
sc->setBackgroundRole(QPalette::Dark);
|
||||
return sc;
|
||||
}
|
||||
@@ -28,7 +28,7 @@ static QScrollArea* wrapScroll(QWidget* child, QWidget* parent) {
|
||||
InpaintPreviewDialog::InpaintPreviewDialog(const QString& title, QWidget* parent)
|
||||
: QDialog(parent) {
|
||||
setModal(true);
|
||||
setMinimumSize(720, 480);
|
||||
setMinimumSize(880, 520);
|
||||
setWindowTitle(title);
|
||||
|
||||
auto* root = new QVBoxLayout(this);
|
||||
@@ -39,6 +39,8 @@ InpaintPreviewDialog::InpaintPreviewDialog(const QString& title, QWidget* parent
|
||||
m_afterLabel = makeImageLabel(this);
|
||||
m_beforeScroll = wrapScroll(m_beforeLabel, this);
|
||||
m_afterScroll = wrapScroll(m_afterLabel, this);
|
||||
m_beforeScroll->setMinimumHeight(200);
|
||||
m_afterScroll->setMinimumHeight(200);
|
||||
|
||||
auto* splitter = new QSplitter(Qt::Horizontal, this);
|
||||
splitter->addWidget(m_beforeScroll);
|
||||
@@ -57,12 +59,16 @@ InpaintPreviewDialog::InpaintPreviewDialog(const QString& title, QWidget* parent
|
||||
|
||||
void InpaintPreviewDialog::setImages(const QImage& before, const QImage& after) {
|
||||
if (m_beforeLabel) {
|
||||
m_beforeLabel->setPixmap(QPixmap::fromImage(before));
|
||||
m_beforeLabel->adjustSize();
|
||||
const QPixmap pb = QPixmap::fromImage(before);
|
||||
m_beforeLabel->setPixmap(pb);
|
||||
m_beforeLabel->setMinimumSize(pb.size());
|
||||
m_beforeLabel->resize(pb.size());
|
||||
}
|
||||
if (m_afterLabel) {
|
||||
m_afterLabel->setPixmap(QPixmap::fromImage(after));
|
||||
m_afterLabel->adjustSize();
|
||||
const QPixmap pa = QPixmap::fromImage(after);
|
||||
m_afterLabel->setPixmap(pa);
|
||||
m_afterLabel->setMinimumSize(pa.size());
|
||||
m_afterLabel->resize(pa.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -697,8 +697,7 @@ void EditorCanvas::setEntities(const QVector<core::Project::Entity>& entities,
|
||||
if (!m_depthAbsPath.isEmpty()) {
|
||||
if (m_depthDirty) {
|
||||
m_depthDirty = false;
|
||||
QImage img = readImageTolerant(m_depthAbsPath);
|
||||
m_depthImage8 = img.isNull() ? QImage() : img.convertToFormat(QImage::Format_Grayscale8);
|
||||
m_depthImage8 = core::image_file::loadDepthMapAlignedToBackground(m_depthAbsPath, m_bgAbsPath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -861,8 +860,7 @@ void EditorCanvas::setTools(const QVector<core::Project::Tool>& tools, const QVe
|
||||
if (!m_depthAbsPath.isEmpty()) {
|
||||
if (m_depthDirty) {
|
||||
m_depthDirty = false;
|
||||
QImage img = readImageTolerant(m_depthAbsPath);
|
||||
m_depthImage8 = img.isNull() ? QImage() : img.convertToFormat(QImage::Format_Grayscale8);
|
||||
m_depthImage8 = core::image_file::loadDepthMapAlignedToBackground(m_depthAbsPath, m_bgAbsPath);
|
||||
}
|
||||
}
|
||||
const qsizetype n = tools.size();
|
||||
@@ -1915,8 +1913,7 @@ void EditorCanvas::paintEvent(QPaintEvent* e) {
|
||||
if (wantDepth) {
|
||||
if (m_depthDirty) {
|
||||
m_depthDirty = false;
|
||||
QImage img = readImageTolerant(m_depthAbsPath);
|
||||
m_depthImage8 = img.isNull() ? QImage() : img.convertToFormat(QImage::Format_Grayscale8);
|
||||
m_depthImage8 = core::image_file::loadDepthMapAlignedToBackground(m_depthAbsPath, m_bgAbsPath);
|
||||
}
|
||||
if (!m_depthImage8.isNull()) {
|
||||
const int overlayAlpha = m_backgroundVisible ? m_depthOverlayAlpha : 255;
|
||||
@@ -2457,8 +2454,7 @@ void EditorCanvas::mousePressEvent(QMouseEvent* e) {
|
||||
if (!m_depthAbsPath.isEmpty()) {
|
||||
if (m_depthDirty) {
|
||||
m_depthDirty = false;
|
||||
QImage img = readImageTolerant(m_depthAbsPath);
|
||||
m_depthImage8 = img.isNull() ? QImage() : img.convertToFormat(QImage::Format_Grayscale8);
|
||||
m_depthImage8 = core::image_file::loadDepthMapAlignedToBackground(m_depthAbsPath, m_bgAbsPath);
|
||||
}
|
||||
if (!m_depthImage8.isNull()) {
|
||||
const int xi = static_cast<int>(std::floor(wp0.x()));
|
||||
@@ -2892,8 +2888,7 @@ void EditorCanvas::mouseMoveEvent(QMouseEvent* e) {
|
||||
if (!m_depthAbsPath.isEmpty()) {
|
||||
if (m_depthDirty) {
|
||||
m_depthDirty = false;
|
||||
QImage img = readImageTolerant(m_depthAbsPath);
|
||||
m_depthImage8 = img.isNull() ? QImage() : img.convertToFormat(QImage::Format_Grayscale8);
|
||||
m_depthImage8 = core::image_file::loadDepthMapAlignedToBackground(m_depthAbsPath, m_bgAbsPath);
|
||||
}
|
||||
if (!m_depthImage8.isNull()) {
|
||||
const int xi = static_cast<int>(std::floor(wp.x()));
|
||||
@@ -3053,8 +3048,7 @@ void EditorCanvas::mouseMoveEvent(QMouseEvent* e) {
|
||||
|
||||
if (!m_depthAbsPath.isEmpty() && m_depthDirty) {
|
||||
m_depthDirty = false;
|
||||
QImage img = readImageTolerant(m_depthAbsPath);
|
||||
m_depthImage8 = img.isNull() ? QImage() : img.convertToFormat(QImage::Format_Grayscale8);
|
||||
m_depthImage8 = core::image_file::loadDepthMapAlignedToBackground(m_depthAbsPath, m_bgAbsPath);
|
||||
}
|
||||
if (!m_depthImage8.isNull()) {
|
||||
const QPointF c =
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
#include <QFontMetrics>
|
||||
#include <QHeaderView>
|
||||
#include <QImage>
|
||||
#include <QTransform>
|
||||
#include <QEventLoop>
|
||||
#include <QMessageBox>
|
||||
#include <QPixmap>
|
||||
@@ -3401,7 +3402,26 @@ void MainWindow::rebuildCentralPages() {
|
||||
polishCompactToolButton(m_previewBtnPlay, 36);
|
||||
pbl->addWidget(m_previewBtnPlay);
|
||||
m_previewPlaybackBar->setParent(canvasHost);
|
||||
cod setPreviewRequested(false);
|
||||
|
||||
m_floatingModeDock = new QFrame(canvasHost);
|
||||
m_floatingModeDock->setObjectName(QStringLiteral("FloatingModeDock"));
|
||||
m_floatingModeDock->setFrameShape(QFrame::NoFrame);
|
||||
m_floatingModeDock->setStyleSheet(QString::fromUtf8(kFloatingModeDockQss));
|
||||
auto* modeDockLayout = new QHBoxLayout(m_floatingModeDock);
|
||||
modeDockLayout->setContentsMargins(4, 4, 4, 4);
|
||||
modeDockLayout->setSpacing(6);
|
||||
|
||||
m_modeSelector = new QComboBox(m_floatingModeDock);
|
||||
m_modeSelector->addItem(QStringLiteral("编辑"));
|
||||
m_modeSelector->addItem(QStringLiteral("动画"));
|
||||
m_modeSelector->addItem(QStringLiteral("热点"));
|
||||
m_modeSelector->addItem(QStringLiteral("预览"));
|
||||
|
||||
connect(m_modeSelector, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
|
||||
if (index == 0) {
|
||||
m_animationRequested = false;
|
||||
m_hotspotRequested = false;
|
||||
setPreviewRequested(false);
|
||||
if (m_workspace.isOpen() &&
|
||||
m_workspace.project().activeAnimationId() != QStringLiteral("none")) {
|
||||
m_workspace.project().setActiveAnimationId(QStringLiteral("none"));
|
||||
@@ -3854,15 +3874,12 @@ cod setPreviewRequested(false);
|
||||
ent.polygonLocal.push_back(pt - ent.originWorld);
|
||||
}
|
||||
|
||||
const QString bgAbs = m_workspace.backgroundAbsolutePath();
|
||||
QImage depth8;
|
||||
if (m_workspace.hasDepth()) {
|
||||
const QString dpath = m_workspace.depthAbsolutePath();
|
||||
if (!dpath.isEmpty() && QFileInfo::exists(dpath)) {
|
||||
const QImage dimg =
|
||||
core::image_file::loadImageLimited(dpath, core::image_decode::kWorkspaceMaxPixels);
|
||||
if (!dimg.isNull()) {
|
||||
depth8 = dimg.convertToFormat(QImage::Format_Grayscale8);
|
||||
}
|
||||
if (!dpath.isEmpty() && QFileInfo::exists(dpath) && !bgAbs.isEmpty()) {
|
||||
depth8 = core::image_file::loadDepthMapAlignedToBackground(dpath, bgAbs);
|
||||
}
|
||||
}
|
||||
const QPointF c = entity_cutout::polygonCentroid(ent.cutoutPolygonWorld);
|
||||
@@ -3879,8 +3896,6 @@ cod setPreviewRequested(false);
|
||||
const double ds01 = static_cast<double>(std::clamp(z, 0, 255)) / 255.0;
|
||||
ent.distanceScaleCalibMult = 0.5 + ds01 * 1.0;
|
||||
}
|
||||
|
||||
const QString bgAbs = m_workspace.backgroundAbsolutePath();
|
||||
QImage bg =
|
||||
core::image_file::loadImageLimited(bgAbs, core::image_decode::kWorkspaceMaxPixels);
|
||||
if (!bg.isNull() && bg.format() != QImage::Format_ARGB32_Premultiplied) {
|
||||
@@ -3925,10 +3940,9 @@ cod setPreviewRequested(false);
|
||||
int z = 0;
|
||||
if (m_workspace.hasDepth()) {
|
||||
const QString dpath = m_workspace.depthAbsolutePath();
|
||||
QImage depth8 =
|
||||
core::image_file::loadImageLimited(dpath, core::image_decode::kWorkspaceMaxPixels);
|
||||
const QString bgAbs = m_workspace.backgroundAbsolutePath();
|
||||
const QImage depth8 = core::image_file::loadDepthMapAlignedToBackground(dpath, bgAbs);
|
||||
if (!depth8.isNull()) {
|
||||
depth8 = depth8.convertToFormat(QImage::Format_Grayscale8);
|
||||
const QPointF c = entity_cutout::polygonCentroid(polyWorld);
|
||||
const int xi = static_cast<int>(std::floor(c.x()));
|
||||
const int yi = static_cast<int>(std::floor(c.y()));
|
||||
@@ -4797,14 +4811,12 @@ void MainWindow::showBlackholeContextMenu(const QPoint& globalPos, const QString
|
||||
QMessageBox::warning(this, QStringLiteral("黑洞修复"), QStringLiteral("背景文件无效。"));
|
||||
return;
|
||||
}
|
||||
QImage bg = core::image_file::loadImageLimited(bgAbs, core::image_decode::kWorkspaceMaxPixels);
|
||||
if (bg.isNull()) {
|
||||
QMessageBox::warning(this, QStringLiteral("黑洞修复"), QStringLiteral("读取背景失败。"));
|
||||
QSize bgLogical;
|
||||
if (!core::image_file::probeImagePixelSize(bgAbs, &bgLogical) || !bgLogical.isValid() ||
|
||||
bgLogical.width() < 1 || bgLogical.height() < 1) {
|
||||
QMessageBox::warning(this, QStringLiteral("黑洞修复"), QStringLiteral("无法读取背景尺寸。"));
|
||||
return;
|
||||
}
|
||||
if (bg.format() != QImage::Format_ARGB32_Premultiplied) {
|
||||
bg = bg.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
|
||||
QVector<QPointF> holePolyWorld;
|
||||
for (const auto& e : m_workspace.entities()) {
|
||||
@@ -4830,19 +4842,32 @@ void MainWindow::showBlackholeContextMenu(const QPoint& globalPos, const QString
|
||||
const int marginX = std::max(kMinMargin, int(std::round((holeRect.width() * (kExpandLinear - 1.0)) / 2.0)));
|
||||
const int marginY = std::max(kMinMargin, int(std::round((holeRect.height() * (kExpandLinear - 1.0)) / 2.0)));
|
||||
QRect cropRect = holeRect.adjusted(-marginX, -marginY, marginX, marginY);
|
||||
cropRect = cropRect.intersected(QRect(QPoint(0, 0), bg.size()));
|
||||
cropRect = cropRect.intersected(QRect(QPoint(0, 0), bgLogical));
|
||||
if (!cropRect.isValid() || cropRect.width() <= 1 || cropRect.height() <= 1) {
|
||||
QMessageBox::warning(this, QStringLiteral("黑洞修复"), QStringLiteral("裁剪区域无效。"));
|
||||
return;
|
||||
}
|
||||
|
||||
const QImage cropRgb = bg.copy(cropRect).convertToFormat(QImage::Format_RGB888);
|
||||
QImage mask(cropRect.size(), QImage::Format_Grayscale8);
|
||||
const int maxDec = std::clamp(std::max(cropRect.width(), cropRect.height()), 512, 4096);
|
||||
QImage bg;
|
||||
if (!core::image_file::loadRegionToQImage(bgAbs, cropRect, maxDec, maxDec, &bg) || bg.isNull()) {
|
||||
QMessageBox::warning(this, QStringLiteral("黑洞修复"), QStringLiteral("读取背景失败。"));
|
||||
return;
|
||||
}
|
||||
if (bg.format() != QImage::Format_ARGB32_Premultiplied) {
|
||||
bg = bg.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
|
||||
const QImage cropRgb = bg.convertToFormat(QImage::Format_RGB888);
|
||||
QImage mask(bg.size(), QImage::Format_Grayscale8);
|
||||
mask.fill(0);
|
||||
{
|
||||
QPainter pm(&mask);
|
||||
pm.setRenderHint(QPainter::Antialiasing, true);
|
||||
pm.translate(-cropRect.topLeft());
|
||||
QTransform worldToMask;
|
||||
worldToMask.translate(-cropRect.left(), -cropRect.top());
|
||||
worldToMask.scale(bg.width() / double(cropRect.width()), bg.height() / double(cropRect.height()));
|
||||
pm.setWorldTransform(worldToMask);
|
||||
pm.fillPath(holePath, QColor(255, 255, 255));
|
||||
pm.end();
|
||||
}
|
||||
@@ -5025,15 +5050,20 @@ void MainWindow::showBlackholeContextMenu(const QPoint& globalPos, const QString
|
||||
client->setBaseUrl(QUrl(base));
|
||||
|
||||
QString immediateErr;
|
||||
const QString prompt = dlg.promptText();
|
||||
QString prompt = dlg.promptText();
|
||||
if (prompt.isEmpty()) {
|
||||
prompt = BlackholeResolveDialog::defaultModelInpaintPrompt();
|
||||
}
|
||||
QNetworkReply* reply = client->inpaintAsync(
|
||||
cropPng,
|
||||
maskPng,
|
||||
// LaMa(物体移除 / 擦除)
|
||||
QStringLiteral("lama"),
|
||||
prompt,
|
||||
// 目标是“去掉人物/实体换成背景”,给一个默认 negative prompt 抑制人物结构与杂项
|
||||
QStringLiteral("person, human, face, body, hands, text, watermark, signature, logo"),
|
||||
// 抑制人物与去人常见伪影(中英混合便于通用后端)
|
||||
QStringLiteral(
|
||||
"person, human, face, body, hands, feet, portrait, silhouette, skin, clothing folds, hair, "
|
||||
"shadow, ghosting, blur halo, seam, banding, watermark, text, logo, signature, jpeg artifacts"),
|
||||
// 去人物场景:strength 太低容易“保留人物残影”;适当提高更干净
|
||||
0.72,
|
||||
1024,
|
||||
@@ -5056,7 +5086,8 @@ void MainWindow::showBlackholeContextMenu(const QPoint& globalPos, const QString
|
||||
});
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this,
|
||||
[this, reply, task, client, entityId, bg, cropRect, cropRgb, mask, cropForInpaint]() mutable {
|
||||
[this, reply, task, client, entityId, bg, cropRect, cropRgb, mask, cropForInpaint,
|
||||
holePath]() mutable {
|
||||
const int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
const QByteArray raw = reply->readAll();
|
||||
const auto netErr = reply->error();
|
||||
@@ -5183,29 +5214,78 @@ void MainWindow::showBlackholeContextMenu(const QPoint& globalPos, const QString
|
||||
}
|
||||
}
|
||||
|
||||
// 预览左图:按你的需求,直接把洞区域挖空成纯黑(更直观)
|
||||
const QRectF cropF(cropRect);
|
||||
|
||||
QImage before = cropForInpaint.convertToFormat(QImage::Format_RGB888);
|
||||
{
|
||||
const QImage m8 = mask.convertToFormat(QImage::Format_Grayscale8);
|
||||
for (int y = 0; y < before.height(); ++y) {
|
||||
const uchar* mr = m8.constScanLine(y);
|
||||
uchar* br = before.scanLine(y);
|
||||
for (int x = 0; x < before.width(); ++x) {
|
||||
if (mr[x] == 0) continue;
|
||||
const int idx = x * 3;
|
||||
br[idx + 0] = 0;
|
||||
br[idx + 1] = 0;
|
||||
br[idx + 2] = 0;
|
||||
QPainter pb(&before);
|
||||
pb.setRenderHint(QPainter::Antialiasing, true);
|
||||
QTransform xf;
|
||||
xf.translate(-cropRect.left(), -cropRect.top());
|
||||
xf.scale(before.width() / double(cropRect.width()),
|
||||
before.height() / double(cropRect.height()));
|
||||
pb.setWorldTransform(xf);
|
||||
for (const auto& e : m_workspace.entities()) {
|
||||
if (e.id == entityId) {
|
||||
continue;
|
||||
}
|
||||
if (!e.blackholeVisible || e.cutoutPolygonWorld.size() < 3) {
|
||||
continue;
|
||||
}
|
||||
const QPainterPath op = entity_cutout::pathFromWorldPolygon(e.cutoutPolygonWorld);
|
||||
if (!op.boundingRect().intersects(cropF)) {
|
||||
continue;
|
||||
}
|
||||
pb.fillPath(op, QColor(0, 0, 0));
|
||||
}
|
||||
pb.fillPath(holePath, QColor(0, 0, 0));
|
||||
const qreal w = std::max<qreal>(1.0, 2.0 / std::min(qAbs(xf.m11()), qAbs(xf.m22())));
|
||||
pb.setPen(QPen(QColor(255, 210, 72), w));
|
||||
pb.setBrush(Qt::NoBrush);
|
||||
pb.drawPath(holePath);
|
||||
pb.end();
|
||||
}
|
||||
|
||||
// 修复后:叠画其他黑洞(与画布一致);当前洞仅描边,中间保留模型补全结果。
|
||||
QImage afterView = after.convertToFormat(QImage::Format_RGB888);
|
||||
{
|
||||
QPainter pa(&afterView);
|
||||
pa.setRenderHint(QPainter::Antialiasing, true);
|
||||
QTransform xf;
|
||||
xf.translate(-cropRect.left(), -cropRect.top());
|
||||
xf.scale(afterView.width() / double(cropRect.width()),
|
||||
afterView.height() / double(cropRect.height()));
|
||||
pa.setWorldTransform(xf);
|
||||
for (const auto& e : m_workspace.entities()) {
|
||||
if (e.id == entityId) {
|
||||
continue;
|
||||
}
|
||||
if (!e.blackholeVisible || e.cutoutPolygonWorld.size() < 3) {
|
||||
continue;
|
||||
}
|
||||
const QPainterPath op = entity_cutout::pathFromWorldPolygon(e.cutoutPolygonWorld);
|
||||
if (!op.boundingRect().intersects(cropF)) {
|
||||
continue;
|
||||
}
|
||||
pa.fillPath(op, QColor(0, 0, 0));
|
||||
}
|
||||
const qreal w = std::max<qreal>(1.0, 2.0 / std::min(qAbs(xf.m11()), qAbs(xf.m22())));
|
||||
pa.setPen(QPen(QColor(255, 210, 72), w));
|
||||
pa.setBrush(Qt::NoBrush);
|
||||
pa.drawPath(holePath);
|
||||
pa.end();
|
||||
}
|
||||
|
||||
InpaintPreviewDialog preview(QStringLiteral("预览"), this);
|
||||
preview.setImages(before, after);
|
||||
preview.setImages(before, afterView);
|
||||
if (preview.exec() != QDialog::Accepted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (after.size() != cropRect.size()) {
|
||||
after = after.scaled(cropRect.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
|
||||
const bool ok2 =
|
||||
m_workspace.resolveBlackholeByModelInpaint(entityId, after, cropRect, true);
|
||||
if (!ok2) {
|
||||
|
||||
Reference in New Issue
Block a user