V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
xmuli
V2EX  ›  分享创造

〖下〗嘿嘿!开发了一款 Sunny 截图 & 钉图软件,亦支持"幕识图"和"OCR"

  •  
  •   xmuli · 266 天前 · 1998 次点击
    这是一个创建于 266 天前的主题,其中的信息可能已经有所发展或是发生改变。

    发帖时提示:主题内容不能超过 20000 个字符,故拆成〖上、下〗两篇;此文为下篇

    • 上篇 详细介绍功能和效果图
    • 下篇 细致分享写此软件的编码经验,提供后来者参考

    番外:意料之外

    分享一下喜悦

    在 v1.3 发布的那天晚上,记得 downloads 是 900+ 的样子;发布完了就去睡觉了。

    第二天早上一看下载量就是 1k ,1.1k ;中午再看一眼就是 1.2k ;晚上再看就是 1.3k ;

    第三天是 1.4k ,

    第四天是 1.5k ,

    ... ...哈哈哈哈哈哈哈哈哈, 放假回家过年了,也没怎么看

    约大大前天回来一看,嗯,还是 1.5k ,大家玩的开心愉快

    大前天到了 1.6k

    前天到了 1.7k

    昨天号到了 1.7k

    今天的到了 1.8k , 纪念打卡(--写这篇时)

    在写过的所有软件中,总的下载量虽然不是最大的,但短时间增速率长是最快的 ヾ(≧▽≦*)o 。


    截图作品系列

    很久之前就想些一个软件截图的软件,目前一共写如下三个层级的难度作品,提供大家参考


    项目 描述 开发经验
    ShotX 功能极简的截图工具 简易,新手级的截图,适合初学 Qt/C++ 入门
    FLIPPED 简洁且漂亮,功能完整的截图软件;隐私安全,无任何联网功能 高级难度,属 Qt/C++ 数年经验的进阶作品,在借鉴同类作品的代码时,可于探索中独立完成的一个大的软件
    Sunny 一款简洁且漂亮的截图的软件工具。亦支持图片翻译和 OCR ;已上架微软商店,深度/统信商店,及三方的星火商店等 专业级作品,适合已多年沉浸研究 Qt/C++ 经验,随心所欲写任意所需功能,属于商业级的成熟作品,是本截图系列的最高水准之作

    • Ⅰ. 新手之作 ShotX

      • 项目地址:ShotX | 镜像
      • 功 能:①基本的截图功能,复制和保存,②右键托盘及菜单,③支持 Window ,MacOS ,Linux ,④攥写 Github-Action 的 CI/CD 自动脚本 .yml ;实现自动打包和发布,⑤更多见 README 和 源码
      • 描 述:新手级的截图,适合初学 Qt/C++ 入门者
    • Ⅱ. 高级之作 FLIPPED

      • 官 网:flipped.xmuli.tech
      • 项目地址:FLIPPED | 镜像
      • 功 能:①贴图和钉图,②多屏截图,延时截图,自定义截图,③智能检测窗口矩形( Windows & Linux ),④矩形、椭圆、箭头、画笔、马赛克、文本、序号,⑤撤销、重做(多级)、保存、取消、拷贝到剪切板,⑥截图框样式三套,且主题色提供自定义;屏幕十字线样式自定义,⑦国际化:英文、简体中文、繁体中文;字体和字号自定义,⑧支持设置窗口,托盘,截图区域之间的流畅切换,⑨更多见 README 和 源码
      • 描 述:高级难度,适合已学习 Qt/C++ 数年经验进阶,需同类型软件的代码借鉴,但可探索中独立写一个大的软件。出发于隐私安全,无任何联网功能。
    • Ⅲ. 商业级别的成熟之作 Sunny (推荐)

      • 官 网:sunny.xmuli.tech
      • 项目地址:Sunny | 镜像
      • 功 能:是 FLIPPED 作品的超集合,常见截图功能都都包含。还包含额外的功能:① "图片翻译" (中/英/日/韩/俄等),和"OCR 提取文字",也支持用户私人 token 的额度使用 ,② .iss 脚本和 CMake 来提供便携版,安装版,③ 绘画工具栏的亚克力效果,且支持跨平台(毛玻璃效果),④编辑文本支持富文本,同一个注释可采用多个字体和颜色等(暂未遇到其它同类软件也能做到),⑤全新的 UI/UE 设计交互,“设置窗口” 无任何缝隙拼接感,颜值达到简约美观,⑥优化截屏完成后的内存释放;⑦国际化翻译更方便,⑧CMake 重写拆分为 EXE + DLL 隔离,⑨进行代码签名,方便下载校验和防篡改,⑩成功上架 Window 的微软商店,Linux 的 深度/统信商店,以及三方的星火商店等;麒麟商店也在上架待审核
      • 描 述:基于前两个的项目经验和不足,直接重写了一套新的框架和 UI 界面;目前个人从代码功能和产品体验来说,已经达到 工程代码整洁、规范、稳定和健壮性,优秀的解耦机制,漂亮简约得 UI / UX 设计,可以随时应对变化的实际需求,很久之内都无需重构了。定位为 漂亮和简洁,功能实用为主。

    注: ShotX ,FLIPPED ,Sunny 这三款均支持跨平台 Windows / MacOS / Linux 。

    Sunny = FLIPPED 的功能重构 + 代码重构 + UI 重构 + 网络功能(图片翻译+OCR )+ 上架应用商店 + 后续新功能;而 ShotX 是最早的练手探索

    如何开发一款截图软件呢?

    在写和发布的后的期间,也遇到很多私聊请教 、 邮件沟通某个功能实现?反馈 Bug 和给出使用心得和建议;都给答疑了,但想来可写为一整篇,中间遇到的困难点都写出来,公开出来提供后来者参考。

    编译环境

    💻 MacOS 13 📎 Qt 5.15.2 📎 gcc/g++ 9.2 📎 gdb8.3

    💻 Ubuntu 22.04 📎Deepin 20.9-23+ 📎 Qt 5.15.2 📎 gcc/g++ 9.0 📎 gdb8.0

    💻 win10 22H2 📎 Qt 5.15.2 📎 Visual Studio 2022 📎 C++17




    [整体思路]

    • 基础窗口: 创建一个 QWidget 窗口,去掉标题栏后,全屏且置顶,捕获此刻多屏幕状态保存为 QPixamp ,然后绘画在 QWidget 最底层,再绘画一层透明黑色作为遮罩
    • 绘画工具栏: 作为是一个单独的子窗口,包含两个一级和二级的绘画工具栏,控制二级的显隐
    • 鼠标光标: 将 QWidget 放于虚拟桌面的左上角;相对坐标和绝对坐标的转换
    • 功能思路: 时刻判断当前所处模式:Wait / Select / Move / Draw / Stretch 标记;根据模式标记,对鼠标的 Press / Move / Release 事件进行对应的操作;重点是鼠标放下和松开时的 QPoint
      • 捕获模式:智能窗口 / 全屏截图 / 延时截图 / 自定义截图 等
      • 绘画模式则细分:一级绘画栏和二级绘画栏(愈加精确的参数)
      • 拉伸可为:拉伸已绘图形 / 选中框 / … ,操作是可见区域的任意一个图案
      • 移动同上
    • 钉图功能: 独立的窗口,将图片绘画在最底层,且需要重绘缩小一圈,为毛玻璃的彩虹灯预留位置
    • 杂项但重要: 国际化,不重启切换语言字体,编译,打包,CI /CD ,热键,窗口尺寸遍历,显示窗口详细信息及大小,代码签名证书,上架应用商店;太多了,单独成篇写在下面

    [如何购买代码签名]


    [如何上架应用商城]

    • 『问题』如何上架到微软的 Microsoft Store ?如何上架 Linux 的深度/统信/麒麟商城,以及如三方的星火商店呢?

      篇幅太长,单写了一篇,包含详细上架 Windows Store ,Deepin/UOS Store, 三方 星火商店等。

      👉 《Sunny 截图上架 Microsoft Store 及 Linux 商店流程的指北

      Note:

      个人作品上架微软商店的流程很折磨,最后上架成功后也是拨开云雾;

      若是文章对你有价值,亦可帮我积累 Sunny 的微软信誉,或者在深度商店的好评,甚至感谢🙇‍ ;

      Windows 用户推荐的下载 👉 Sunny_setup_msvc_1.3.0_x64.exe


    [打包发布 Windows / MacOS / Linux 上]

    介绍多种平台和格式:①Windows:绿色便携版和安装包 .exe ②MacOS:.app.img ③Linux: 绿色版、 .deb.AppImage

    • 『问题』 Windows 如何构建打包为 .exe 文件?如何生成构绿色版和安装版?

      QT 项目在 Windows 平台上面发布成可执行程序

    • 『问题』 MacOS 如何构建打包为 .dmg 文件?

      QT 项目在 MacOS 平台上面发布成可执行程序

    • 『问题』 Linux 如何构建打包为 .deb 文件、如何打包为通用的 .AppImage 格式?

      • Linux 下又多种打包 .deb 打包方法:

        • 〖方法一〗通过 ldd.sh + Sunny.sh 两个脚本打包依赖,参考《QT 项目在 Linux 平台上面发布成可执行程序

        • 〖方法二〗通过 dh_make + dpkg-buildpackage 命令《Linux 中用 dh_make 将 Qt + CMake 项目打包为 deb 文件

        • 〖方法三,最推荐〗通过 CMake 的 cpack 命令,那样就不需要填写 debian 文件夹下的 control 等文件,直接拷贝相关资源文件过去。CMakeLists.txt 底部加上 CPack 的相关代码,核心如下:

          # CPACK: General Settings
          set (CPACK_GENERATOR "TBZ2")
          set (CPACK_PACKAGE_NAME "${project_name}")
          set (CPACK_PACKAGE_VERSION "${project_version}")
          set (CPACK_PACKAGE_VENDOR "https://github.com/XMuli")
          set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Simple and beautiful screenshot software tool for Windows, MacOS and Linux")
          set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
          set (CPACK_PACKAGE_CONTACT "https://sunny.xmuli.tech")
          # 设置 Debian 软件包的依赖关系
          set (CPACK_DEBIAN_PACKAGE_DEPENDS "libqt5x11extras5, libqt5svg5")
          set (CPACK_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}")
          set (CPACK_DEBIAN_PACKAGE_SHILIBDEPS ON)
          
          include(CPack)
          
      • Linux 下有多种打包 .AppImage 打包方法

        # [方式四] 使用 linuxdeployqt 方式打包,在 Ubuntu 22.04 打包,不可以使用 -----------------------------
        ####linuxdeployqt-continuous-x86_64.AppImage 方案可在 Ubuntu 22.04 上面不可行####
        $ ../linuxdeployqt-continuous-x86_64.AppImage Sunny -appimage
        $ sudo apt install  libfuse2
        
        但是由于过于作者的固执坚守旧的版本,所以无法使用,理由和可能的解决如下:
        https://github.com/probonopd/linuxdeployqt/issues/340#issuecomment-932712016
        即:使用 linuxdeploy 和 linuxdeploy-plugin-qt
        
        #####linuxdeploy-x86_64.AppImage + linuxdeploy-plugin-qt-x86_64.AppImage 下面方案可行#####
        https://github.com/BearKidsTeam/thplayer/blob/master/.github/workflows/linux.yml#L54
        
        $ sudo apt update
        $ sudo apt install qtbase5-dev qtmultimedia5-dev libqt5multimedia5-plugins
        $ sudo add-apt-repository universe
        $ sudo apt install libfuse2
        
        $ wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
        $ wget https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
        $ chmod +x linuxdeploy*.AppImage
        
        $ mkdir build && cd build
        $ cmake ..
        $ cmake --build . -j$(nproc)
        $ cd ..
        
        $ ../linuxdeploy-x86_64.AppImage --appdir AppDir -e bin/Sunny -d bin/resources/cpack/tech.xmuli.sunny.desktop -i bin/resources/logo/logo.svg --icon-filename tech.xmuli.sunny -p qt -o appimage
        
        $  ./linuxdeploy-x86_64.AppImage --appdir AppDir -e build/thplayer -d assets/thplayer.desktop -i assets/thplayer.svg --icon-filename thplayer -p qt -o appimage
        $ mv TouHou_Player*.AppImage thplayer-linux.AppImage
        
    • 『问题』如何书写 .yml 的脚本,通过 GitHub 的 Action 资源,自动打包构建生成 Release 呢?

      通过写三个系统的 .yml 脚本,路径必须是 .github/workflows ,随着时间的流逝⌛,想要持续构建对应的云系统和 Kit 也必须更新,文档和版本参见 images ,直接往 .yml 修改;这是一个实际可跑的脚本 *.yml 都是可以编译成功的,失败可能是额度时间不够了,如某次成功的示例,可看到头像是 GitHub 的头像发布的 Release-v6.1


    [ UI / UX 设计的效果]

    • 『问题』截图的一级二级的菜单工具栏,如何实现 Windows7 的透明磨砂 / Windows 的亚克力的效果,且能够支持 Windows / Linux / MacOS ?

      单纯实现亚克力效果不难,难在 Linux 和 MacOS 上也能实现这个效果?这是当时的一些探索和经验,总结了四种方法放置于 GitHub - AcrylicWindow

    • 『问题』如何实现一个完美的无边框窗口跨平台,且还要占用低,没有瑕疵 BUG ,还能白嫖?

      也折腾过,难度也很大,后来发现对于截图,费力可以实现,但是没必要,成本太大;结论:这样现成的没有,目前效果和跨平台都最佳的方案是framelesshelper, 有时放弃也是一种解决方案。

    • 『问题』如何实现国际化多语言的切换?尤其是未使用 Qt Designer 来创建 .ui 文件,遇到无 ui->retranslateUi(this) 函数?不重启软件便可以切换语言

      对于有有 .ui 的部分,可以通过 《Qt 项目(CMake)设置国际化支持》来解决。对于存手写的控件实现的,且大致实现的思路是:

      下拉框中切换语言时,发射信号 → 全局单例 → 信号和槽函 → 到主窗口的槽函数,在里面进行重新加载语言,所有相关的控件的默认文本,都写在这个函数里面,便可以不重启软件,直接实现语言切换成功


    [用户体验细节]

    • 『问题』是否需要管理员权限才能运行?

      全程不会弹 UAC 弹窗,不需要管理员权限就可以使用所有功能,也不会中途提权,仅普通用户权限即可,包括导向安装,静默安装,使用卸载;

    • 『问题』 Windows 和 Linux 支持一次截多个屏幕,MacOS 仅只能截图单个屏幕,如何实现呢?

      MacOS 除了系统自带的截图支持外,至今没有任何一个三方软件可以做到这点,包括大厂等某企鹅的截图的,无解。根原是属于此苹果接口没公开,至少没人能够发现。

    • 『问题』如何确保 MacOS 上的效果和 Window 上面保持外观的一致?

      一个难点是再 MacOS 上也要和再 Windows 的效果保持一致,于是对不同风格进行对比,但 Fusion 又会倒是 Setting 窗口非原生的样式,但好在十分接近;选取一个平衡点。另外还手绘画了一个二十多个自定义或者复杂控件。


    [看不见的优化]

    • 『问题』如何解决使用 ESC 取消截图后的内存泄露问题? QPointer 、智能指针、还是单例?

      也花了大力气来探究,在完成一次截图之后,内存的占用会在合适时机自动释放出来;这是定位在消耗内存的变量;开发环境显示器为 4K 27 寸 + 3K 笔记本双屏;

    • 『问题』对于使用单例模式不止一处时,有序需要多个单例用来传递或者保存数值时候,重复写很容易

      可采用奇异递归模板的方式,然后添加一个宏展开为友元类;多个单例都只用写一份,而前提是需要对 《C++ 类的六个特殊成员函数》 很熟悉,才能理解,属于优雅的一种实现。

    • 『问题』日志和崩溃生成 DUMP 记录?

      日志可以通过配置文件修改,若是遇到传说的崩溃,亦会自动生成 .dmp 和 崩溃原因;

      转储文件存放: C:/Users/用户名/AppData/Local/XMuli/Sunny/cache/Sunny_Dumps/dump_2024_02_29_11_31_30_714.dmp

      实现方法可通过 WIN API 来实现

      #ifdef _MSC_VER
      SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)ApplicationCrashHandler);//注冊异常捕获函数
      #endif
      

      额,你没接触过 DUMP ,完全不会对其进行解剖分析?也简单写了一个使用 WinDbg 进行入门

      WinDbg:入门分析 dmp 文件『一』》、《WinDbg:调试之附加进程生成 dmp 『二』

    • 『问题』希望单例运行 EXE ,确保全局唯一性?

      可以通过共享内存 QSharedMemory 和系统信号量 QSystemSemaphore ,双重保证程序在一台终端上,仅会运行一个;

      也能杜绝很罕见的一种情况,即使上次程序崩溃之后,但仍有残留的僵死进程,被误判当前没有启动。严谨(中指推一下眼镜)

      QString uniqueKey = "SunnyUniqueKey"; // 使用唯一的标识符来创建共享内存和系统信号量
      QSharedMemory sharedMemory;
      sharedMemory.setKey(uniqueKey);
      
      // 尝试附加到现有的共享内存并分离
      if (sharedMemory.attach()) {
          sharedMemory.detach();
      }
      
      // 尝试创建共享内存,如果已经存在,表示已经有一个实例在运行, 判断是为了确保在同一台计算机上只能运行一个相同实例的程序。
      if (!sharedMemory.create(1)) {
          qDebug() << "There is already an instance of the application running (by QSharedMemory)!";
          return 1;
      }
      
      // 创建系统信号量, 再尝试获取系统信号量,如果已经被其他实例持有,程序就退出, 判断是为了确保在多个进程同时启动时,只有一个进程能够继续执行。QSystemSemaphore 用于创建系统信号量,如果系统信号量已经被其他实例持有(比如由于上一次程序异常退出导致信号量未被释放),则 acquire 函数会返回 false ,
      QSystemSemaphore systemSemaphore(uniqueKey, 1, QSystemSemaphore::Open);
      if (!systemSemaphore.acquire()) {
          qDebug() << "There is already an instance of the application running (by QSystemSemaphore)!";
          return 1;
      }
      
      // ...程序其它逻辑
      
      // 释放系统信号量
      systemSemaphore.release();
      

    [ Qt / C++ 编码问题]


    [项目杂项]


    • [编译遇坑] [杂谈经验总结] 等有空再更

    系列地址

    QtExamples 欢迎 star ⭐ 和 fork 🍴 这个系列的 C++ / QT / DTK 学习,附学习由浅入深的目录,这里你可以学到如何亲自编写这类软件的经验,这是一系列完整的教程,并且永久免费

    15 条回复    2024-03-29 13:34:36 +08:00
    xmuli
        1
    xmuli  
    OP
       266 天前
    使用任何的截图中,感觉出彩、实用顺手加分或者痛点,都可以分享下🙇‍

    听不同人的实现奇思妙想,也很有意思,也可对 "截图 & 钉图 & 图片翻译 & OCR" 这几个核心功能,更好提升下;
    charlestang
        2
    charlestang  
       266 天前   ❤️ 1
    我以前最喜欢用的就是微信的截图了,不过呢,那个老是要启动微信,让我不是很喜欢。现在我用一款,叫 Snipaste 的免费软件。按 F1 呼起,画圈,画箭头,写文字,可以保存或者复制。感觉就很够用了。就是它的箭头,几何图形都太丑了。缺乏美感。保存的时候,如果允许我简单加工一下,比如,增加阴影(为了在博客贴图),调整格式 PNG ,WebP 等,就更好了。
    xmuli
        3
    xmuli  
    OP
       266 天前 via iPhone
    @charlestang 多谢建议,FSC 对各种箭头编辑需求也很棒
    neochen13
        4
    neochen13  
       266 天前
    没发现支持 M1 处理器的 MacOS 安装包……
    xmuli
        5
    xmuli  
    OP
       266 天前
    @neochen13 昨夜用 intel MBP 编译的,但没买 M 的设备,你可以先试一下 M 芯片能不能跑;后面有机会用 M 芯来编译一份上传下一个 dmg ;
    charlestang
        6
    charlestang  
       266 天前
    Mac 版的 dmg 下载下来,打开一看没有图标
    xmuli
        7
    xmuli  
    OP
       266 天前 via iPhone
    @charlestang mbp 丢老家了,现在一直是用的 windows 开发。后面腾出手研究下怎么 mac 加图标的方法
    xmuli
        8
    xmuli  
    OP
       266 天前 via iPhone
    @xmuli 刚在一位铁子的 M3 实体机试了下,qt 5.15 不支持,等以后 qt 升级 > 6.2 再来编译 M 的
    neochen13
        9
    neochen13  
       266 天前
    @xmuli #5 好的,谢谢老哥,主要现在新 MBP 都是 M 处理器,很遗憾
    sunmoon1983
        10
    sunmoon1983  
       265 天前
    要是能高清录制屏幕就好了
    xmuli
        11
    xmuli  
    OP
       265 天前 via iPhone
    @sunmoon1983 GIF 功能已经写好了,但是还没集成进来,高清录屏暂不着急
    subframe75361
        12
    subframe75361  
       264 天前   ❤️ 1
    个人刚需:本地 OCR+Gif 录制

    在用 pixpin ,但是 Gif 录制效果不是很好

    期待可以替换~
    xmuli
        13
    xmuli  
    OP
       262 天前
    @subframe75361 好滴,
    locochen
        14
    locochen  
       239 天前
    在用重量级的老 App ,Snagit , 大杂烩的。

    最多的是截图,标注。 然后是录屏(包括声音)。
    虽然很重。 但是确实开箱即用,不同来回点过来,点过去到处 copy ,paste 编辑。
    xmuli
        15
    xmuli  
    OP
       238 天前 via iPhone
    @locochen 记忆被打开,很久以前听过这个名字
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2355 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 15:52 · PVG 23:52 · LAX 07:52 · JFK 10:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.