refactor: improve image loading and handling in ImageData and ImagesCarousel
This commit is contained in:
+34
-11
@@ -1,34 +1,56 @@
|
||||
/*
|
||||
* @Author: Uyanide pywang0608@foxmail.com
|
||||
* @Date: 2025-11-30 20:32:27
|
||||
* @LastEditTime: 2025-11-30 23:07:52
|
||||
* @LastEditTime: 2026-01-14 23:31:41
|
||||
* @Description: Image item widget for displaying an image.
|
||||
*/
|
||||
#include "image_item.h"
|
||||
|
||||
#include <QImageReader>
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
using namespace GeneralLogger;
|
||||
|
||||
ImageData* ImageData::create(const QString& p, const int initWidth, const int initHeight) {
|
||||
ImageData* data = new ImageData(p);
|
||||
data->image = new QImage();
|
||||
|
||||
if (!data->image.load(p)) {
|
||||
QImageReader reader(p);
|
||||
if (!reader.canRead()) {
|
||||
error(QString("Failed to load image from path: %1").arg(p));
|
||||
delete data;
|
||||
return nullptr;
|
||||
}
|
||||
const QSize targetSize(initWidth, initHeight);
|
||||
data->image = data->image.scaled(targetSize, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
|
||||
// Crop to center
|
||||
int x = (data->image.width() - targetSize.width()) / 2;
|
||||
int y = (data->image.height() - targetSize.height()) / 2;
|
||||
data->image = data->image.copy(x, y, targetSize.width(), targetSize.height());
|
||||
const QSize targetSize(initWidth, initHeight);
|
||||
const QSize originalSize = reader.size();
|
||||
|
||||
if (originalSize.isValid()) {
|
||||
double widthRatio = (double)targetSize.width() / originalSize.width();
|
||||
double heightRatio = (double)targetSize.height() / originalSize.height();
|
||||
double scaleFactor = std::max(widthRatio, heightRatio);
|
||||
|
||||
QSize scaledSize = originalSize * scaleFactor;
|
||||
reader.setScaledSize(scaledSize);
|
||||
}
|
||||
|
||||
if (!reader.read(data->image)) {
|
||||
error(QString("Failed to load image from path: %1").arg(p));
|
||||
delete data;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (data->image->size() != targetSize) {
|
||||
int x = (data->image->width() - targetSize.width()) / 2;
|
||||
int y = (data->image->height() - targetSize.height()) / 2;
|
||||
*data->image = data->image->copy(x, y, targetSize.width(), targetSize.height());
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
ImageItem::ImageItem(const ImageData* data,
|
||||
ImageItem::ImageItem(ImageData* data,
|
||||
const int itemWidth,
|
||||
const int itemHeight,
|
||||
const int itemFocusWidth,
|
||||
@@ -40,11 +62,12 @@ ImageItem::ImageItem(const ImageData* data,
|
||||
m_itemFocusSize(itemFocusWidth, itemFocusHeight) {
|
||||
assert(data != nullptr);
|
||||
setScaledContents(true);
|
||||
if (data->image.isNull()) {
|
||||
if (!data->isValid()) {
|
||||
setText(":(");
|
||||
setAlignment(Qt::AlignCenter);
|
||||
} else {
|
||||
setPixmap(QPixmap::fromImage(data->image));
|
||||
setPixmap(QPixmap::fromImage(data->getImage()));
|
||||
data->releaseImage();
|
||||
}
|
||||
setFixedSize(itemWidth, itemHeight);
|
||||
}
|
||||
|
||||
+20
-10
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* @Author: Uyanide pywang0608@foxmail.com
|
||||
* @Date: 2025-11-30 20:31:15
|
||||
* @LastEditTime: 2025-11-30 23:08:22
|
||||
* @LastEditTime: 2026-01-14 23:32:58
|
||||
* @Description: Image item widget for displaying an image.
|
||||
*/
|
||||
#ifndef IMAGE_ITEM_H
|
||||
@@ -17,13 +17,23 @@
|
||||
* @brief Data structure to hold image information
|
||||
* and can be safely created and passed between threads.
|
||||
*/
|
||||
struct ImageData {
|
||||
class ImageData {
|
||||
QFileInfo file;
|
||||
QImage image;
|
||||
QImage* image;
|
||||
|
||||
public:
|
||||
static ImageData* create(const QString& p, const int initWidth, const int initHeight);
|
||||
|
||||
~ImageData() { releaseImage(); }
|
||||
|
||||
void releaseImage() { delete image, image = nullptr; }
|
||||
|
||||
[[nodiscard]] const QImage& getImage() const { return *image; }
|
||||
|
||||
[[nodiscard]] bool isValid() const { return !image->isNull(); }
|
||||
|
||||
[[nodiscard]] const QFileInfo& getFileInfo() const { return file; }
|
||||
|
||||
private:
|
||||
ImageData(const QString& path) : file(path), image() {}
|
||||
};
|
||||
@@ -38,7 +48,7 @@ class ImageItem : public QLabel {
|
||||
public:
|
||||
static constexpr int s_animationDuration = 300;
|
||||
|
||||
explicit ImageItem(const ImageData* data,
|
||||
explicit ImageItem(ImageData* data,
|
||||
const int itemWidth,
|
||||
const int itemHeight,
|
||||
const int itemFocusWidth,
|
||||
@@ -47,15 +57,15 @@ class ImageItem : public QLabel {
|
||||
|
||||
~ImageItem() override;
|
||||
|
||||
[[nodiscard]] QString getFileFullPath() const { return m_data->file.absoluteFilePath(); }
|
||||
[[nodiscard]] QString getFileFullPath() const { return m_data->getFileInfo().absoluteFilePath(); }
|
||||
|
||||
[[nodiscard]] QString getFileName() const { return m_data->file.fileName(); }
|
||||
[[nodiscard]] QString getFileName() const { return m_data->getFileInfo().fileName(); }
|
||||
|
||||
[[nodiscard]] QDateTime getFileDate() const { return m_data->file.lastModified(); }
|
||||
[[nodiscard]] QDateTime getFileDate() const { return m_data->getFileInfo().lastModified(); }
|
||||
|
||||
[[nodiscard]] const QImage& getThumbnail() const { return m_data->image; }
|
||||
[[nodiscard]] const QImage& getThumbnail() const { return m_data->getImage(); }
|
||||
|
||||
[[nodiscard]] qint64 getFileSize() const { return m_data->file.size(); }
|
||||
[[nodiscard]] qint64 getFileSize() const { return m_data->getFileInfo().size(); }
|
||||
|
||||
void setFocus(bool focus = true, bool animate = true);
|
||||
|
||||
@@ -75,4 +85,4 @@ class ImageItem : public QLabel {
|
||||
void clicked(const QString& path);
|
||||
};
|
||||
|
||||
#endif // IMAGE_ITEM_H
|
||||
#endif // IMAGE_ITEM_H
|
||||
|
||||
+10
-7
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* @Author: Uyanide pywang0608@foxmail.com
|
||||
* @Date: 2025-08-05 01:22:53
|
||||
* @LastEditTime: 2025-12-01 01:43:00
|
||||
* @LastEditTime: 2026-01-14 23:50:49
|
||||
* @Description: Animated carousel widget for displaying and selecting images.
|
||||
*/
|
||||
#include "images_carousel.h"
|
||||
@@ -93,7 +93,10 @@ void ImagesCarousel::_onImagesLoaded() {
|
||||
// Focus the first image
|
||||
if (m_currentIndex < 0) {
|
||||
m_currentIndex = 0;
|
||||
focusCurrImage();
|
||||
// Ensure the layout events are processed
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
focusCurrImage();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +148,7 @@ ImageLoader::ImageLoader(const QString& path, ImagesCarousel* carousel)
|
||||
setAutoDelete(true);
|
||||
}
|
||||
|
||||
void ImagesCarousel::_insertImageQueue(const ImageData* data) {
|
||||
void ImagesCarousel::_insertImageQueue(ImageData* data) {
|
||||
if (!m_noLoadingScreen) {
|
||||
_insertImage(data);
|
||||
return;
|
||||
@@ -156,7 +159,7 @@ void ImagesCarousel::_insertImageQueue(const ImageData* data) {
|
||||
}
|
||||
}
|
||||
|
||||
int ImagesCarousel::_insertImage(const ImageData* data) {
|
||||
int ImagesCarousel::_insertImage(ImageData* data) {
|
||||
// Increase loaded count regardless of success or failure
|
||||
Defer defer([this]() {
|
||||
emit imageLoaded(getLoadedImagesCount());
|
||||
@@ -270,7 +273,7 @@ void ImageLoader::run() {
|
||||
QMetaObject::invokeMethod(m_carousel,
|
||||
"_insertImageQueue",
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(const ImageData*, data));
|
||||
Q_ARG(ImageData*, data));
|
||||
});
|
||||
{
|
||||
QMutexLocker stopSignLocker(&m_carousel->m_stopSignMutex);
|
||||
@@ -340,7 +343,7 @@ void ImagesCarousel::focusCurrImage() {
|
||||
}
|
||||
auto item = getImageItemAt(m_currentIndex);
|
||||
if (!item) {
|
||||
warn(QString("Failed to get item at index: %1").arg(m_currentIndex));
|
||||
error(QString("Failed to get item at index: %1").arg(m_currentIndex));
|
||||
return;
|
||||
}
|
||||
item->setFocus(true, m_animationEnabled);
|
||||
@@ -428,4 +431,4 @@ void ImagesCarousel::_onItemClicked(const QString& path) {
|
||||
void ImagesCarousel::onStop() {
|
||||
QMutexLocker locker(&m_stopSignMutex);
|
||||
m_stopSign = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* @Author: Uyanide pywang0608@foxmail.com
|
||||
* @Date: 2025-08-05 01:22:53
|
||||
* @LastEditTime: 2025-12-01 01:36:04
|
||||
* @LastEditTime: 2026-01-14 23:26:32
|
||||
* @Description: Animated carousel widget for displaying and selecting images.
|
||||
*/
|
||||
#ifndef IMAGES_CAROUSEL_H
|
||||
@@ -121,8 +121,8 @@ class ImagesCarousel : public QWidget {
|
||||
void appendImages(const QStringList& paths);
|
||||
|
||||
private:
|
||||
int _insertImage(const ImageData* item);
|
||||
Q_INVOKABLE void _insertImageQueue(const ImageData* item);
|
||||
int _insertImage(ImageData* item);
|
||||
Q_INVOKABLE void _insertImageQueue(ImageData* item);
|
||||
|
||||
void _enableUIUpdates(bool enable);
|
||||
int _focusingLeftOffset(int index);
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* @Author: Uyanide pywang0608@foxmail.com
|
||||
* @Date: 2025-11-30 20:59:57
|
||||
* @LastEditTime: 2025-12-07 06:08:18
|
||||
* @Description: THE utils header that every project needs :)
|
||||
*/
|
||||
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
|
||||
Reference in New Issue
Block a user