Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions reader/browser/BrowserPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1289,12 +1289,9 @@ QPixmap BrowserPage::applyNightMode(const QPixmap &src)
if (img.isNull())
return src;

// 统一为 ARGB32 便于逐行扫描
if (img.format() != QImage::Format_ARGB32 &&
img.format() != QImage::Format_ARGB32_Premultiplied &&
img.format() != QImage::Format_RGB32) {
// 统一转非预乘 ARGB32,避免对 ARGB32_Premultiplied 写入非预乘值导致半透明像素错误
if (img.format() != QImage::Format_ARGB32)
img = img.convertToFormat(QImage::Format_ARGB32);
}

const int w = img.width();
const int h = img.height();
Expand All @@ -1306,11 +1303,17 @@ QPixmap BrowserPage::applyNightMode(const QPixmap &src)
const int alpha = qAlpha(px);

// HSL 亮度反转:保留色相(H)和饱和度(S),仅反转亮度(L)
// 白(255) → 黑(0),黑(0) → 白(255),彩色仅变暗、色相不偏移
// 白(255) → 黑,黑(0) → 白(255),彩色仅变暗、色相不偏移
// 两端收敛:下限钳制 30(#1E1E1E),反转后 ≥192 提亮纯白(原图 L≤63 深色文字)
const int kMinLightAfterInvert = 30; // #1E1E1E 的 HSL 亮度值
const int kMaxLightBoostThreshold = 192; // 0xC0,提亮阈值
QColor c = QColor::fromRgb(qRed(px), qGreen(px), qBlue(px));
int hue, sat, light, dummy;
c.getHsl(&hue, &sat, &light, &dummy);
light = 255 - light;
if (light >= kMaxLightBoostThreshold)
light = 255;
light = qMax(light, kMinLightAfterInvert);
c.setHsl(hue, sat, light);
line[x] = qRgba(c.red(), c.green(), c.blue(), alpha);
}
Expand Down
60 changes: 56 additions & 4 deletions reader/sidebar/BookMarkDelegate.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (C) 2019 ~ 2020 Uniontech Software Technology Co.,Ltd.
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
// Copyright (C) 2019 ~ 2026 Uniontech Software Technology Co.,Ltd.
// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

Expand All @@ -11,16 +11,18 @@
#include <DGuiApplicationHelper>

#include <QPainter>
#include <QItemSelectionModel>

Check warning on line 14 in reader/sidebar/BookMarkDelegate.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QItemSelectionModel> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QAbstractItemView>

Check warning on line 15 in reader/sidebar/BookMarkDelegate.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QAbstractItemView> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QPainterPath>

Check warning on line 16 in reader/sidebar/BookMarkDelegate.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QPainterPath> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QImage>

Check warning on line 17 in reader/sidebar/BookMarkDelegate.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QImage> not found. Please note: Cppcheck does not need standard library headers to get proper results.

BookMarkDelegate::BookMarkDelegate(QAbstractItemView *parent)
: DStyledItemDelegate(parent)
{
qCInfo(appLog) << "Creating BookMarkDelegate with parent widget:" << parent;

m_parent = parent;
m_darkPixmapCache.setMaxCost(8 * 1024 * 1024); // 反色缓存预算 8MB,按像素字节数计费
}

void BookMarkDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
Expand All @@ -45,7 +47,51 @@
QPainterPath clipPath;
clipPath.addRoundedRect(rect, borderRadius, borderRadius);
painter->setClipPath(clipPath);
painter->drawPixmap(rect.x(), rect.y(), scalePix);
// 深色主题下将白底缩略图反色为黑底白字(仅绘制时反色,不改缓存原图):
// HSL 亮度反转,下限钳制 37(#252525),反转后 ≥192 提亮纯白。
if (DTK_NAMESPACE::Gui::DGuiApplicationHelper::instance()->themeType() == DTK_NAMESPACE::Gui::DGuiApplicationHelper::DarkType) {
// 按源图 cacheKey() 缓存反色结果,避免每次重绘重复逐像素计算
QPixmap invertedPixmap;
if (QPixmap *cached = m_darkPixmapCache.object(pixmap.cacheKey())) {
invertedPixmap = *cached;
} else {
QImage img = scalePix.toImage();
if (!img.isNull()) {
if (img.format() != QImage::Format_ARGB32)
img = img.convertToFormat(QImage::Format_ARGB32);
const int w = img.width();
const int h = img.height();
const int kMinLightAfterInvert = 37; // #252525
const int kMaxLightBoostThreshold = 192; // 0xC0,提亮阈值
for (int y = 0; y < h; ++y) {
QRgb *line = reinterpret_cast<QRgb *>(img.scanLine(y));
for (int x = 0; x < w; ++x) {
const QRgb px = line[x];
const int alpha = qAlpha(px);
QColor c = QColor::fromRgb(qRed(px), qGreen(px), qBlue(px));
int hue, sat, light, dummy;
c.getHsl(&hue, &sat, &light, &dummy);
light = 255 - light;
if (light >= kMaxLightBoostThreshold)
light = 255;
light = qMax(light, kMinLightAfterInvert);
c.setHsl(hue, sat, light);
line[x] = qRgba(c.red(), c.green(), c.blue(), alpha);
}
}
invertedPixmap = QPixmap::fromImage(img);
invertedPixmap.setDevicePixelRatio(scalePix.devicePixelRatio());
m_darkPixmapCache.insert(pixmap.cacheKey(), new QPixmap(invertedPixmap),
img.width() * img.height() * 4); // ARGB32 每像素固定 4 字节
}
}
if (!invertedPixmap.isNull())
painter->drawPixmap(rect.x(), rect.y(), invertedPixmap);
else
painter->drawPixmap(rect.x(), rect.y(), scalePix);
} else {
painter->drawPixmap(rect.x(), rect.y(), scalePix);
}
painter->restore();
}

Expand All @@ -59,7 +105,13 @@
painter->setPen(QPen(DTK_NAMESPACE::Gui::DGuiApplicationHelper::instance()->applicationPalette().highlight().color(), 2));
painter->drawRoundedRect(rect, borderRadius, borderRadius);
} else {
painter->setPen(QPen(DTK_NAMESPACE::Gui::DGuiApplicationHelper::instance()->applicationPalette().frameShadowBorder().color(), 1));
// 未选中:深色主题下 frameShadowBorder 与深色背景混色,改用 windowText@0.2α
QColor frameColor = DTK_NAMESPACE::Gui::DGuiApplicationHelper::instance()->applicationPalette().frameShadowBorder().color();
if (DTK_NAMESPACE::Gui::DGuiApplicationHelper::instance()->themeType() == DTK_NAMESPACE::Gui::DGuiApplicationHelper::DarkType) {
frameColor = DTK_NAMESPACE::Gui::DGuiApplicationHelper::instance()->applicationPalette().windowText().color();
frameColor.setAlphaF(0.2);
}
painter->setPen(QPen(frameColor, 1));
painter->drawRoundedRect(rect, borderRadius, borderRadius);
}
painter->restore();
Expand Down
12 changes: 10 additions & 2 deletions reader/sidebar/BookMarkDelegate.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
// Copyright (C) 2019 ~ 2020 Uniontech Software Technology Co.,Ltd.
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
// Copyright (C) 2019 ~ 2026 Uniontech Software Technology Co.,Ltd.
// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef BOOKMARKDELEGATE_H
#define BOOKMARKDELEGATE_H

#include <DStyledItemDelegate>

Check warning on line 9 in reader/sidebar/BookMarkDelegate.h

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <DStyledItemDelegate> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <QCache>

Check warning on line 11 in reader/sidebar/BookMarkDelegate.h

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QCache> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QPixmap>

Check warning on line 12 in reader/sidebar/BookMarkDelegate.h

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QPixmap> not found. Please note: Cppcheck does not need standard library headers to get proper results.

DWIDGET_USE_NAMESPACE

/**
Expand All @@ -31,6 +34,11 @@

private:
QAbstractItemView *m_parent = nullptr;

/**
* @brief 深色主题反色结果缓存(键:源图 cacheKey();paint() 为 const 故 mutable)
*/
mutable QCache<qint64, QPixmap> m_darkPixmapCache;
};

#endif // BOOKMARKDELEGATE_H
14 changes: 13 additions & 1 deletion reader/sidebar/ThumbnailDelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ void ThumbnailDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opt
// 不修改 DocSheet 中缓存的真实缩略图(始终为白底),避免主题切换时双重反色。
// 采用与 BrowserPage::applyNightMode 相同的 HSL 亮度反转算法:
// 仅反转 Lightness 通道,保留 Hue/Saturation,避免图片色相偏移 180°。
// 两端收敛:下限钳制 37(#252525),反转后 ≥192 提亮纯白
// 白底黑字 → 黑底白字(文字/背景正确反色)
// 彩色图片/链接 → 仅变暗,色相保持
if (DTK_NAMESPACE::Gui::DGuiApplicationHelper::instance()->themeType() == DTK_NAMESPACE::Gui::DGuiApplicationHelper::DarkType) {
Expand All @@ -77,6 +78,8 @@ void ThumbnailDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opt
img = img.convertToFormat(QImage::Format_ARGB32);
const int w = img.width();
const int h = img.height();
const int kMinLightAfterInvert = 37; // #252525
const int kMaxLightBoostThreshold = 192; // 0xC0,提亮阈值
for (int y = 0; y < h; ++y) {
QRgb *line = reinterpret_cast<QRgb *>(img.scanLine(y));
for (int x = 0; x < w; ++x) {
Expand All @@ -86,6 +89,9 @@ void ThumbnailDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opt
int hue, sat, light, dummy;
c.getHsl(&hue, &sat, &light, &dummy);
light = 255 - light;
if (light >= kMaxLightBoostThreshold)
light = 255;
light = qMax(light, kMinLightAfterInvert);
c.setHsl(hue, sat, light);
line[x] = qRgba(c.red(), c.green(), c.blue(), alpha);
}
Expand All @@ -110,7 +116,13 @@ void ThumbnailDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opt
painter->setPen(QPen(DTK_NAMESPACE::Gui::DGuiApplicationHelper::instance()->applicationPalette().highlight().color(), 2));
painter->drawRoundedRect(rect, borderRadius, borderRadius);
} else {
painter->setPen(QPen(DTK_NAMESPACE::Gui::DGuiApplicationHelper::instance()->applicationPalette().frameShadowBorder().color(), 1));
// 未选中:深色主题下 frameShadowBorder 与深色背景混色,改用 windowText@0.2α
QColor frameColor = DTK_NAMESPACE::Gui::DGuiApplicationHelper::instance()->applicationPalette().frameShadowBorder().color();
if (DTK_NAMESPACE::Gui::DGuiApplicationHelper::instance()->themeType() == DTK_NAMESPACE::Gui::DGuiApplicationHelper::DarkType) {
frameColor = DTK_NAMESPACE::Gui::DGuiApplicationHelper::instance()->applicationPalette().windowText().color();
frameColor.setAlphaF(0.2);
}
painter->setPen(QPen(frameColor, 1));
painter->drawRoundedRect(rect, borderRadius, borderRadius);
painter->setPen(QPen(DTK_NAMESPACE::Gui::DGuiApplicationHelper::instance()->applicationPalette().windowText().color()));
}
Expand Down
Loading