update
This commit is contained in:
@@ -38,6 +38,23 @@ QImage loadImageLimited(const QString& absolutePath, qint64 maxPixelBudget) {
|
||||
return reader.read();
|
||||
}
|
||||
|
||||
QImage loadDepthMapAlignedToBackground(const QString& depthAbsolutePath, const QString& backgroundAbsolutePath) {
|
||||
if (depthAbsolutePath.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
QImage g8 = loadImageLimited(depthAbsolutePath, core::image_decode::kWorkspaceMaxPixels);
|
||||
if (g8.isNull()) {
|
||||
return {};
|
||||
}
|
||||
g8 = g8.convertToFormat(QImage::Format_Grayscale8);
|
||||
QSize logical;
|
||||
if (!backgroundAbsolutePath.isEmpty() && probeImagePixelSize(backgroundAbsolutePath, &logical) &&
|
||||
logical.isValid() && logical.width() > 0 && logical.height() > 0 && g8.size() != logical) {
|
||||
g8 = g8.scaled(logical, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
return g8;
|
||||
}
|
||||
|
||||
bool loadRegionToQImage(const QString& absolutePath, const QRect& rectLogical, int maxOutputWidth, int maxOutputHeight,
|
||||
QImage* out) {
|
||||
if (!out || absolutePath.isEmpty() || maxOutputWidth < 32 || maxOutputHeight < 32) {
|
||||
|
||||
@@ -16,6 +16,11 @@ namespace image_file {
|
||||
/// 统一大图解码管线:libvips(可用)按像素预算缩小后再解码为 QImage,否则 Qt。
|
||||
[[nodiscard]] QImage loadImageLimited(const QString& absolutePath, qint64 maxPixelBudget);
|
||||
|
||||
/// 加载深度图并按背景图的逻辑像素尺寸对齐(与 probeImagePixelSize 一致)。
|
||||
/// 解决「背景走 vips 元数据为全尺寸、深度仍按像素预算降采样」时世界坐标采样错位。
|
||||
[[nodiscard]] QImage loadDepthMapAlignedToBackground(const QString& depthAbsolutePath,
|
||||
const QString& backgroundAbsolutePath);
|
||||
|
||||
/// 仅解码源图中矩形区域(逻辑像素坐标);超过 maxOutput* 则缩放该区域。
|
||||
/// libvips 可用时走随机访问裁剪;否则整图降采样回退后再拷贝矩形。
|
||||
[[nodiscard]] bool loadRegionToQImage(const QString& absolutePath, const QRect& rectLogical, int maxOutputWidth,
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <QSet>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QTransform>
|
||||
#include <QPolygonF>
|
||||
#include <QRect>
|
||||
|
||||
@@ -2275,41 +2276,64 @@ bool ProjectWorkspace::resolveBlackholeByCopyBackground(const QString& id, const
|
||||
}
|
||||
const QImage srcSnapshot = bg;
|
||||
|
||||
QPainterPath holePath;
|
||||
holePath.addPolygon(QPolygonF(ent.cutoutPolygonWorld));
|
||||
holePath.closeSubpath();
|
||||
const QRect targetRect = holePath.boundingRect().toAlignedRect().intersected(QRect(QPoint(0, 0), bg.size()));
|
||||
if (!targetRect.isValid() || targetRect.width() <= 0 || targetRect.height() <= 0) {
|
||||
QSize logicalSz;
|
||||
if (!image_file::probeImagePixelSize(bgAbs, &logicalSz) || !logicalSz.isValid() || logicalSz.width() < 1 ||
|
||||
logicalSz.height() < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QRect srcRect(targetRect.topLeft() + sourceOffsetPx, targetRect.size());
|
||||
if (srcRect.left() < 0) srcRect.moveLeft(0);
|
||||
if (srcRect.top() < 0) srcRect.moveTop(0);
|
||||
if (srcRect.right() >= bg.width()) srcRect.moveRight(bg.width() - 1);
|
||||
if (srcRect.bottom() >= bg.height()) srcRect.moveBottom(bg.height() - 1);
|
||||
srcRect = srcRect.intersected(QRect(QPoint(0, 0), bg.size()));
|
||||
if (srcRect.width() != targetRect.width() || srcRect.height() != targetRect.height()) {
|
||||
QPainterPath holePathWorld;
|
||||
holePathWorld.addPolygon(QPolygonF(ent.cutoutPolygonWorld));
|
||||
holePathWorld.closeSubpath();
|
||||
const QRect targetWorld =
|
||||
holePathWorld.boundingRect().toAlignedRect().intersected(QRect(0, 0, logicalSz.width(), logicalSz.height()));
|
||||
if (!targetWorld.isValid() || targetWorld.width() <= 0 || targetWorld.height() <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QRect srcWorld(targetWorld.topLeft() + sourceOffsetPx, targetWorld.size());
|
||||
if (srcWorld.left() < 0) srcWorld.moveLeft(0);
|
||||
if (srcWorld.top() < 0) srcWorld.moveTop(0);
|
||||
if (srcWorld.right() >= logicalSz.width()) srcWorld.moveRight(logicalSz.width() - 1);
|
||||
if (srcWorld.bottom() >= logicalSz.height()) srcWorld.moveBottom(logicalSz.height() - 1);
|
||||
srcWorld = srcWorld.intersected(QRect(0, 0, logicalSz.width(), logicalSz.height()));
|
||||
if (srcWorld.width() != targetWorld.width() || srcWorld.height() != targetWorld.height()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const qreal sx = bg.width() / qreal(logicalSz.width());
|
||||
const qreal sy = bg.height() / qreal(logicalSz.height());
|
||||
QTransform worldToBg;
|
||||
worldToBg.scale(sx, sy);
|
||||
|
||||
const QRect targetImg =
|
||||
worldToBg.mapRect(QRectF(targetWorld)).toAlignedRect().intersected(QRect(0, 0, bg.width(), bg.height()));
|
||||
const QRect srcImg =
|
||||
worldToBg.mapRect(QRectF(srcWorld)).toAlignedRect().intersected(QRect(0, 0, bg.width(), bg.height()));
|
||||
if (!targetImg.isValid() || !srcImg.isValid() || targetImg.width() != srcImg.width() ||
|
||||
targetImg.height() != srcImg.height()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const QPainterPath holePathImg = worldToBg.map(holePathWorld);
|
||||
|
||||
{
|
||||
QPainter p(&bg);
|
||||
p.setRenderHint(QPainter::Antialiasing, true);
|
||||
p.setClipPath(holePath);
|
||||
p.drawImage(targetRect.topLeft(), srcSnapshot, srcRect);
|
||||
p.setClipPath(holePathImg);
|
||||
p.drawImage(targetImg.topLeft(), srcSnapshot, srcImg);
|
||||
p.end();
|
||||
}
|
||||
|
||||
const QImage patch = bg.copy(targetRect);
|
||||
const QImage patch = bg.copy(targetImg);
|
||||
const auto before = m_project.entities();
|
||||
QString overlayRel;
|
||||
if (!writeBlackholeOverlayPng(m_projectDir, id, ents[hit].blackholeOverlayPath, patch, targetRect,
|
||||
if (!writeBlackholeOverlayPng(m_projectDir, id, ents[hit].blackholeOverlayPath, patch, targetWorld,
|
||||
&overlayRel)) {
|
||||
return false;
|
||||
}
|
||||
ents[hit].blackholeOverlayPath = overlayRel;
|
||||
ents[hit].blackholeOverlayRect = targetRect;
|
||||
ents[hit].blackholeOverlayRect = targetWorld;
|
||||
ents[hit].blackholeVisible = hideBlackholeAfterFill ? false : ents[hit].blackholeVisible;
|
||||
if (ents[hit].blackholeId.isEmpty()) {
|
||||
ents[hit].blackholeId = QStringLiteral("blackhole-%1").arg(ents[hit].id);
|
||||
|
||||
Reference in New Issue
Block a user