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
17 changes: 17 additions & 0 deletions batch-print/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ set(BATCHPRINT_READER_SOURCES
${CMAKE_SOURCE_DIR}/reader/document/XpsTextExtractor.cpp
)

# OFD: Model.cpp gets OFD_SUPPORT_ENABLED from the global add_compile_definitions,
# so OfdModel.cpp (implements OfdDocument::loadDocument) and rofd/cairo must be linked too.
if (OFD_SUPPORT_ENABLED)
list(APPEND BATCHPRINT_READER_SOURCES
${CMAKE_SOURCE_DIR}/reader/document/OfdModel.cpp
${CMAKE_SOURCE_DIR}/reader/document/Navigation.cpp
)
endif()

add_library(batchprint-convert STATIC
formatconverter.h formatconverter.cpp
${BATCHPRINT_READER_SOURCES}
Expand All @@ -61,6 +70,8 @@ target_include_directories(batchprint-convert PUBLIC
${CMAKE_SOURCE_DIR}/reader/document
${PDFIUM_INCLUDE_DIRS}
$<$<BOOL:${XPS_SUPPORT_ENABLED}>:${XPS_DEPS_INCLUDE_DIRS}>
$<$<BOOL:${OFD_SUPPORT_ENABLED}>:${ROFD_INCLUDE_DIR}>
$<$<BOOL:${OFD_SUPPORT_ENABLED}>:${OFD_CAIRO_INCLUDE_DIRS}>
)

target_compile_definitions(batchprint-convert PRIVATE
Expand All @@ -83,6 +94,8 @@ target_link_libraries(batchprint-convert PUBLIC
${LIBJPEG_LIBRARIES}
${FREETYPE_LIBRARIES}
$<$<BOOL:${XPS_SUPPORT_ENABLED}>:${XPS_DEPS_LIBRARIES}>
$<$<BOOL:${OFD_SUPPORT_ENABLED}>:${ROFD_FFI_LIBRARY}>
$<$<BOOL:${OFD_SUPPORT_ENABLED}>:${OFD_CAIRO_LIBRARIES}>
)

# DTK linking
Expand All @@ -109,6 +122,10 @@ if (XPS_SUPPORT_ENABLED)
target_compile_options(batchprint-convert PUBLIC ${XPS_DEPS_CFLAGS_OTHER})
endif()

if (OFD_SUPPORT_ENABLED)
target_compile_options(batchprint-convert PRIVATE ${OFD_CAIRO_CFLAGS_OTHER})
endif()

# Executable
add_executable(deepin-reader-batchprint
main.cpp
Expand Down
7 changes: 6 additions & 1 deletion reader/browser/PageRenderThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,11 @@ bool PageRenderThread::execNextDocPageThumbnailTask()
QImage image = task.renderer->getImage(task.index, 174, 174);

if (!image.isNull()) {
// 预取图片对象 bbox(夜间/深色蒙版用):在工作线程取,避免 UI 线程与渲染争文档锁;
// 与 getImage 同尺寸(174,174)请求,蒙版与缩略图输出像素一一对齐
if (DocSheet::existSheetByUuid(task.uuid) && task.renderer->opened()) {
task.imageRects = task.renderer->getImageObjectRects(task.index, 174, 174);
}
emit sigDocPageThumbnailTaskFinished(task, QPixmap::fromImage(image));
}
qCDebug(appLog) << "执行缩略图任务已完成";
Expand Down Expand Up @@ -968,7 +973,7 @@ void PageRenderThread::onDocPageThumbnailTask(DocPageThumbnailTask task, QPixmap
{
// qCDebug(appLog) << "PageRenderThread::onDocPageThumbnailTask() - Starting on doc page thumbnail task";
if (DocSheet::existSheet(task.sheet)) {
task.model->handleRenderThumbnail(task.index, pixmap);
task.model->handleRenderThumbnail(task.index, pixmap, task.imageRects);
}
// qCDebug(appLog) << "PageRenderThread::onDocPageThumbnailTask() - On doc page thumbnail task completed";
}
Expand Down
1 change: 1 addition & 0 deletions reader/browser/PageRenderThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ struct DocPageThumbnailTask {//缩略图
DocSheet *sheet = nullptr;
SideBarImageViewModel *model = nullptr;
int index = -1;
QVector<QRectF> imageRects; //图片对象 bbox(夜间/深色蒙版用,与缩略图像素对齐,worker线程预取)
};

struct DocOpenTask {//打开文档
Expand Down
52 changes: 22 additions & 30 deletions reader/sidebar/BookMarkDelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@

#include "BookMarkDelegate.h"
#include "SideBarImageViewModel.h"
#include "NightFilter.h"

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

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "NightFilter.h" not found.
#include "Application.h"

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

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "Application.h" not found.
#include "ddlog.h"

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

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "ddlog.h" not found.

#include <DGuiApplicationHelper>

Expand Down Expand Up @@ -48,42 +49,33 @@
clipPath.addRoundedRect(rect, borderRadius, borderRadius);
painter->setClipPath(clipPath);
// 深色主题下将白底缩略图反色为黑底白字(仅绘制时反色,不改缓存原图):
// HSL 亮度反转,下限钳制 37(#252525),反转后 ≥192 提亮纯白。
// 统一走主干夜间滤镜 NightFilter(CIELAB L* 反转),图片对象区域不反色
// (照片零负片,与主视图蒙版行为一致),含扫描页整页反色特判。
if (DTK_NAMESPACE::Gui::DGuiApplicationHelper::instance()->themeType() == DTK_NAMESPACE::Gui::DGuiApplicationHelper::DarkType) {
// 按源图 cacheKey() 缓存反色结果,避免每次重绘重复逐像素计算
// 图片对象 bbox(与存储缩略图像素对齐,渲染线程预取)
const QVector<QRectF> imageRects = index.data(ImageinfoType_e::IMAGE_NIGHT_MASK).value<QVector<QRectF>>();
// 按源缩略图 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());
// bbox 是存储缩略图(174px)坐标,而 scalePix 是等比缩小后的图,
// 须先映射到 scalePix 坐标,否则覆盖率特判/蒙版区域全错
QVector<QRectF> scaledRects;
scaledRects.reserve(imageRects.size());
const qreal sx = pixmap.isNull() || pixmap.width() == 0
? 0.0 : qreal(scalePix.width()) / pixmap.width();
const qreal sy = pixmap.isNull() || pixmap.height() == 0
? 0.0 : qreal(scalePix.height()) / pixmap.height();
for (const QRectF &r : imageRects)
scaledRects.append(QRectF(r.x() * sx, r.y() * sy,
r.width() * sx, r.height() * sy));

invertedPixmap = QPixmap::fromImage(NightFilter::applyPage(scalePix.toImage(), scaledRects));
invertedPixmap.setDevicePixelRatio(scalePix.devicePixelRatio());
if (!invertedPixmap.isNull())
m_darkPixmapCache.insert(pixmap.cacheKey(), new QPixmap(invertedPixmap),
img.width() * img.height() * 4); // ARGB32 每像素固定 4 字节
}
invertedPixmap.width() * invertedPixmap.height() * 4); // ARGB32 每像素固定 4 字节
}
if (!invertedPixmap.isNull())
painter->drawPixmap(rect.x(), rect.y(), invertedPixmap);
Expand Down
47 changes: 45 additions & 2 deletions reader/sidebar/NotesDelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,25 @@

#include "NotesDelegate.h"
#include "SideBarImageViewModel.h"
#include "NightFilter.h"

Check warning on line 8 in reader/sidebar/NotesDelegate.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "NightFilter.h" not found.
#include "Utils.h"

Check warning on line 9 in reader/sidebar/NotesDelegate.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "Utils.h" not found.
#include "Application.h"

Check warning on line 10 in reader/sidebar/NotesDelegate.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "Application.h" not found.
#include "ddlog.h"

Check warning on line 11 in reader/sidebar/NotesDelegate.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "ddlog.h" not found.

#include <DGuiApplicationHelper>

#include <QPainter>
#include <QItemSelectionModel>

Check warning on line 16 in reader/sidebar/NotesDelegate.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 17 in reader/sidebar/NotesDelegate.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 18 in reader/sidebar/NotesDelegate.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>

NotesDelegate::NotesDelegate(QAbstractItemView *parent)
: DStyledItemDelegate(parent)
{
// qCDebug(appLog) << "NotesDelegate::NotesDelegate() - Starting constructor";
m_parent = parent;
m_darkPixmapCache.setMaxCost(8 * 1024 * 1024); // 反色缓存预算 8MB,按像素字节数计费
// qCDebug(appLog) << "NotesDelegate::NotesDelegate() - Constructor completed";
}

Expand All @@ -45,7 +48,42 @@
QPainterPath clipPath;
clipPath.addRoundedRect(rect, borderRadius, borderRadius);
painter->setClipPath(clipPath);
painter->drawPixmap(rect.x(), rect.y(), scalePix);
// 深色主题下将白底缩略图反色为黑底白字(仅绘制时反色,不改缓存原图):
// 统一走主干夜间滤镜 NightFilter(CIELAB L* 反转),图片对象区域不反色
// (照片零负片,与主视图蒙版行为一致),含扫描页整页反色特判。
if (DTK_NAMESPACE::Gui::DGuiApplicationHelper::instance()->themeType() == DTK_NAMESPACE::Gui::DGuiApplicationHelper::DarkType) {
// 图片对象 bbox(与存储缩略图像素对齐,渲染线程预取)
const QVector<QRectF> imageRects = index.data(ImageinfoType_e::IMAGE_NIGHT_MASK).value<QVector<QRectF>>();
// 按源缩略图 cacheKey() 缓存反色结果,避免每次重绘重复逐像素计算
QPixmap invertedPixmap;
if (QPixmap *cached = m_darkPixmapCache.object(pixmap.cacheKey())) {
invertedPixmap = *cached;
} else {
// bbox 是存储缩略图(174px)坐标,而 scalePix 是等比缩小后的图,
// 须先映射到 scalePix 坐标,否则覆盖率特判/蒙版区域全错
QVector<QRectF> scaledRects;
scaledRects.reserve(imageRects.size());
const qreal sx = pixmap.isNull() || pixmap.width() == 0
? 0.0 : qreal(scalePix.width()) / pixmap.width();
const qreal sy = pixmap.isNull() || pixmap.height() == 0
? 0.0 : qreal(scalePix.height()) / pixmap.height();
for (const QRectF &r : imageRects)
scaledRects.append(QRectF(r.x() * sx, r.y() * sy,
r.width() * sx, r.height() * sy));

invertedPixmap = QPixmap::fromImage(NightFilter::applyPage(scalePix.toImage(), scaledRects));
invertedPixmap.setDevicePixelRatio(scalePix.devicePixelRatio());
if (!invertedPixmap.isNull())
m_darkPixmapCache.insert(pixmap.cacheKey(), new QPixmap(invertedPixmap),
invertedPixmap.width() * invertedPixmap.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 @@ -57,7 +95,12 @@
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));
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
8 changes: 8 additions & 0 deletions reader/sidebar/NotesDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

#include <DStyledItemDelegate>

#include <QCache>
#include <QPixmap>

DWIDGET_USE_NAMESPACE
/**
* @brief The NotesDelegate class
Expand Down Expand Up @@ -39,6 +42,11 @@ class NotesDelegate : public DStyledItemDelegate

private:
QAbstractItemView *m_parent = nullptr;

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

#endif // NOTESDELEGATE_H
25 changes: 24 additions & 1 deletion reader/sidebar/SearchResDelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "SearchResDelegate.h"
#include "SideBarImageViewModel.h"
#include "NightFilter.h"
#include "Utils.h"
#include "Application.h"
#include "ddlog.h"
Expand Down Expand Up @@ -39,7 +40,13 @@ void SearchResDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opt


if (!pixmap.isNull()) {
const QPixmap &scalePix = pixmap.scaled(pageSize);
// 深色主题下搜索结果页的页面小图与缩略图侧栏一致走主干夜间滤镜
// (CIELAB L* 反转,图片对象区域保持原色,扫描页整页反色特判),
// 浅色主题照常绘制原图;先按原始尺寸反色再缩放,蒙版坐标无需换算
const bool darkTheme = (DTK_NAMESPACE::Gui::DGuiApplicationHelper::instance()->themeType() == DTK_NAMESPACE::Gui::DGuiApplicationHelper::DarkType);
const QVector<QRectF> imageRects = index.data(ImageinfoType_e::IMAGE_NIGHT_MASK).value<QVector<QRectF>>();
const QPixmap &displayPixmap = darkTheme ? nightPixmap(pixmap, imageRects) : pixmap;
const QPixmap &scalePix = displayPixmap.scaled(pageSize);
//clipPath pixmap
painter->save();
QPainterPath clipPath;
Expand Down Expand Up @@ -124,3 +131,19 @@ QSize SearchResDelegate::sizeHint(const QStyleOptionViewItem &option, const QMod
return size;
}

QPixmap SearchResDelegate::nightPixmap(const QPixmap &src, const QVector<QRectF> &imageRects) const
{
if (src.isNull())
return src;

// 搜索结果列表滚动时同一张页面小图会被反复重绘,缓存反色结果避免逐像素重复计算;
// 页面重渲染时 cacheKey 必然变化,无需将蒙版纳入缓存键
if (m_nightSourceCache.cacheKey() == src.cacheKey() && !m_nightPixmapCache.isNull())
return m_nightPixmapCache;

m_nightSourceCache = src;
m_nightPixmapCache = QPixmap::fromImage(NightFilter::applyPage(src.toImage(), imageRects));
m_nightPixmapCache.setDevicePixelRatio(src.devicePixelRatio());
return m_nightPixmapCache;
}

18 changes: 18 additions & 0 deletions reader/sidebar/SearchResDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#define SEARCHRESDELEGATE_H

#include <DStyledItemDelegate>
#include <QPixmap>
#include <QVector>
#include <QRectF>

DWIDGET_USE_NAMESPACE
/**
Expand Down Expand Up @@ -37,8 +40,23 @@ class SearchResDelegate : public DStyledItemDelegate
*/
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;

private:
/**
* @brief nightPixmap
* 夜间智能滤镜/深色主题下页面小图的反色结果(带缓存):
* 走主干 NightFilter 管线(CIELAB L* 反转 + 图片对象区域跳过 + 扫描页整页反色特判),
* 与缩略图侧栏/主视图观感一致
* @param src 原始缩略图
* @param imageRects 图片对象 bbox(与 src 像素对齐,这些区域不反色避免照片负片)
* @return 反色后的缩略图
*/
QPixmap nightPixmap(const QPixmap &src, const QVector<QRectF> &imageRects = QVector<QRectF>()) const;

private:
QAbstractItemView *m_parent = nullptr;

mutable QPixmap m_nightSourceCache; // 反色缓存的源缩略图
mutable QPixmap m_nightPixmapCache; // 反色后的缩略图
};

#endif // SEARCHRESDELEGATE_H
9 changes: 6 additions & 3 deletions reader/sidebar/SideBarImageViewModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ QVariant SideBarImageViewModel::data(const QModelIndex &index, int role) const
} else if (role == ImageinfoType_e::IMAGE_PAGE_SIZE) {
// qCDebug(appLog) << "Getting page size for index:" << nRow;
return QVariant::fromValue(m_sheet->pageSizeByIndex(nRow));
} else if (role == ImageinfoType_e::IMAGE_NIGHT_MASK) {
// 图片对象 bbox:夜间/深色反色时跳过这些区域,与主视图(BrowserPage)蒙版行为一致
return QVariant::fromValue(m_sheet->thumbnailImageRects(nRow));
}
return QVariant();
}
Expand Down Expand Up @@ -302,11 +305,11 @@ int SideBarImageViewModel::findItemForAnno(deepin_reader::Annotation *annotation
return -1;
}

void SideBarImageViewModel::handleRenderThumbnail(int index, QPixmap pixmap)
void SideBarImageViewModel::handleRenderThumbnail(int index, QPixmap pixmap, const QVector<QRectF> &imageRects)
{
qCDebug(appLog) << "Handling thumbnail render for page:" << index << "size:" << pixmap.size();
qCDebug(appLog) << "Handling thumbnail render for page:" << index << "size:" << pixmap.size() << "imageRects:" << imageRects.size();
pixmap.setDevicePixelRatio(dApp->devicePixelRatio());
m_sheet->setThumbnail(index, pixmap);
m_sheet->setThumbnail(index, pixmap, imageRects);

m_pendingUpdatePages.insert(index);
if (!m_batchUpdateTimer->isActive()) {
Expand Down
8 changes: 7 additions & 1 deletion reader/sidebar/SideBarImageViewModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@
#include <QMap>
#include <QTimer>
#include <QSet>
#include <QVector>
#include <QRectF>

namespace deepin_reader {
class Annotation;
}

Q_DECLARE_METATYPE(QVector<QRectF>)

typedef enum E_SideBar {
SIDE_THUMBNIL = 0,
SIDE_BOOKMARK,
Expand All @@ -31,6 +35,7 @@ typedef enum ImageinfoType_e {
IMAGE_CONTENT_TEXT = Qt::UserRole + 4,
IMAGE_SEARCH_COUNT = Qt::UserRole + 5,
IMAGE_PAGE_SIZE = Qt::UserRole + 6,
IMAGE_NIGHT_MASK = Qt::UserRole + 7, //图片对象 bbox 列表(夜间/深色反色时跳过图片区域,与 IMAGE_PIXMAP 像素对齐)
} ImageinfoType_e;

typedef struct ImagePageInfo_t {
Expand Down Expand Up @@ -157,8 +162,9 @@ class SideBarImageViewModel : public QAbstractListModel
* 处理缩略图
* @param index
* @param pixmap
* @param imageRects 图片对象 bbox(与 pixmap 像素对齐,夜间/深色反色跳过图片区域用)
*/
void handleRenderThumbnail(int index, QPixmap pixmap);
void handleRenderThumbnail(int index, QPixmap pixmap, const QVector<QRectF> &imageRects = QVector<QRectF>());

public slots:
/**
Expand Down
Loading
Loading