117 lines
4.1 KiB
C++
117 lines
4.1 KiB
C++
#include "image/ImageFileLoader.h"
|
|
|
|
#include "image/ImageDecodeConfig.h"
|
|
#include "large_image/VipsBackend.h"
|
|
|
|
#include <QImageReader>
|
|
|
|
namespace core {
|
|
namespace image_file {
|
|
|
|
bool probeImagePixelSize(const QString& absolutePath, QSize* outSize) {
|
|
if (!outSize || absolutePath.isEmpty()) {
|
|
return false;
|
|
}
|
|
if (VipsBackend::isAvailable() && VipsBackend::probeSize(absolutePath, outSize)) {
|
|
return outSize->isValid() && outSize->width() > 0 && outSize->height() > 0;
|
|
}
|
|
core::image_decode::prepareLargeImageReader();
|
|
QImageReader reader(absolutePath);
|
|
reader.setAutoTransform(true);
|
|
*outSize = reader.size();
|
|
return outSize->isValid() && outSize->width() > 0 && outSize->height() > 0;
|
|
}
|
|
|
|
QImage loadImageLimited(const QString& absolutePath, qint64 maxPixelBudget) {
|
|
if (absolutePath.isEmpty()) {
|
|
return {};
|
|
}
|
|
QImage viaVips;
|
|
if (VipsBackend::isAvailable() &&
|
|
VipsBackend::loadThumbnailQImage(absolutePath, maxPixelBudget, &viaVips) && !viaVips.isNull()) {
|
|
return viaVips;
|
|
}
|
|
core::image_decode::prepareLargeImageReader();
|
|
QImageReader reader(absolutePath);
|
|
reader.setAutoTransform(true);
|
|
core::image_decode::downscaleReaderIfExceeds(reader, 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) {
|
|
return false;
|
|
}
|
|
out->detach();
|
|
*out = QImage();
|
|
if (VipsBackend::isAvailable() &&
|
|
VipsBackend::loadRegionToQImage(absolutePath, rectLogical, maxOutputWidth, maxOutputHeight, out) &&
|
|
!out->isNull()) {
|
|
return true;
|
|
}
|
|
QSize logical;
|
|
if (!probeImagePixelSize(absolutePath, &logical)) {
|
|
return false;
|
|
}
|
|
const QRect r = rectLogical.intersected(QRect(0, 0, logical.width(), logical.height()));
|
|
if (r.isEmpty()) {
|
|
return false;
|
|
}
|
|
QImage full = loadImageLimited(absolutePath, core::image_decode::kWorkspaceMaxPixels);
|
|
if (full.isNull()) {
|
|
return false;
|
|
}
|
|
const QRect r2 = core::image_decode::mapRectBetweenSizes(r, logical, full.size());
|
|
QImage piece = full.copy(r2);
|
|
if (piece.isNull()) {
|
|
return false;
|
|
}
|
|
// 与 vips 路径保持一致:输出永不超过 maxOutput*,避免后续绘制阶段二次缩放导致明显“发糊”。
|
|
if (piece.width() > maxOutputWidth || piece.height() > maxOutputHeight) {
|
|
piece = piece.scaled(QSize(maxOutputWidth, maxOutputHeight), Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
|
}
|
|
*out = piece;
|
|
return !out->isNull();
|
|
}
|
|
|
|
bool loadRegionToQImageExact(const QString& absolutePath, const QRect& rectLogical, QImage* out) {
|
|
if (!out || absolutePath.isEmpty()) {
|
|
return false;
|
|
}
|
|
out->detach();
|
|
*out = QImage();
|
|
QSize logical;
|
|
if (!probeImagePixelSize(absolutePath, &logical)) {
|
|
return false;
|
|
}
|
|
const QRect r = rectLogical.intersected(QRect(0, 0, logical.width(), logical.height()));
|
|
if (r.isEmpty()) {
|
|
return false;
|
|
}
|
|
// 1:1 输出:maxOutput 设为 region 本身大小,避免 vips/Qt 管线自动缩放导致坐标不一致。
|
|
const int w = std::max(1, r.width());
|
|
const int h = std::max(1, r.height());
|
|
return loadRegionToQImage(absolutePath, r, w, h, out);
|
|
}
|
|
|
|
} // namespace image_file
|
|
} // namespace core
|