Skip to content

feat(reader): add OFD reading support via rofd - #381

Open
hualet wants to merge 19 commits into
masterfrom
ofd_support
Open

feat(reader): add OFD reading support via rofd#381
hualet wants to merge 19 commits into
masterfrom
ofd_support

Conversation

@hualet

@hualet hualet commented Sep 11, 2026

Copy link
Copy Markdown

概述

为 deepin-reader 增加 OFD 文档支持。当前以只读阅读为目标,主要阅读链路已经基本完善:不仅能够打开和显示 OFD,也已接入文本选择/复制、全文搜索、目录与页面链接、阅读状态恢复、文档信息等常用能力。

底层使用 linuxdeepin/rofd 提供的 OFD 解析与渲染能力,通过 rofd-ffi 的 C ABI 接入现有 Document / Page 抽象。reader 负责界面和交互,格式解析、文本语义和渲染由 rofd 提供。

当前支持状态

阅读能力 本 PR 状态
文件打开与桌面集成 OFD 文件识别、打开入口、MIME/desktop 注册、格式显示
页面阅读与渲染 页数/尺寸、整页和像素区域/瓦片渲染、缩略图、缩放、旋转、单/双页布局;区域渲染加入分配前大小检查,避免为小区域分配整页位图
文本与搜索 文本提取、字符布局、选择/复制、全文搜索及结果定位;后端支持大小写敏感和整词匹配
目录与跳转 完整层级目录、展开状态恢复、显式点击/键盘激活;支持 XYZFitFitHFitVFitR 目标及旋转/双页布局下定位
页面链接 链接区域命中、悬停、文档内跳转;外部 URI 使用白名单和确认对话框,不执行脚本或任意文件动作
阅读辅助 书签、阅读位置恢复、护眼模式、通用栅格打印路径、原文件副本另存为
元数据与诊断 接入标题、作者、创建/修改时间、Keywords、DocID 等元数据;文档信息展示解析警告,渲染诊断记录到日志

与主干保持一致

  • 已基于当前 master4862a03c)完成 rebase,保留主干的异步 NightFilter、主视图图片区域蒙版和阅读状态恢复机制。
  • 缩略图内容跟随护眼模式,界面装饰跟随系统主题;复用主干滤镜,不引入独立的旧 HSL 实现。
  • 有效的 OFD 目录/页面链接导航优先于尚未完成的阅读位置恢复,避免点击后被跳回旧页;同时处理可见页与记录页不同步时的同页跳转。无效目标和外部链接不取消正常恢复流程。

依赖与构建

  • 依赖 rofd >= 0.4.0 的匹配头文件与共享库;Debian 构建依赖为 librofd-ffi-dev (>= 0.4.0),渲染适配使用 Cairo。
  • 默认优先使用系统库,也可通过 ROFD_ROOTROFD_INCLUDE_DIR / ROFD_FFI_LIBRARY 指定本地构建。
  • OFD_SUPPORT 控制可选接入;配置时检查所需的区域渲染、元数据、警告、目录和页面链接 C ABI,避免误用接口不完整的旧库。
  • 复用主干 PDFium 共享库时,头文件和库也必须匹配,包含新的 DPdfPage::imageObjectRects() 接口。

当前边界

  • 本 PR 完善的是阅读能力,不是完整 OFD 编辑器;不包含注释/高亮写回、表单操作、签章验证或 OFD 内容修改。“另存为”仅复制原文件。
  • 纯图片/扫描内容不会因此自动获得可搜索文本,本 PR 不提供 OCR。
  • OFD 主视图及缩略图尚未提供图片对象蒙版,夜间模式使用主干滤镜的无蒙版回退路径;不宣称与 PDF 的照片保护效果完全一致。
  • 复杂文档仍需持续补充实际样本回归,不将“主要阅读链路基本完善”等同于所有 OFD 标准特性和所有文档均已覆盖。
  • 本次验证针对 CMake/Qt 6 路径;旧 qmake 工程的 C++17 和新增源文件清单适配仍需单独整理。

验证

本地使用 Qt 6 和 rofd 0.4.0:

  • 只构建 deepin-reader 本体,-j1,未触发 OOM。
  • 59 项 OFD 适配、导航计算、目录模型测试。
  • 41 项缩略图滤镜、缓存、透明度和高分屏检查。
  • 294 项真实 Qt 控件检查:目录/页面链接、旋转和布局、恢复期间导航、无效目标、外链取消,以及主题/护眼模式下的缩略图内容绘制。
  • git diff --check

定向测试不链接体积较大的 test-deepin-reader。Qt 控件检查使用 offscreen 平台,不替代可见桌面窗口、实体打印机和更广泛文档样本的验收;本地结果也不等同于 GitHub CI 已通过。

复现命令和范围见 定向验证说明

Hualet Wang added 19 commits September 11, 2026 12:01
Add a read-only OFD (GB/T 33190-2016) backend built on the rofd
library's stable C ABI (librofd_ffi), following the XPS adapter
integration pattern:

- OfdDocument/OfdPage implement the Document/Page interfaces: open,
  page count, page size (mm to logical px via screen DPI), and page
  rendering through rofd_renderer_render_page_cairo into a QImage.
  Text extraction and search return empty until the rofd C ABI
  exposes text APIs.
- New Dr::OFD file type detected by .ofd extension, factory branch,
  open-dialog filter, sidebar (thumbnail | bookmark), big-image
  rendering path, title widget enablement, save-as filter and format
  string.
- CMake option OFD_SUPPORT (default ON) locates rofd.h and
  librofd_ffi via -DROFD_ROOT, degrading gracefully when absent;
  qmake gains a matching ofd_support CONFIG block.
- Install application/ofd MIME definition and register it in the
  desktop file.
- Add GTest coverage (open, page size, out-of-range, render content
  check, invalid size, missing/broken file) with tests/files/normal.ofd.

Verified: full build with OFD on/off, 7 OFD unit tests pass, and the
application opens and renders an OFD invoice end to end.
OFD support now uses the Debian packages shipped by upstream rofd
instead of a local rofd checkout:

- debian/control Build-Depends on librofd-ffi-dev; the runtime
  dependency on librofd-ffi0 (>= 0.2.2) is derived automatically by
  dh_shlibdeps from the library's shlibs file.
- CMake keeps locating rofd.h and librofd_ffi through find_path and
  find_library, now also looking in lib/<multiarch> so a custom
  install prefix works, and still degrades gracefully (OFD disabled
  with a warning) when the dependency is absent; -DROFD_ROOT remains
  available for local development against a rofd checkout.
- qmake CONFIG+=ofd_support links the system librofd_ffi.
- Document librofd-ffi-dev in both README dependency lists.

Verified with librofd-ffi-dev 0.2.2-1: full build, TestOfdModel 7/7,
1116 unit tests pass, the application opens and renders
tests/files/normal.ofd, and dpkg-shlibdeps resolves
librofd-ffi0 (>= 0.2.2).
The thumbnail delegate inverted the page pixmap whenever the system
theme was dark, while BrowserPage only inverts in the night
eye-protection mode. Under a dark system theme with eye protection
off the main view kept white pages but the sidebar thumbnails turned
black, so the two disagreed - most visible with white OFD/PDF pages.

- ThumbnailDelegate now follows the EyeProtectionManager mode instead
  of the system theme and mirrors BrowserPage::paint exactly: night
  mode inverts luminance and dims with the page colour, classic/green
  multiply-tint with the page colour, off draws the original pixmap.
- Extract the HSL luminance inversion into
  EyeProtectionManager::invertLuminance and let
  BrowserPage::applyNightMode delegate to it so both paths share one
  algorithm; the inverted thumbnail is cached by source pixmap key to
  avoid per-pixel work on every repaint.
- SideBarImageListView refreshes visible thumbnails on modeChanged
  instead of themeTypeChanged.
- Cover the inversion helper, the mode-driven delegate painting and
  the modeChanged refresh in unit tests.

Verified under a dark system theme: thumbnails render white with eye
protection off (matching the main view, previously black), dark in
night mode and tinted in classic mode; targeted unit tests pass.

Log: 修复深色主题下OFD/PDF侧边栏缩略图黑底与主视图白底不一致的问题
Influence: 侧边栏缩略图外观改为跟随护眼模式(夜间反色、经典/绿色染色),与主视图页面保持一致;深色系统主题且未开启护眼时缩略图恢复白底
Use rofd pixel canvas and region rendering APIs instead of rendering and cropping a full page. Validate tile bounds and raster budgets before allocation, probe the required API at configure time, and add a lightweight OFD adapter test target.
Map rofd metadata snapshots to reader properties, preserve raw dates, and use valid document dates in file attributes. Add metadata and identifier coverage and extend the required API probe.
Refresh owned warning snapshots after lazy page loads and rendering, log each warning once, and display warning details in file attributes. Add Chinese translations and lazy-load warning coverage.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @hualet, your pull request is larger than the review limit of 150,000 diff characters

@github-actions

Copy link
Copy Markdown
  • 检测到debian目录文件有变更: debian/control

@github-actions

Copy link
Copy Markdown
  • 敏感词检查失败, 检测到7个文件存在敏感词
详情
{
    "tests/document/ut_ofdmodel.cpp": [
        {
            "line": "    EXPECT_EQ(uri.navigation->uri, QUrl(\"https://example.invalid/base/child?q=1&x=2\"));",
            "line_number": 183,
            "rule": "S35",
            "reason": "Url link | 443f9cf4ab"
        },
        {
            "line": "        \"<Action Event=\\"PO\\"><URI URI=\\"https://example.invalid/\\"/></Action>\"",
            "line_number": 274,
            "rule": "S35",
            "reason": "Url link | 12f87b2550"
        },
        {
            "line": "        + linkAction(\"<URI URI=\\"https://ignored.invalid/\\"/>\", {}, \"PO\")",
            "line_number": 360,
            "rule": "S35",
            "reason": "Url link | 2b4aa39828"
        },
        {
            "line": "        + linkAction(\"<URI URI=\\"https://later.invalid/\\"/>\", separatedLinkRegions) + \"</Actions>\";",
            "line_number": 363,
            "rule": "S35",
            "reason": "Url link | d3815d1565"
        },
        {
            "line": "        linkAction(\"<URI URI=\\"https://explicit.invalid/\\"/>\", explicitRegion))",
            "line_number": 412,
            "rule": "S35",
            "reason": "Url link | 183a779763"
        },
        {
            "line": "        + object(\"11\", \"100 110 20 10\", linkAction(\"<URI URI=\\"https://fallback.invalid/\\"/>\"));",
            "line_number": 413,
            "rule": "S35",
            "reason": "Url link | cca6461ea0"
        },
        {
            "line": "    for (const auto &sample : {std::make_pair(QPointF(55, 65), QString(\"https://explicit.invalid/\")),",
            "line_number": 421,
            "rule": "S35",
            "reason": "Url link | 183a779763"
        },
        {
            "line": "                              std::make_pair(QPointF(105, 115), QString(\"https://fallback.invalid/\"))}) {",
            "line_number": 422,
            "rule": "S35",
            "reason": "Url link | cca6461ea0"
        },
        {
            "line": "        linkAction(\"<URI URI=\\"https://ignored.invalid/\\"/>\", {}, \"PO\"),",
            "line_number": 437,
            "rule": "S35",
            "reason": "Url link | 2b4aa39828"
        },
        {
            "line": "        linkAction(\"<URI URI=\\"https://ignored.invalid/\\"/>\", {}, \"CUSTOM\"),",
            "line_number": 439,
            "rule": "S35",
            "reason": "Url link | 2b4aa39828"
        },
        {
            "line": "            ? linkAction(\"<URI URI=\\"child?q=1&amp;x=2\\" Base=\\"https://example.invalid/base/\\"/>\")",
            "line_number": 455,
            "rule": "S35",
            "reason": "Url link | 275ea50db3"
        },
        {
            "line": "                + linkAction(\"<URI URI=\\"https://later.invalid/\\"/>\") : QByteArray();",
            "line_number": 456,
            "rule": "S35",
            "reason": "Url link | d3815d1565"
        },
        {
            "line": "            EXPECT_EQ(hit.navigation->uri, QUrl(\"https://example.invalid/base/child?q=1&x=2\"));",
            "line_number": 469,
            "rule": "S35",
            "reason": "Url link | 443f9cf4ab"
        },
        {
            "line": "            EXPECT_EQ(hit.urlOrFileName, QStringLiteral(\"https://example.invalid/base/child?q=1&x=2\"));",
            "line_number": 470,
            "rule": "S35",
            "reason": "Url link | 443f9cf4ab"
        },
        {
            "line": "        + linkAction(\"<URI URI=\\"https://bad-region.invalid/\\"/>\", \"<Region><Area Start=\\"NaN 0\\"/></Region>\")",
            "line_number": 509,
            "rule": "S35",
            "reason": "Url link | eebdbaccbf"
        }
    ],
    "tests/document/ut_catalogoutlinemodel.cpp": [
        {
            "line": "    external.navigation = NavigationTarget{{}, QUrl(\"https://example.invalid/\")};",
            "line_number": 94,
            "rule": "S35",
            "reason": "Url link | 12f87b2550"
        }
    ],
    "tests/document/ut_navigation.cpp": [
        {
            "line": "    target.uri = QUrl(QStringLiteral(\"https://example.org/document\"));",
            "line_number": 128,
            "rule": "S35",
            "reason": "Url link | e4287474a7"
        },
        {
            "line": "    for (const auto &uri : {QStringLiteral(\"http://example.org/\"),",
            "line_number": 354,
            "rule": "S35",
            "reason": "Url link | 4ae2026102"
        },
        {
            "line": "                            QStringLiteral(\"https://example.org:443/a%20b?q=x#section\"),",
            "line_number": 355,
            "rule": "S35",
            "reason": "Url link | 4c2c7e6a14"
        },
        {
            "line": "    EXPECT_EQ(resolveNavigationUri(\"../next.html#heading\", \"https://example.org/docs/book/\"),",
            "line_number": 368,
            "rule": "S35",
            "reason": "Url link | 09cc6ee688"
        },
        {
            "line": "              QUrl(\"https://example.org/docs/next.html#heading\"));",
            "line_number": 369,
            "rule": "S35",
            "reason": "Url link | 83ae76601b"
        },
        {
            "line": "    EXPECT_EQ(resolveNavigationUri(\"/page\", \"http://example.org/docs/book\"),",
            "line_number": 370,
            "rule": "S35",
            "reason": "Url link | a9a46ad780"
        },
        {
            "line": "              QUrl(\"http://example.org/page\"));",
            "line_number": 371,
            "rule": "S35",
            "reason": "Url link | f927d94e81"
        },
        {
            "line": "    EXPECT_EQ(resolveNavigationUri(\"#part\", \"https://example.org/document.html\"),",
            "line_number": 372,
            "rule": "S35",
            "reason": "Url link | d82c59b640"
        },
        {
            "line": "              QUrl(\"https://example.org/document.html#part\"));",
            "line_number": 373,
            "rule": "S35",
            "reason": "Url link | e576c85fbe"
        },
        {
            "line": "    EXPECT_EQ(resolveNavigationUri(\"//cdn.example.org/image\", \"https://example.org/\"),",
            "line_number": 374,
            "rule": "S35",
            "reason": "Url link | 48800cefc9"
        },
        {
            "line": "              QUrl(\"https://cdn.example.org/image\"));",
            "line_number": 375,
            "rule": "S35",
            "reason": "Url link | a29bb02fca"
        },
        {
            "line": "                            QStringLiteral(\"ftp://example.org/file\"), QStringLiteral(\"custom:target\"),",
            "line_number": 387,
            "rule": "S35",
            "reason": "Url link | 92f7b93b67"
        },
        {
            "line": "                            QStringLiteral(\"http://example.org/%zz\"), QStringLiteral(\"http://exa mple.org/\"),",
            "line_number": 390,
            "rule": "S35",
            "reason": "Url link | f81bd3b3c6"
        },
        {
            "line": "                            QStringLiteral(\"https://example.org/a b\"), QStringLiteral(\"\nhttps://example.org/\"),",
            "line_number": 391,
            "rule": "S35",
            "reason": "Url link | 48800cefc9"
        },
        {
            "line": "        EXPECT_TRUE(resolveNavigationUri(uri, \"https://example.org/docs/\").isEmpty())",
            "line_number": 395,
            "rule": "S35",
            "reason": "Url link | e912a44d45"
        },
        {
            "line": "    Link link(QPainterPath(), QStringLiteral(\"https://legacy.example.org\"));",
            "line_number": 423,
            "rule": "S35",
            "reason": "Url link | 586e8c0f46"
        }
    ],
    "tests/ofd-model/navigation_smoke.cc": [
        {
            "line": "              \"<URI URI=\\"https://example.invalid/navigation\\"/></Action></Actions></OutlineElem>\";",
            "line_number": 128,
            "rule": "S35",
            "reason": "Url link | 34f9245507"
        },
        {
            "line": "                     \"<Actions><Action Event=\\"CLICK\\"><URI URI=\\"https://example.invalid/page\\"/>\"",
            "line_number": 141,
            "rule": "S35",
            "reason": "Url link | 58cd5f0d75"
        },
        {
            "line": "    verify(uriLink.urlOrFileName == \"https://example.invalid/page\", \"page link hover URL\");",
            "line_number": 359,
            "rule": "S35",
            "reason": "Url link | 58cd5f0d75"
        }
    ],
    "reader/Application.cpp": [
        {
            "line": "    setApplicationAcknowledgementPage(\"https://www.deepin.org/acknowledgments/deepin_reader\");",
            "line_number": 30,
            "rule": "S35",
            "reason": "Url link | c08ef69076"
        }
    ],
    "reader/app/Global.h": [
        {
            "line": "const QString key_up               = \"Up\";",
            "line_number": 112,
            "rule": "S106",
            "reason": "Var naming | 20293a700f"
        },
        {
            "line": "const QString key_down             = \"Down\";",
            "line_number": 113,
            "rule": "S106",
            "reason": "Var naming | 21f2799b08"
        },
        {
            "line": "const QString key_left             = \"Left\";",
            "line_number": 114,
            "rule": "S106",
            "reason": "Var naming | ebc87ca254"
        },
        {
            "line": "const QString key_right            = \"Right\";",
            "line_number": 115,
            "rule": "S106",
            "reason": "Var naming | ce51450b6e"
        },
        {
            "line": "const QString key_space            = \"Space\";           // 空格用于停止启动幻灯片播放",
            "line_number": 116,
            "rule": "S106",
            "reason": "Var naming | 19eddccbbe"
        },
        {
            "line": "const QString key_pgUp             = \"PgUp\";            // 上一页",
            "line_number": 117,
            "rule": "S106",
            "reason": "Var naming | 9c0713cb36"
        },
        {
            "line": "const QString key_pgDown           = \"PgDown\";          // 下一页",
            "line_number": 118,
            "rule": "S106",
            "reason": "Var naming | 73cb3b091d"
        },
        {
            "line": "const QString key_delete           = \"Del\";             // 删除",
            "line_number": 119,
            "rule": "S106",
            "reason": "Var naming | 8309604c6a"
        },
        {
            "line": "const QString key_esc              = \"Esc\";             // 退出全屏\退出放映\退出放大镜",
            "line_number": 120,
            "rule": "S106",
            "reason": "Var naming | 7dc55b084c"
        },
        {
            "line": "const QString key_f1               = \"F1\";              // 帮助",
            "line_number": 121,
            "rule": "S106",
            "reason": "Var naming | cfc950dca5"
        },
        {
            "line": "const QString key_f5               = \"F5\";              // 播放幻灯片",
            "line_number": 122,
            "rule": "S106",
            "reason": "Var naming | 8ce983fd5e"
        },
        {
            "line": "const QString key_f11              = \"F11\";             // 全屏",
            "line_number": 123,
            "rule": "S106",
            "reason": "Var naming | a2272d0c5c"
        },
        {
            "line": "const QString key_ctrl_1           = \"Ctrl+1\";          // 适合页面状态",
            "line_number": 124,
            "rule": "S106",
            "reason": "Var naming | 298036410c"
        },
        {
            "line": "const QString key_ctrl_2           = \"Ctrl+2\";          // 适合高度",
            "line_number": 125,
            "rule": "S106",
            "reason": "Var naming | bb89826f32"
        },
        {
            "line": "const QString key_ctrl_3           = \"Ctrl+3\";          // 适合宽度",
            "line_number": 126,
            "rule": "S106",
            "reason": "Var naming | 0ec78a6f33"
        },
        {
            "line": "const QString key_ctrl_d           = \"Ctrl+D\";          // 添加书签",
            "line_number": 127,
            "rule": "S106",
            "reason": "Var naming | 55b590dac6"
        },
        {
            "line": "const QString key_ctrl_f           = \"Ctrl+F\";          // 搜索",
            "line_number": 128,
            "rule": "S106",
            "reason": "Var naming | c37c14ca83"
        },
        {
            "line": "const QString key_ctrl_o           = \"Ctrl+O\";          // 打开",
            "line_number": 129,
            "rule": "S106",
            "reason": "Var naming | 71c792ad13"
        },
        {
            "line": "const QString key_ctrl_e           = \"Ctrl+E\";          // 导出",
            "line_number": 130,
            "rule": "S106",
            "reason": "Var naming | f21c130ba1"
        },
        {
            "line": "const QString key_ctrl_p           = \"Ctrl+P\";          // 打印",
            "line_number": 131,
            "rule": "S106",
            "reason": "Var naming | c6591979a9"
        },
        {
            "line": "const QString key_ctrl_s           = \"Ctrl+S\";          // 保存",
            "line_number": 132,
            "rule": "S106",
            "reason": "Var naming | 7c224c84ee"
        },
        {
            "line": "const QString key_ctrl_m           = \"Ctrl+M\";          // 打开目标缩略图",
            "line_number": 133,
            "rule": "S106",
            "reason": "Var naming | f723ab894f"
        },
        {
            "line": "const QString key_ctrl_r           = \"Ctrl+R\";          // 左旋转",
            "line_number": 134,
            "rule": "S106",
            "reason": "Var naming | d3f2cb7d2b"
        },
        {
            "line": "const QString key_ctrl_c           = \"Ctrl+C\";",
            "line_number": 135,
            "rule": "S106",
            "reason": "Var naming | 7191938108"
        },
        {
            "line": "const QString key_ctrl_x           = \"Ctrl+X\";",
            "line_number": 136,
            "rule": "S106",
            "reason": "Var naming | a6dd4ba68a"
        },
        {
            "line": "const QString key_ctrl_v           = \"Ctrl+V\";",
            "line_number": 137,
            "rule": "S106",
            "reason": "Var naming | 241a1788e0"
        },
        {
            "line": "const QString key_ctrl_z           = \"Ctrl+Z\";",
            "line_number": 138,
            "rule": "S106",
            "reason": "Var naming | f78601e55e"
        },
        {
            "line": "const QString key_ctrl_a           = \"Ctrl+A\";",
            "line_number": 139,
            "rule": "S106",
            "reason": "Var naming | 4774d3cc37"
        },
        {
            "line": "const QString key_ctrl_equal       = \"Ctrl+=\";          // 放大",
            "line_number": 140,
            "rule": "S106",
            "reason": "Var naming | 51a1643479"
        },
        {
            "line": "const QString key_ctrl_smaller     = \"Ctrl+-\";          // 缩小",
            "line_number": 141,
            "rule": "S106",
            "reason": "Var naming | 2c983162a1"
        },
        {
            "line": "const QString key_alt_1            = \"Alt+1\";           // 选择工具",
            "line_number": 142,
            "rule": "S106",
            "reason": "Var naming | a0378f280b"
        },
        {
            "line": "const QString key_alt_2            = \"Alt+2\";           // 手型工具",
            "line_number": 143,
            "rule": "S106",
            "reason": "Var naming | 57ced1cd00"
        },
        {
            "line": "const QString key_alt_a            = \"Alt+A\";           // 添加注释",
            "line_number": 144,
            "rule": "S106",
            "reason": "Var naming | 3c60d1d86d"
        },
        {
            "line": "const QString key_alt_h            = \"Alt+H\";           // 添加高亮",
            "line_number": 145,
            "rule": "S106",
            "reason": "Var naming | 1878434593"
        },
        {
            "line": "const QString key_alt_z            = \"Alt+Z\";           // 放大镜",
            "line_number": 146,
            "rule": "S106",
            "reason": "Var naming | e48b2efc36"
        },
        {
            "line": "const QString key_alt_f4           = \"Alt+F4\";          // 退出应用程序",
            "line_number": 147,
            "rule": "S106",
            "reason": "Var naming | d225da4d6e"
        },
        {
            "line": "const QString key_alt_harger       = \"Ctrl++\";          // 放大",
            "line_number": 148,
            "rule": "S106",
            "reason": "Var naming | 9e19ceeedd"
        },
        {
            "line": "const QString key_ctrl_shift_r     = \"Ctrl+Shift+R\";    // 右旋转",
            "line_number": 149,
            "rule": "S106",
            "reason": "Var naming | 6be0727d79"
        },
        {
            "line": "const QString key_ctrl_shift_s     = \"Ctrl+Shift+S\";    // 另存为",
            "line_number": 150,
            "rule": "S106",
            "reason": "Var naming | 8f81237f85"
        },
        {
            "line": "const QString key_ctrl_shift_slash = \"Ctrl+Shift+/\";",
            "line_number": 151,
            "rule": "S106",
            "reason": "Var naming | bad1d49dcc"
        },
        {
            "line": "const QString key_ctrl_home        = \"Ctrl+Home\";       //第一页",
            "line_number": 152,
            "rule": "S106",
            "reason": "Var naming | bff733899f"
        },
        {
            "line": "const QString key_ctrl_end         = \"Ctrl+End\";        //最后一页",
            "line_number": 153,
            "rule": "S106",
            "reason": "Var naming | 7cbe7a3f8b"
        }
    ],
    "assets/mimetype/ofd.xml": [
        {
            "line": "<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">",
            "line_number": 2,
            "rule": "S35",
            "reason": "Url link | 4072667606"
        }
    ]
}

@add-uos

add-uos commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Hi, @hualet thanks for your PR! There's two issues here:

1. render region outside canvas

[Warning] [org.deepin.reader] <deepin_reader::OfdDocument::renderPage:493> OFD render region outside canvas: QRect(1000,0 1000x1542) QRect(0,0 1090x1542)
[Warning] [org.deepin.reader] <deepin_reader::OfdDocument::renderPage:493> OFD render region outside canvas: QRect(1000,0 1000x1561) QRect(0,0 1104x1562)

_._20260911152618.mp4

2.renderer returned a diagnostic kind unknown to C ABI v1
https://github.com/linuxdeepin/rofd/tests/ofdrw-compat/fixtures/converter/发票监制章-数科.ofd

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants