1. 项目背景:摄影爱好者的“整理焦虑”与解决方案

作为一名摄影爱好者,我深知每次拍摄归来后的整理之痛:将 SD 卡插入电脑,面对的是相机生成的 DCIM/100CANON 这类巨型文件夹,里面散落着成百上千个名为 IMG_7829.JPG 的无序文件。手动归档这些“原始素材”,成了创作流程中最枯燥的环节。

反观智能手机,iOS 和 Android 系统早已通过底层算法实现了照片的自动化归类——按时间、地点聚合展示。然而,相机作为纯粹的采集设备,只负责录入,不负责组织。正是这一痛点,催生了 C-SORTING 项目的诞生:让相机导入的照片,也能像手机相册一样获得智能、美观、完全离线的自动化分类。


2. 技术架构:极简交互与底层性能的平衡

C-SORTING 的开发遵循三大核心原则:极简交互绝对隐私(全离线)极致性能

2.1 前端界面:基于 PyQt6 的现代化重构

为了打破传统 Python GUI 工具“灰扑扑”的刻板印象,C-SORTING 采用 PyQt6 构建现代化的用户界面。在 app.py 中,我实现了一套基于 QSS 字符串注入的主题系统,支持 10 种配色方案与深色模式的动态切换。

# src/gui/app.py - 动态样式表注入逻辑
def get_stylesheet(self):
    primary = self.current_theme_color
    bg = "#ffffff" if not self.is_dark_mode else "#1c1c1e"
    sidebar_bg = "#f5f5f7" if not self.is_dark_mode else "#121212"
    text_color = "#1d1d1f" if not self.is_dark_mode else "#f5f5f7"
    
    return f"""
    QWidget {{
        background-color: {bg};
        color: {text_color};
        font-family: "Segoe UI", "PingFang SC", sans-serif;
    }}
    #Sidebar {{
        background-color: {sidebar_bg};
        border-right: 1px solid {'#d2d2d7' if not self.is_dark_mode else '#38383a'};
    }}
    #Sidebar QPushButton:hover {{
        background-color: {primary}20; /* 20% 透明度的主题色 */
    }}
    """

2.2 数据采集:EXIF 信息的深度解析

分类算法的数据基础来源于照片的 EXIF 信息。在 exif_utils.py 中,我们实现了对拍摄时间与 GPS 坐标的稳定提取。

# src/exif_utils.py - 核心元数据解析逻辑
def get_photo_metadata(path: str) -> Dict[str, Optional[object]]:
    meta = {"datetime": None, "gps": None}
    exif = _get_exif(path) # 获取原始 EXIF 字典
    if not exif:
        return meta
    
    # 维度 1: 拍摄时间 (优先读取原始拍摄时间)
    dt = exif.get('DateTimeOriginal') or exif.get('DateTime')
    if dt:
        meta['datetime'] = dt
        
    # 维度 2: GPS 坐标转换 (从度分秒元组转为十进制浮点数)
    gps = _get_gps_info(exif)
    if gps:
        lat = _convert_to_degrees(gps['GPSLatitude'])
        lon = _convert_to_degrees(gps['GPSLongitude'])
        meta['gps'] = (lat, lon)
    return meta

2.3 性能优化:双重并发模型

针对照片整理涉及的大量磁盘 I/O 操作,C-SORTING 设计了 双重并发模型:将繁重的文件操作封装在继承自 QThread 的 SortWorker 中。

# src/gui/app.py - 异步任务执行器
class SortWorker(QThread):
    progress = pyqtSignal(str) # 进度反馈信号
    finished = pyqtSignal(dict) # 完成任务信号

    def run(self):
        # 1. 在后台线程扫描文件树
        items = scan_folder(self.folder)
        
        # 2. 根据用户选择的模式(日期/城市)进行分组
        if self.mode == 'date':
            groups = group_by_date(items)
        # ...
        
        # 3. 执行物理移动或复制,不阻塞 UI 刷新
        move_grouped_items(groups, target_path, copy=self.copy_mode)
        self.finished.emit({"success": True})

3. 核心技术突破:实现 100% 离线地理编码

这是 C-SORTING 研发过程中最具转折意义的技术决策。为了保护隐私并提升速度,我放弃了云端地图 API,在 geocode.py 中实现了本地匹配算法。

# src/geocode.py - 离线地理编码算法
def latlon_to_city(lat: float, lon: float) -> Optional[str]:
    # 核心原理:根据经纬度反查预置的 337 个地级市中心点坐标
    min_dist = float('inf')
    found_city = None

    for city, coord in CHINA_CITIES.items():
        # 这里使用了加权欧几里得距离简化球面计算,极大提升匹配效率
        d_lat = lat - coord[0]
        d_lon = (lon - coord[1]) * 0.86 # 针对中国纬度的经度加权
        dist_sq = d_lat**2 + d_lon**2
        
        if dist_sq < min_dist:
            min_dist = dist_sq
            found_city = city
            
    return _clean_city_suffix(found_city) # 去除“市/地区/自治州”等后缀

4. 版本演进:从单一分类工具到综合媒体管家

v1.1.0:全能型功能扩展

2026 年度的重大更新实现了跨媒体支持。在 SortWorker 中,我们引入了分流逻辑,使得相机录制的视频(MP4/MOV)也能被精准归档。

# src/sorter.py - 媒体类型识别逻辑
IMAGE_SUFFIXES = {'.jpg', '.jpeg', '.png', '.heic', '.webp'}
VIDEO_SUFFIXES = {'.mp4', '.mov', '.avi', '.mkv'}

def scan_folder(folder: Path) -> List[MediaItem]:
    items = []
    for p in folder.rglob('*'):
        suffix = p.suffix.lower()
        if suffix in IMAGE_SUFFIXES:
            items.append(MediaItem(p, 'image'))
        elif suffix in VIDEO_SUFFIXES:
            items.append(MediaItem(p, 'video'))
    return items

5. 项目结构设计

C-SORTING 的代码组织遵循高内聚低耦合原则:

  • gui/:负责用户交互层,利用信号与槽机制解耦 UI 与逻辑。
  • sorter.py:实现文件夹扫描、分组聚类及物理分拣的核心逻辑。
  • exif_utils.py:作为“感知层”,提供对媒体文件底层元数据的访问能力。
  • packaging/:内置主流 Linux 发行版的打包配置,确保跨平台体验的一致性。

6. 开发者总结与未完成功能

作为开发者,最大的成就感并非来自复杂算法的实现,而是看到用户桌面那个 50GB 的“2026旅行待整理”文件夹,在几分钟内被重构为结构清晰的分类目录:

这种由混乱回归秩序的体验,正是 C-SORTING 存在的核心价值。在数据爆炸的时代,优秀的工具不应只是处理数据,更要帮助用户重建数字生活的秩序感。

与此同时,项目还预留了本地小模型接口,用于实现以人脸/宠物/场景/自拍等分类,受限于知识储备尚未完善,预计在一个月之内完成,GitHub和博客会同步更新,敬请期待。


项目开源信息

此作者没有提供个人介绍。
最后更新于 2026-02-24