Skip to content

xeonliu/cp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CP(CardCopier)

一个使用 PyQt6 编写的桌面导入工具,用于从磁盘或存储卡中批量导入照片与视频,并提供去重、按日期组织、预览和统计等能力。整体交互设计的灵感来自一些专业相片管理软件的导入体验。

目前主要围绕以下几个目标设计:

  • 导入前尽量看清楚会发生什么(预览树 + 统计)
  • 自动去重,避免重复拷贝
  • 不阻塞 UI,在大批量 RAW 文件时仍然可操作

功能概览

  • 文件扫描

    • 从左侧“来源”树选择文件夹,点击“扫描”后,在后台线程中遍历文件。
    • 支持常见图片与 RAW 格式:JPG/JPEG/PNG/ARW/CR2/NEF/DNG/ORF/RW2,以及 MP4/MOV 等视频格式。
    • 可选“递归扫描”,扫描子目录时会忽略隐藏目录(以 . 开头)。
  • 日期分组与导入预览

    • 中间区域按“日期分组”展示文件,每个日期对应一个 DateSection 网格。
    • 右侧“目标位置”中,会根据当前设置计算导入路径,并构建一棵“目录结构预览树”。
    • 预览树中可以看到导入后将创建哪些子目录、每个目录下会导入多少文件。
  • 去重逻辑

    • 扫描完成后,会根据目标路径计算每个源文件的“导入目标文件路径”。
    • 如果目标位置已经存在同名文件,并且通过内容比对(例如 MD5)判定为相同:
      • 该源文件会被标记为“重复”,在中间网格中隐藏、且取消勾选;
      • 在统计中计入“重复跳过”的数量;
      • 不会出现在右侧导入结果预览中,也不会再次拷贝。
  • 选择与勾选逻辑

    • 每个缩略图条目旁边有一个勾选框,控制“是否导入该文件”。
    • 点击缩略图区域只会更新右侧预览,不会影响勾选状态。
    • 扫描完成后,默认会勾选所有非重复文件,方便“一键全选导入”。
    • 勾选状态会实时反映到右侧目录预览树和统计中。
  • 缩略图开关与延迟加载

    • 右侧“导入设置”中提供选项:
      • 生成缩略图(可能较慢)
    • 默认关闭缩略图生成
      • 扫描时仍会列出所有文件,但使用统一灰色占位图标,不进行任何图片解码,CPU 占用较低。
    • 仅当勾选此选项时才会生成缩略图:
      • 缩略图在后台线程中加载,不阻塞 UI。
      • 对 RAW 文件优先尝试读取内嵌 JPEG 缩略图;如果没有,则使用 rawpy.postprocess(half_size=True) 生成较小图像。
    • 已实现视口级别的延迟加载
      • 仅对当前滚动区域内“看得见”的条目批量生成缩略图,每批最多处理固定数量(例如 32 个)。
      • 向下滚动时,新的可见条目会被检测并加入下一批加载队列。
      • 对大批量文件时,不会一次性解码全部缩略图,大幅降低 CPU 和内存压力。
  • 预览面板

    • 右侧“预览”区域显示当前选中文件的大图和基本信息。
    • 与中间网格/勾选逻辑解耦:预览只是“查看”,勾选才决定是否导入。
    • 对 RAW 文件,预览会按需解码单张图像。
  • 导入统计

    • 右下角“统计”区域会展示:
      • 已选择的文件数量;
      • 预计复制大小(如果实现);
      • 重复文件数量等。
    • 勾选 / 去重 / 设置变更后会自动刷新统计。
  • 性能与稳定性

    • 文件扫描、缩略图加载、实际导入操作均放在后台线程,避免卡死 UI。
    • 对目录结构重建、导入预览等操作增加了 debounce(延迟合并刷新),减少重复计算。
    • 提供 cProfile 支持,可以快速分析性能瓶颈。

安装与运行

依赖

项目基于:

  • Python 3.12(.python-version 中指定)
  • PyQt6
  • rawpy
  • imageio
  • numpy

依赖信息在 pyproject.toml 中已经列出,建议使用你熟悉的工具(如 uvpippoetry)安装。

示例(使用 pip,仅供参考):

pip install -e .

或直接根据 pyproject.toml 中的依赖列表安装。

启动程序

在项目根目录下:

python3 main.py

程序启动后,会打开主窗口。


基本使用流程

  1. 选择来源文件夹

    • 在左侧“来源”树中选择要导入的文件夹。
    • 勾选“递归扫描”可包含子目录,不勾选则只扫描当前目录。
  2. 扫描文件

    • 点击“扫描”按钮开始扫描。
    • 中间区域会按日期分组显示文件,每个条目带一个勾选框。
    • 默认情况下不生成缩略图,只显示占位图(可以在右侧打开缩略图)。
  3. 调整导入设置

    • 在右侧“导入设置”中:
      • 选择“按日期组织文件”与否;
      • 设置“日期格式”(如 YYYY-MM-DDYYYY/MM/DD 等);
      • 选择时间源:
        • 文件修改时间(默认)
        • 拍摄时间 (EXIF)(如果文件带 EXIF 信息);
      • 可选填写“自定义模板”,如:
        • {year}/{month:02d}/{day:02d}
        • {year}-{month}-{day} 等。
    • 在“目标位置”中选择导入的主目录,预览树会根据当前设置实时更新。
  4. 勾选要导入的文件

    • 中间网格每个条目旁边的勾选框控制是否导入该文件。
    • 扫描和去重完成后,默认勾选所有非重复文件。
    • 点击缩略图区域只会更新右侧预览,不改变勾选状态。
    • 去重后的重复文件会被自动隐藏并取消勾选,不会出现在预览树中。
  5. 预览导入结果

    • 在右侧“目标位置”的树中,可以看到导入后将创建的目录结构和每个目录下的文件计数。
    • “统计”区域显示当前勾选的文件数量等信息。
  6. 执行导入

    • 核对无误后,点击“导入”按钮开始实际拷贝。
    • 导入过程在后台线程处理,同时更新进度与状态。

缩略图行为说明

  1. 缩略图开关

右侧“导入设置”中有一项:

  • 生成缩略图(可能较慢)

默认关闭,关闭时:

  • 仅显示灰色占位图;
  • 不对任何文件进行缩略图解码;
  • 在大量 RAW 文件场景下,CPU 占用明显降低。

勾选开启后:

  • 扫描时仍然先用占位符把所有文件列出来,保证 UI 流畅;
  • 后台线程会为部分文件生成真实缩略图。
  1. 视口级延迟加载

为进一步减少负载,实现了“只为视口附近项目生成缩略图”的逻辑:

  • 每次扫描或滚动时,会计算当前 ScrollArea 的可见区域;
  • 遍历每个日期分组的 QListWidget,只处理与可见区域有交集的条目;
  • 对这些条目中尚未加载过的文件,按批加入缩略图加载队列(每批最多约 32 个);
  • 后台线程依次为这些文件生成缩略图,并在完成后更新对应条目的图标。

这样在成千上万张图的场景下,也只会为“眼前看到的”和“附近”少量项目解码缩略图,大幅减少不必要的计算。


性能分析(可选)

为方便排查性能问题,程序支持通过 cProfile 进行性能分析。

大致用法(示例,具体以 main.py 实现为准):

python3 main.py --profile --profile-output myrun.prof

运行结束后,可以使用:

python3 -m pstats myrun.prof

查看性能热点,例如缩略图加载、目录扫描、去重等部分的时间占比。


已实现的关键点小结

  • 支持常见 RAW 格式(含 RW2)与常见视频格式;
  • 后台线程扫描,UI 不随文件数量线性卡死;
  • 自动按日期分组显示,支持多种日期格式及自定义模板;
  • 导入前通过目录树预览将要创建的目录结构和文件分布;
  • 基于目标路径和内容比对的去重逻辑,避免重复导入;
  • 缩略图默认关闭,可按需开启,并实现“只为视口附近项目生成缩略图”的延迟加载;
  • 勾选逻辑与预览解耦:勾选控制导入,点击控制预览;
  • 提供基础性能分析支持,方便进一步优化。

后续可以在此基础上继续扩展,例如:

  • 更细粒度的导入规则(按相机型号、镜头、评分等);
  • 磁盘级缩略图缓存,避免重复 RAW 解码;
  • 更完善的错误提示和日志系统等。

About

CP(CardCopier)can import images and videos form External Devices in a Lightroom way.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages