From 87114731aacd1809c5d14f91cb31a34d7d639fba Mon Sep 17 00:00:00 2001 From: renbin Date: Thu, 12 Dec 2024 13:56:22 +0800 Subject: [PATCH] fix: ocr position offset on HiDPI displays - Add devicePixelRatio support to fix text box positioning on HiDPI screens - Remove Image.Tile fillMode for better DPI compatibility - Scale image dimensions based on device pixel ratio Log: Fix ocr position offset on HiDPI displays. Bug: https://pms.uniontech.com/bug-view-275403.html --- src/main.cpp | 5 +- src/qml/ImageDelegate/BaseImageDelegate.qml | 10 +- src/qml/ImageDelegate/NormalImageDelegate.qml | 5 + src/qml/ImageDelegate/ViewDelegateLoader.qml | 20 +-- src/qml/LiveText/LiveBlock.qml | 2 +- src/qml/ThumbnailListView.qml | 7 + src/src/globalcontrol.cpp | 1 + src/src/imagedata/imageinfo.cpp | 12 +- src/src/imagedata/imageprovider.cpp | 33 +++-- src/src/imagedata/imageprovider.h | 1 + src/src/imagedata/pathviewproxymodel.cpp | 47 +++++- src/src/imagedata/thumbnailcache.cpp | 13 ++ src/src/imagedata/thumbnailcache.h | 1 + src/src/ocr/livetextanalyzer.cpp | 53 ++++--- src/src/ocr/livetextanalyzer.h | 3 +- src/src/unionimage/imageutils.cpp | 2 +- src/src/unionimage/unionimage.cpp | 139 ++++-------------- src/src/unionimage/unionimage.h | 2 +- src/src/utils/rotateimagehelper.cpp | 6 +- 19 files changed, 184 insertions(+), 178 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 31d407e74..acd0cc0a6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -120,7 +120,10 @@ int main(int argc, char *argv[]) status.setEnableNavigation(fileControl.isEnableNavigation()); QObject::connect( &status, &GlobalStatus::enableNavigationChanged, [&]() { fileControl.setEnableNavigation(status.enableNavigation()); }); - QObject::connect(&fileControl, &FileControl::imageRenamed, &control, &GlobalControl::renameImage); + QObject::connect(&fileControl, &FileControl::imageRenamed, &control, [&](const QUrl &oldName, const QUrl &newName){ + providerCache->renameImageCache(oldName.toLocalFile(), newName.toLocalFile()); + control.renameImage(oldName, newName); + }); // 文件变更时清理缓存 QObject::connect(&fileControl, &FileControl::imageFileChanged, [&](const QString &fileName) { providerCache->removeImageCache(fileName); diff --git a/src/qml/ImageDelegate/BaseImageDelegate.qml b/src/qml/ImageDelegate/BaseImageDelegate.qml index 33af332fa..7695f27b0 100644 --- a/src/qml/ImageDelegate/BaseImageDelegate.qml +++ b/src/qml/ImageDelegate/BaseImageDelegate.qml @@ -25,8 +25,8 @@ Item { // 图片绘制后是否初始化,Qt6后 Image.Ready 时 PaintedWidth 没有更新,以此标志判断是否执行初始化 property bool inited: false property ImageInputHandler inputHandler: null - // PathView下不再提供 index === IV.GControl.currentIndex - property bool isCurrentImage: parent.PathView.view.currentIndex === model.index + // PathView not provides index === IV.GControl.currentIndex, use ViewDelegateLoader.enabled + property bool isCurrentImage: parent.enabled // 坐标偏移,用于动画效果时调整显示位置 property real offset: 0 // 图片绘制区域到边框的位置 @@ -38,10 +38,10 @@ Item { property int type: IV.Types.NullImage function reset() { - if (targetImage.paintedWidth > 0) { - resetCache(); - } if (targetImage) { + if (targetImage.paintedWidth > 0) { + resetCache(); + } targetImage.rotation = 0; } diff --git a/src/qml/ImageDelegate/NormalImageDelegate.qml b/src/qml/ImageDelegate/NormalImageDelegate.qml index 1ced9d0ad..e084a13e5 100644 --- a/src/qml/ImageDelegate/NormalImageDelegate.qml +++ b/src/qml/ImageDelegate/NormalImageDelegate.qml @@ -12,6 +12,9 @@ BaseImageDelegate { property bool rotationRunning: false function resetSource() { + // check if source rename + updateSource() + // 加载完成,触发动画效果 var temp = image.source; image.source = ""; @@ -48,6 +51,8 @@ BaseImageDelegate { smooth: true source: "image://ImageLoad/" + delegate.source + "#frame_" + delegate.frameIndex width: delegate.width + // TODO: wait for Qt6.8 avoid flickering when image source change + // retainWhileLoading: true onStatusChanged: { if (Image.Ready === image.status && !rotationRunning) { diff --git a/src/qml/ImageDelegate/ViewDelegateLoader.qml b/src/qml/ImageDelegate/ViewDelegateLoader.qml index ad6885eff..a25e0f668 100644 --- a/src/qml/ImageDelegate/ViewDelegateLoader.qml +++ b/src/qml/ImageDelegate/ViewDelegateLoader.qml @@ -9,17 +9,18 @@ Loader { id: pathViewItemLoader property alias frameCount: imageInfo.frameCount - property int frameIndex: model.frameIndex - property url imageSource: model.imageUrl - readonly property int index: model.index + // model.frameIndex + required property int frameIndex + // model.imageUrl + required property url imageUrl function updateLoaderSource() { if (active && imageInfo.delegateSource) { setSource(imageInfo.delegateSource, { - "source": pathViewItemLoader.imageSource, - "type": imageInfo.type, - "frameIndex": pathViewItemLoader.frameIndex - }); + "source": pathViewItemLoader.imageUrl, + "type": imageInfo.type, + "frameIndex": pathViewItemLoader.frameIndex + }); } } @@ -45,7 +46,7 @@ Loader { Binding { property: "source" target: pathViewItemLoader.item - value: pathViewItemLoader.imageSource + value: pathViewItemLoader.imageUrl when: Loader.Ready === pathViewItemLoader.status } @@ -72,7 +73,6 @@ Loader { function checkDelegateSource() { if (IV.ImageInfo.Ready !== status && IV.ImageInfo.Error !== status) { - delegateSource = ""; return; } if (!imageInfo.exists) { @@ -104,7 +104,7 @@ Loader { // WARNING: 由于 Delegate 组件宽度关联的 view.width ,PathView 会计算 Delegate 大小 // Loader 在构造时直接设置图片链接会导致数据提前加载,破坏了延迟加载策略 // 调整机制,不在激活状态的图片信息置为空,在需要加载时设置图片链接 - source: pathViewItemLoader.active ? pathViewItemLoader.imageSource : "" + source: pathViewItemLoader.active ? pathViewItemLoader.imageUrl : "" onDelegateSourceChanged: { updateLoaderSource(); diff --git a/src/qml/LiveText/LiveBlock.qml b/src/qml/LiveText/LiveBlock.qml index e444db5d8..157354441 100644 --- a/src/qml/LiveText/LiveBlock.qml +++ b/src/qml/LiveText/LiveBlock.qml @@ -73,8 +73,8 @@ Rectangle { } Image { + // Note: we need to use default fillMode, to support diff devicePixelRatio (>1.0) anchors.fill: parent - fillMode: Image.Tile source: "image://liveTextAnalyzer/" + Math.random() + "_" + index } diff --git a/src/qml/ThumbnailListView.qml b/src/qml/ThumbnailListView.qml index e312ae02a..6a19c1d9a 100644 --- a/src/qml/ThumbnailListView.qml +++ b/src/qml/ThumbnailListView.qml @@ -350,6 +350,13 @@ Control { } } + Binding { + property: "source" + target: thumbnailItemLoader.item + value: thumbnailItemLoader.imageSource + when: Loader.Ready === thumbnailItemLoader.status + } + IV.ImageInfo { id: imageInfo diff --git a/src/src/globalcontrol.cpp b/src/src/globalcontrol.cpp index af8661dd6..909d5c89c 100644 --- a/src/src/globalcontrol.cpp +++ b/src/src/globalcontrol.cpp @@ -354,6 +354,7 @@ void GlobalControl::renameImage(const QUrl &oldName, const QUrl &newName) submitImageChangeImmediately(); sourceModel->setData(sourceModel->index(index), newName, Types::ImageUrlRole); + viewSourceModel->setData(viewSourceModel->index(viewSourceModel->currentIndex()), newName, Types::ImageUrlRole); if (oldName == currentImage.source()) { // 强制刷新,避免出现重命名为已缓存的删除图片 diff --git a/src/src/imagedata/imageinfo.cpp b/src/src/imagedata/imageinfo.cpp index ac16cbf15..e68c8069a 100644 --- a/src/src/imagedata/imageinfo.cpp +++ b/src/src/imagedata/imageinfo.cpp @@ -29,7 +29,7 @@ class ImageInfoData other->size = this->size; other->frameIndex = this->frameIndex; other->frameCount = this->frameCount; - + other->scale = this->scale; other->x = this->x; other->y = this->y; @@ -84,7 +84,7 @@ class ImageInfoCache : public QObject Q_SIGNAL void imageSizeChanged(const QString &path, int frameIndex); private: - bool aboutToQuit { false }; + bool aboutToQuit{false}; QHash cache; QSet waitSet; QScopedPointer localPoolPtr; @@ -229,7 +229,7 @@ ImageInfoCache::ImageInfoCache() }); } -ImageInfoCache::~ImageInfoCache() { } +ImageInfoCache::~ImageInfoCache() {} /** @return 返回缓存中文件路径为 \a path 和帧索引为 \a frameIndex 的缓存数据 @@ -282,10 +282,10 @@ void ImageInfoCache::loadFinished(const QString &path, int frameIndex, ImageInfo ThumbnailCache::Key key = ThumbnailCache::toFindKey(path, frameIndex); - waitSet.remove(key); - if (data) { + if (data && waitSet.contains(key)) { cache.insert(key, data); } + waitSet.remove(key); Q_EMIT imageDataChanged(path, frameIndex); } @@ -337,7 +337,7 @@ ImageInfo::ImageInfo(const QUrl &source, QObject *parent) setSource(source); } -ImageInfo::~ImageInfo() { } +ImageInfo::~ImageInfo() {} ImageInfo::Status ImageInfo::status() const { diff --git a/src/src/imagedata/imageprovider.cpp b/src/src/imagedata/imageprovider.cpp index adc75f648..c0218ac5b 100644 --- a/src/src/imagedata/imageprovider.cpp +++ b/src/src/imagedata/imageprovider.cpp @@ -87,7 +87,7 @@ AsyncImageResponse::AsyncImageResponse(AsyncImageProvider *p, const QString &i, setAutoDelete(false); } -AsyncImageResponse::~AsyncImageResponse() { } +AsyncImageResponse::~AsyncImageResponse() {} QQuickTextureFactory *AsyncImageResponse::textureFactory() const { @@ -106,6 +106,7 @@ void AsyncImageResponse::run() // 判断缓存中是否存在图片 image = provider->imageCache.get(tempPath, frameIndex); + if (image.isNull()) { if (frameIndex) { image = readMultiImage(tempPath, frameIndex); @@ -129,9 +130,9 @@ void AsyncImageResponse::run() @class ProviderCache @brief 图像加载器缓存,存储最近的图像数据并处理旋转等操作 */ -ProviderCache::ProviderCache() { } +ProviderCache::ProviderCache() {} -ProviderCache::~ProviderCache() { } +ProviderCache::~ProviderCache() {} /** @brief 对缓存的 \a imagePath 图片执行旋转 \a angle 的操作。 @@ -180,16 +181,22 @@ void ProviderCache::rotateImageCached(int angle, const QString &imagePath, int f void ProviderCache::removeImageCache(const QString &imagePath) { // 直接缓存的图像信息较少,遍历查询是否包含对应的图片 - QList keys; - QMutexLocker _locker(&mutex); - keys = imageCache.keys(); - _locker.unlock(); - + QList keys = imageCache.keys(); for (const ThumbnailCache::Key &key : keys) { if (key.first == imagePath) { - _locker.relock(); imageCache.remove(key.first, key.second); - _locker.unlock(); + } + } +} + +void ProviderCache::renameImageCache(const QString &oldPath, const QString &newPath) +{ + // 直接缓存的图像信息较少,遍历查询是否包含对应的图片 + QList keys = imageCache.keys(); + for (const ThumbnailCache::Key &key : keys) { + if (key.first == oldPath) { + QImage image = imageCache.take(key.first, key.second); + imageCache.add(newPath, key.second, image); } } } @@ -224,7 +231,7 @@ AsyncImageProvider::AsyncImageProvider() imageCache.setMaxCost(4); } -AsyncImageProvider::~AsyncImageProvider() { } +AsyncImageProvider::~AsyncImageProvider() {} /** @brief 请求图像加载并返回应答,当图像加载成功时,通过接收信号进行实际图像的加载 @@ -259,7 +266,7 @@ ImageProvider::ImageProvider() { } -ImageProvider::~ImageProvider() { } +ImageProvider::~ImageProvider() {} /** @brief 外部请求图像文件中指定帧的图像,指定帧号通过传入的 \a id 进行区分。 @@ -316,7 +323,7 @@ ThumbnailProvider::ThumbnailProvider() { } -ThumbnailProvider::~ThumbnailProvider() { } +ThumbnailProvider::~ThumbnailProvider() {} /** @brief 外部请求图像文件中指定帧的图像,指定帧号通过传入的 \a id 进行区分。 diff --git a/src/src/imagedata/imageprovider.h b/src/src/imagedata/imageprovider.h index 221b101c9..cb405b6af 100644 --- a/src/src/imagedata/imageprovider.h +++ b/src/src/imagedata/imageprovider.h @@ -20,6 +20,7 @@ class ProviderCache void rotateImageCached(int angle, const QString &imagePath, int frameIndex = 0); void removeImageCache(const QString &imagePath); + void renameImageCache(const QString &oldPath, const QString &newPath); void clearCache(); virtual void preloadImage(const QString &filePath); diff --git a/src/src/imagedata/pathviewproxymodel.cpp b/src/src/imagedata/pathviewproxymodel.cpp index 362179291..49119387f 100644 --- a/src/src/imagedata/pathviewproxymodel.cpp +++ b/src/src/imagedata/pathviewproxymodel.cpp @@ -61,12 +61,49 @@ QVariant PathViewProxyModel::data(const QModelIndex &index, int role) const return {}; } -bool PathViewProxyModel::setData(const QModelIndex &index, const QVariant &value, int role) +bool PathViewProxyModel::setData(const QModelIndex &idx, const QVariant &value, int role) { - // Do nothing - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role) + if (!checkIndex(idx, CheckIndexOption::ParentIsInvalid | CheckIndexOption::IndexIsValid)) { + return false; + } + + auto infoPtr = indexQueue[idx.row()]; + switch (role) { + case Types::ImageUrlRole: + if (infoPtr) { + QUrl oldUrl = infoPtr->url; + QUrl newUrl = value.toUrl(); + + infoPtr->url = newUrl; + Q_EMIT dataChanged(idx, idx); + + // update previous and next + for (int previous = idx.row() - 1; previous >= 0; --previous) { + if (auto preInfo = indexQueue[previous]) { + if (preInfo->url == oldUrl) { + preInfo->url = newUrl; + QModelIndex notifyIdx = index(previous, idx.column()); + Q_EMIT dataChanged(notifyIdx, notifyIdx); + } + } + } + + for (int next = idx.row() + 1; next < indexQueue.size(); ++next) { + if (auto nextInfo = indexQueue[next]) { + if (nextInfo->url == oldUrl) { + nextInfo->url = newUrl; + QModelIndex notifyIdx = index(next, idx.column()); + Q_EMIT dataChanged(notifyIdx, notifyIdx); + } + } + } + + } + return true; + default: + break; + } + return false; } diff --git a/src/src/imagedata/thumbnailcache.cpp b/src/src/imagedata/thumbnailcache.cpp index 1514033a7..f02fb2003 100644 --- a/src/src/imagedata/thumbnailcache.cpp +++ b/src/src/imagedata/thumbnailcache.cpp @@ -42,11 +42,23 @@ QImage ThumbnailCache::get(const QString &path, int frameIndex) } } +QImage ThumbnailCache::take(const QString &path, int frameIndex) +{ + QMutexLocker _locker(&mutex); + QImage *image = cache.take(toFindKey(path, frameIndex)); + if (image) { + return *image; + } else { + return QImage(); + } +} + /** @brief 添加文件路径为 \a path 和图片帧索引为 \a frameIndex 的缩略图 */ void ThumbnailCache::add(const QString &path, int frameIndex, const QImage &image) { + // TODO: not need reallocate QMutexLocker _locker(&mutex); cache.insert(toFindKey(path, frameIndex), new QImage(image)); } @@ -83,6 +95,7 @@ void ThumbnailCache::clear() */ QList ThumbnailCache::keys() { + QMutexLocker _locker(&mutex); return cache.keys(); } diff --git a/src/src/imagedata/thumbnailcache.h b/src/src/imagedata/thumbnailcache.h index 23f59415b..a87a87648 100644 --- a/src/src/imagedata/thumbnailcache.h +++ b/src/src/imagedata/thumbnailcache.h @@ -21,6 +21,7 @@ class ThumbnailCache bool contains(const QString &path, int frameIndex = 0); QImage get(const QString &path, int frameIndex = 0); + QImage take(const QString &path, int frameIndex = 0); void add(const QString &path, int frameIndex, const QImage &image); void remove(const QString &path, int frameIndex); void setMaxCost(int maxCost); diff --git a/src/src/ocr/livetextanalyzer.cpp b/src/src/ocr/livetextanalyzer.cpp index 0f7c5521d..5506c5cb7 100644 --- a/src/src/ocr/livetextanalyzer.cpp +++ b/src/src/ocr/livetextanalyzer.cpp @@ -5,6 +5,8 @@ #include "livetextanalyzer.h" #include +#include +#include #include #include @@ -20,23 +22,37 @@ LiveTextAnalyzer::LiveTextAnalyzer(QObject *parent) // 退出时终止文本识别 connect(qApp, &QCoreApplication::aboutToQuit, this, &LiveTextAnalyzer::breakAnalyze); + + if (QScreen *screen = qApp->primaryScreen()) { + pixelRatio = screen->devicePixelRatio(); + } } void LiveTextAnalyzer::setImage(const QImage &image) { imageCache = image; + QImage image_copy = image.convertToFormat(QImage::Format_RGB888); - ocrDriver->setMatrix(image_copy.height(), image_copy.width(), image_copy.bits(), - static_cast(image_copy.bytesPerLine()), DeepinOCRPlugin::PixelType::Pixel_RGB); + // If the device pixel ratio is > 1, we need to reset the width and height to get the actual position. + if (pixelRatio > 1) { + image_copy = image_copy.scaled( + image.width() / pixelRatio, image.height() / pixelRatio, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + } + + ocrDriver->setMatrix(image_copy.height(), + image_copy.width(), + image_copy.bits(), + static_cast(image_copy.bytesPerLine()), + DeepinOCRPlugin::PixelType::Pixel_RGB); } void LiveTextAnalyzer::analyze(const QString &token) { - //此处使用token来标记本次识别的目标,后续的识别结果也随token发出 - //外部调用的时候也凭借收到的token判断是否采用此次的识别结果 - //以此来解决QML的信号延迟问题,但仅降低此问题的复现概率,没有完全解决 + // 此处使用token来标记本次识别的目标,后续的识别结果也随token发出 + // 外部调用的时候也凭借收到的token判断是否采用此次的识别结果 + // 以此来解决QML的信号延迟问题,但仅降低此问题的复现概率,没有完全解决 QtConcurrent::run([this, token]() { - while(ocrDriver->isRunning()) {}; //等待之前的分析结束 + while (ocrDriver->isRunning()) { }; // 等待之前的分析结束 emit analyzeFinished(ocrDriver->analyze(), token); }); } @@ -53,9 +69,9 @@ QVariant LiveTextAnalyzer::liveBlock() const auto boxes = ocrDriver->getTextBoxes(); QList result; - for(auto &box : boxes) { + for (auto &box : boxes) { QList temp; - for(size_t i = 0;i != box.points.size();++i) { + for (size_t i = 0; i != box.points.size(); ++i) { temp.push_back(box.points[i].first); temp.push_back(box.points[i].second); } @@ -68,7 +84,7 @@ QVariant LiveTextAnalyzer::liveBlock() const QVariant LiveTextAnalyzer::charBox(int blockIndex) const { - if(static_cast(blockIndex) >= ocrDriver->getTextBoxes().size()) { + if (static_cast(blockIndex) >= ocrDriver->getTextBoxes().size()) { return QVariant(); } @@ -78,7 +94,7 @@ QVariant LiveTextAnalyzer::charBox(int blockIndex) const float base = boxes[0].points[0].first; result.push_back(0); - for(auto &box : boxes) { + for (auto &box : boxes) { result.push_back(box.points[1].first - base); } @@ -87,7 +103,7 @@ QVariant LiveTextAnalyzer::charBox(int blockIndex) const QString LiveTextAnalyzer::textResult(int blockIndex, int startIndex, int len) const { - if(static_cast(blockIndex) >= ocrDriver->getTextBoxes().size() || startIndex < 0 || len <= 0) { + if (static_cast(blockIndex) >= ocrDriver->getTextBoxes().size() || startIndex < 0 || len <= 0) { return ""; } @@ -95,25 +111,26 @@ QString LiveTextAnalyzer::textResult(int blockIndex, int startIndex, int len) co return fullStr.mid(startIndex, len); } -//格式:random_index +// 格式:random_index QImage LiveTextAnalyzer::requestImage(const QString &id, QSize *size, const QSize &requestedSize) { auto startIndex = id.indexOf("_") + 1; size_t index = id.mid(startIndex).toUInt(); - if(index >= ocrDriver->getTextBoxes().size()) { + if (index >= ocrDriver->getTextBoxes().size()) { return QImage(); } + // Combined with Image fileMode, show the original image auto box = ocrDriver->getTextBoxes()[index]; - QRect rect(QPoint(static_cast(box.points[0].first), static_cast(box.points[0].second)), - QPoint(static_cast(box.points[2].first), static_cast(box.points[2].second))); + QRect rect(QPoint(static_cast(box.points[0].first * pixelRatio), static_cast(box.points[0].second * pixelRatio)), + QPoint(static_cast(box.points[2].first * pixelRatio), static_cast(box.points[2].second * pixelRatio))); + QImage image = imageCache.copy(rect); - if(size != nullptr) - { + if (size != nullptr) { *size = image.size(); } - if(requestedSize.width() > 0 && requestedSize.height() > 0) { + if (requestedSize.width() > 0 && requestedSize.height() > 0) { return image.scaled(requestedSize); } else { return image; diff --git a/src/src/ocr/livetextanalyzer.h b/src/src/ocr/livetextanalyzer.h index c1b53b477..6163e50c1 100644 --- a/src/src/ocr/livetextanalyzer.h +++ b/src/src/ocr/livetextanalyzer.h @@ -9,7 +9,7 @@ #include namespace DeepinOCRPlugin { - class DeepinOCRDriver; +class DeepinOCRDriver; } class LiveTextAnalyzer : public QQuickImageProvider @@ -36,4 +36,5 @@ public slots: private: DeepinOCRPlugin::DeepinOCRDriver *ocrDriver; QImage imageCache; + qreal pixelRatio{1.0}; // for diff devicePixelRatio }; diff --git a/src/src/unionimage/imageutils.cpp b/src/src/unionimage/imageutils.cpp index 6945e0d37..c87e68326 100755 --- a/src/src/unionimage/imageutils.cpp +++ b/src/src/unionimage/imageutils.cpp @@ -123,7 +123,7 @@ bool rotate(const QString &path, int degree) { /*lmh0724使用USE_UNIONIMAGE*/ QString erroMsg; - return LibUnionImage_NameSpace::rotateImageFIle(degree, path, erroMsg); + return LibUnionImage_NameSpace::rotateImageFile(degree, path, erroMsg); } /*! diff --git a/src/src/unionimage/unionimage.cpp b/src/src/unionimage/unionimage.cpp index bec4259a5..f675c8f3e 100644 --- a/src/src/unionimage/unionimage.cpp +++ b/src/src/unionimage/unionimage.cpp @@ -229,7 +229,6 @@ UNIONIMAGESHARED_EXPORT QString unionImageVersion() return ver; } -QString PrivateDetectImageFormat(const QString &filepath); UNIONIMAGESHARED_EXPORT bool loadStaticImageFromFile(const QString &path, QImage &res, QString &errorMsg, const QString &format_bar) { QFileInfo file_info(path); @@ -258,7 +257,7 @@ UNIONIMAGESHARED_EXPORT bool loadStaticImageFromFile(const QString &path, QImage res_qt = reader.read(); if (res_qt.isNull()) { //try old loading method - QString format = PrivateDetectImageFormat(path); + QString format = detectImageFormat(path); QImageReader readerF(path, format.toLatin1()); QImage try_res; readerF.setAutoTransform(true); @@ -300,57 +299,57 @@ UNIONIMAGESHARED_EXPORT QString detectImageFormat(const QString &path) // Check bmp file. if (data.startsWith("BM")) { - return "bmp"; + return "BMP"; } // Check dds file. if (data.startsWith("DDS")) { - return "dds"; + return "DDS"; } // Check gif file. if (data.startsWith("GIF8")) { - return "gif"; + return "GIF"; } // Check Max OS icons file. if (data.startsWith("icns")) { - return "icns"; + return "ICNS"; } // Check jpeg file. if (data.startsWith("\xff\xd8")) { - return "jpg"; + return "JPG"; } // Check mng file. if (data.startsWith("\x8a\x4d\x4e\x47\x0d\x0a\x1a\x0a")) { - return "mng"; + return "MNG"; } // Check net pbm file (BitMap). if (data.startsWith("P1") || data.startsWith("P4")) { - return "pbm"; + return "PBM"; } // Check pgm file (GrayMap). if (data.startsWith("P2") || data.startsWith("P5")) { - return "pgm"; + return "PGM"; } // Check ppm file (PixMap). if (data.startsWith("P3") || data.startsWith("P6")) { - return "ppm"; + return "PPM"; } // Check png file. if (data.startsWith("\x89PNG\x0d\x0a\x1a\x0a")) { - return "png"; + return "PNG"; } // Check svg file. if (data.indexOf(" -1) { - return "svg"; + return "SVG"; } // TODO(xushaohua): tga file is not supported yet. @@ -358,28 +357,28 @@ UNIONIMAGESHARED_EXPORT QString detectImageFormat(const QString &path) // Check tiff file. if (data.startsWith("MM\x00\x2a") || data.startsWith("II\x2a\x00")) { // big-endian, little-endian. - return "tiff"; + return "TIFF"; } // TODO(xushaohua): Support wbmp file. // Check webp file. if (data.startsWith("RIFFr\x00\x00\x00WEBPVP")) { - return "webp"; + return "WEBP"; } // Check xbm file. if (data.indexOf("#define max_width ") > -1 && data.indexOf("#define max_height ") > -1) { - return "xbm"; + return "XBM"; } // Check xpm file. if (data.startsWith("/* XPM */")) { - return "xpm"; + return "XPM"; } - - return ""; + QFileInfo info(path); + return info.suffix().toUpper(); } UNIONIMAGESHARED_EXPORT bool isNoneQImage(const QImage &qi) @@ -446,7 +445,7 @@ QImage adjustImageToRealPosition(const QImage &image, int orientation) return result; } -UNIONIMAGESHARED_EXPORT bool rotateImageFIle(int angel, const QString &path, QString &erroMsg, const QString &targetPath) +UNIONIMAGESHARED_EXPORT bool rotateImageFile(int angel, const QString &path, QString &erroMsg, const QString &targetPath) { if (angel % 90 != 0) { erroMsg = "unsupported angel"; @@ -497,14 +496,18 @@ UNIONIMAGESHARED_EXPORT bool rotateImageFIle(int angel, const QString &path, QSt QTransform rotatematrix; rotatematrix.rotate(angel); image_copy = image_copy.transformed(rotatematrix, Qt::SmoothTransformation); - if (image_copy.save(savePath, format.toLatin1().data(), SAVE_QUAITY_VALUE)) + if (image_copy.save(savePath, format.toLatin1().data(), SAVE_QUAITY_VALUE)) { return true; - else + } else { + erroMsg = "save image failed"; return false; + } } erroMsg = "rotate by qt failed"; return false; } + + erroMsg = "not support rotate image format: " + format; return false; } @@ -674,98 +677,6 @@ imageViewerSpace::PathType getPathType(const QString &imagepath) return type; } -QString PrivateDetectImageFormat(const QString &filepath) -{ - QFile file(filepath); - if (!file.open(QIODevice::ReadOnly)) { - return ""; - } - - const QByteArray data = file.read(1024); - - // Check bmp file. - if (data.startsWith("BM")) { - return "bmp"; - } - - // Check dds file. - if (data.startsWith("DDS")) { - return "dds"; - } - - // Check gif file. - if (data.startsWith("GIF8")) { - return "gif"; - } - - // Check Max OS icons file. - if (data.startsWith("icns")) { - return "icns"; - } - - // Check jpeg file. - if (data.startsWith("\xff\xd8")) { - return "jpg"; - } - - // Check mng file. - if (data.startsWith("\x8a\x4d\x4e\x47\x0d\x0a\x1a\x0a")) { - return "mng"; - } - - // Check net pbm file (BitMap). - if (data.startsWith("P1") || data.startsWith("P4")) { - return "pbm"; - } - - // Check pgm file (GrayMap). - if (data.startsWith("P2") || data.startsWith("P5")) { - return "pgm"; - } - - // Check ppm file (PixMap). - if (data.startsWith("P3") || data.startsWith("P6")) { - return "ppm"; - } - - // Check png file. - if (data.startsWith("\x89PNG\x0d\x0a\x1a\x0a")) { - return "png"; - } - - // Check svg file. - if (data.indexOf(" -1) { - return "svg"; - } - - // TODO(xushaohua): tga file is not supported yet. - - // Check tiff file. - if (data.startsWith("MM\x00\x2a") || data.startsWith("II\x2a\x00")) { - // big-endian, little-endian. - return "tiff"; - } - - // TODO(xushaohua): Support wbmp file. - - // Check webp file. - if (data.startsWith("RIFFr\x00\x00\x00WEBPVP")) { - return "webp"; - } - - // Check xbm file. - if (data.indexOf("#define max_width ") > -1 && - data.indexOf("#define max_height ") > -1) { - return "xbm"; - } - - // Check xpm file. - if (data.startsWith("/* XPM */")) { - return "xpm"; - } - return ""; -} - }; diff --git a/src/src/unionimage/unionimage.h b/src/src/unionimage/unionimage.h index f09a29a14..63d16f954 100644 --- a/src/src/unionimage/unionimage.h +++ b/src/src/unionimage/unionimage.h @@ -123,7 +123,7 @@ UNIONIMAGESHARED_EXPORT bool rotateImage(int angel, QImage &image); * 当不需要获取旋转图片的结果或者只有文件地址时调用该函数 * 失败时会将错误信息写入erroMsg */ -UNIONIMAGESHARED_EXPORT bool rotateImageFIle(int angel, const QString &path, QString &erroMsg, const QString &targetPath = {}); +UNIONIMAGESHARED_EXPORT bool rotateImageFile(int angel, const QString &path, QString &erroMsg, const QString &targetPath = {}); /** * @brief rotateImageFIle diff --git a/src/src/utils/rotateimagehelper.cpp b/src/src/utils/rotateimagehelper.cpp index e6d9b4896..2082d2de5 100644 --- a/src/src/utils/rotateimagehelper.cpp +++ b/src/src/utils/rotateimagehelper.cpp @@ -121,15 +121,17 @@ bool RotateImageHelper::rotateImageImpl(const QString &cachePath, const QString { // 拷贝文件到目录 if (!QFile::exists(cachePath)) { - if (!QFile::copy(path, cachePath)) + if (!QFile::copy(path, cachePath)) { + qWarning() << "Copy rotate file to cache failed!"; return false; + } } // 操作前标记动作 Q_EMIT RotateImageHelper::instance()->recordRotateImage(path); QString errorMsg; - bool ret = LibUnionImage_NameSpace::rotateImageFIle(angle, cachePath, errorMsg, path); + bool ret = LibUnionImage_NameSpace::rotateImageFile(angle, cachePath, errorMsg, path); // NOTE:处理结束,过滤旋转操作文件更新,旋转图像已在软件中缓存且旋转状态同步,不再从文件中更新读取 // 保存文件后发送图片更新更新信号,通过监控文件变更触发。文件更新可能滞后,延时一定时间处理