
图像处理桌面应用【免费下载链接】CompositorThe Photoshop alternative for Mac项目地址https://gitcode.com/gh_mirrors/compos/Compositor点击查看免费下载Compositor 是 macOS 平台上的 Photoshop 替代应用其项目文件.comp采用 macOS 文档包document package格式将 JSON 清单与 PNG 像素资产组织在一个文件夹中实现无损、可移植、源图无关的保存。本文以仓库文档 docs/project-format.md 为骨架结合 ProjectStore.swift、ProjectController.swift 等源码与 ProjectTests.swift 等测试完整讲解.comp的目录结构、manifest 字段、从 v1 到 v7 的版本演进、全部限制阈值与校验规则帮助开发者理解格式设计、排查兼容性问题或实现同类文档格式。一、.comp 是什么macOS 文档包与“内嵌像素”设计一个.comp文件本质上是 macOS 文档包package——在 Finder 中表现为单个文件在文件系统中是一个文件夹。其内部结构固定为两部分MyProject.comp/ ├── manifest.json # 项目元数据JSONUTF-8 └── images/ # 图层与蒙版像素资产 ├── layer UUID.png # 每个像素图层一个 PNG └── layer UUID.mask.png # 每个蒙版一个 8-bit 灰度 PNGv4 起在代码层面这一类型通过UTType(exportedAs: com.compositor.project, conformingTo: .package)注册见 ProjectStore.swift因此系统将其视为“包”而非普通目录NSOpenPanel等文件对话框默认不会把用户带进包内部。为什么把像素内嵌进包里这是.comp格式最核心的设计决策嵌入式 PNG 保留源照片的原始像素与透明度图层的变换transform始终作为独立元数据保存从不写回像素因此项目在移动、重命名甚至删除导入的源照片之后依然完整可用——ProjectTests.swift 中的projectRoundTripSurvivesSourceRemovalAndPackageMove测试专门验证了“删除源图 → 保存 → 移动包 → 重新打开”后文档、图层、变换、分辨率全部一致保存采用“协调式原子替换”见下文第四节失败不会破坏已有文件。二、manifest.json 核心结构字段与取值manifest 由ProjectManifest结构体定义ProjectStore.swift保存时使用JSONEncoder并以.prettyPrinted、.sortedKeys格式写出ProjectStore.swift便于阅读与 diff。2.1 顶层字段字段类型说明formatString固定为com.compositor.project标识格式身份versionInt格式版本号。文档撰写时新保存为 v6当前源码中已提升为7见第七节colorSpaceString工作色彩空间固定为sRGBresolutionDouble?可选。每英寸像素数ppi取值范围 1–9600旧清单缺省视为 72代码注释原文Older version-1 projects default to 72 pixels/inchdocumentIDUUID文档唯一标识跨会话保持width/heightInt画布像素尺寸各 1–30000activeLayerIDUUID?当前活动图层必须存在于layers中否则校验失败layers[ProjectLayerRecord]图层数组自底向上排序2.2 图层记录字段每个图层由ProjectLayerRecord定义ProjectStore.swift字段类型引入版本说明idUUIDv1图层唯一标识同时决定资产文件名nameStringv1图层名去空白后非空UTF-8 编码长度 ≤ 16384 字节isVisibleBoolv1可见性标志transform对象v1变换origin原点、size尺寸、rotation顺时针旋转角、flipX/flipY翻转、sampling采样方式imageFileString?v1可选空白图层无图像资产。必须严格等于id.uuidString.pngparentIDUUID?v2父组 ID根节点缺省isGroupBool?v2是否组文件夹组不允许有imageFileopacityDouble?v30–1 有限值缺省 1blendModeString?v3Normal / Multiply / Screen / Overlay / Darken / Lighten / Difference / Color Dodge / Color Burn缺省 NormalmaskFileString?v4蒙版文件名必须严格等于id.uuidString.mask.pngmaskEnabledBool?v4缺省在存在蒙版时为 truemaskSourceIDUUID?v5实时蒙版剪贴蒙版的源图层 UUIDadjustment对象?v7调整图层参数见第七节maskPlacement/maskLinked对象?/Bool?源码扩展蒙版脱离图层后的文档位置与链接状态代码中已有文档正文未详述effects对象?源码扩展图层效果见第八节text对象?源码扩展可编辑文本元数据见第六节2.3 示意 manifest结构示意字段名以源码 Codable 为准{ format: com.compositor.project, version: 7, colorSpace: sRGB, resolution: 300, documentID: 8A2F3B1C-0000-0000-0000-000000000001, width: 1920, height: 1080, activeLayerID: 8A2F3B1C-0000-0000-0000-00000000000A, layers: [ { id: 8A2F3B1C-0000-0000-0000-00000000000A, name: 背景照片, isVisible: true, transform: { origin: [0, 0], size: [1920, 1080], rotation: 0, flipX: false, flipY: false, sampling: bicubic }, imageFile: 8A2F3B1C-0000-0000-0000-00000000000A.png, opacity: 1, blendMode: Normal, maskFile: 8A2F3B1C-0000-0000-0000-00000000000A.mask.png, maskEnabled: true } ] }三、硬性限制画布、像素、文件与清单阈值project-format.md给出了一组明确上限全部可在 ProjectStore.swift 的validate与checkSize中逐条对应限制项阈值代码位置画布/单张图像每边≤ 30,000 像素validate与checkSize全部图像源像素总量≤ 100,000,0001 亿checkSize累加used全部蒙版像素总量≤ 100,000,000独立于图像checkSize对 mask 单独累加图层数量≤ 10,000validatemanifest.json 体积≤ 4 MiB保存与加载两侧均检查单个编码资产体积≤ 512 MiB加载时checkFile保存时经 PNG 编码后写入其中像素总量采用“边读边累加”的方式checkSize(width:height:used:)先验证每边不超过 30000再验证width * height 100_000_000 - usedProjectStore.swift超出即抛ProjectError.tooLarge错误信息明确提示“exceeds the supported canvas, layer, file-size, or 100-megapixel image limit”。蒙版在 v4 引入后与图像像素各自独立拥有 1 亿像素预算同时蒙版同样受每边 30000 与每文件 512 MiB 限制。四、保存与加载先验证、后原子替换4.1 保存流程保存路径在 ProjectController.swift 的saveCurrent中发起实际写入由ProjectStore.save完成ProjectStore.swift关键步骤校验先行try validate(snapshot.manifest)任何非法状态在写盘前被拒绝编码资产对每个图层依次编码imageFile与maskFile指向的 PNG蒙版还需通过LayerMask.isValid8-bit 单色、无 alpha检查编码清单JSON 序列化后检查 ≤ 4 MiB构建包用FileWrapper(directoryWithFileWrappers:)组装manifest.json与images/原子替换通过NSFileCoordinator.coordinate(writingItemAt:options: .forReplacing)协调并以.atomic选项写入。代码注释明确说明Foundation 会先在旁边落一个完整的兄弟包只有整个包写完后才原子替换目标任何中途失败都不会破坏正在编辑的文档。4.2 加载流程ProjectStore.loadProjectStore.swift同样先读后验目标必须是目录否则invalid读取manifest.json≤ 4 MiB并先解码轻量Header仅formatversion确认format com.compositor.project且version ∈ [1, 7]再完整解码逐层读取images/下的资产必须是单帧 PNG、位深 ≤ 8超过 512 MiB 或路径越界即拒绝同时生成 96 像素缩略图供图层列表使用蒙版额外校验LayerMask.isValid全部校验通过后返回ProjectSnapshotmanifest images masks。4.3 失败保护与路径安全ProjectTests.swift用四个测试锁死了这些行为failedSavePreservesPreviouslySavedPackage先正常保存再尝试以version 99覆盖、以及“通过一个普通文件写入子路径”——两次失败后原包内容分毫未动unsupportedCorruptAndUnsafeMetadataAreRejected将version改为 42、把imageFile改成../../outside.png路径穿越、写入非 JSON 文本——三种篡改全部被拒会话内文档不受影响missingEmbeddedImageIsRejected删除images/中的资产后加载失败且“当前文档没有被替换”overwriteReplacesPackageAndDropsRemovedAssets删除图层后覆盖保存images/目录中的废弃资产被清空不会残留脏文件。路径安全有双重保障一是imageFile/maskFile必须严格匹配UUID.png/UUID.mask.png命名UUID 不包含路径分隔符天然杜绝穿越二是checkFile在解析符号链接后要求文件真实路径必须以包根目录为前缀ProjectStore.swift。打开操作本身也遵循“先验证、后替换”ProjectController.swift 的open先ProjectStore.shared.load完成全部校验再弹窗确认是否替换当前文档——损坏的项目永远不会丢弃正在编辑的内容。五、版本演进从 v1 到 v7 的增量式 schema.comp格式的兼容策略是新版本只增加可选字段旧版本文件必须能被新版本读取新版本文件必须能被旧版本明确拒绝而不是错误渲染。逐版本拆解如下。v2图层分组parentID/isGroup根节点无parentID子节点必须引用一个已存在的组数组顺序即自底向上的兄弟顺序渲染器将每个组视为一段连续子树遍历见 LayerGroups.swift 的LayerHierarchy.entries其visit递归实现组没有图像文件可见性沿层级继承但不修改子节点的isVisible标志校验拒绝循环引用、父节点缺失或非组、带图像的组、嵌套超过 64 层LayerHierarchy.validate中seen.count 64且父链上每个节点都必须isGroup true组祖先在 64 层内为最深层留出叶子节点的空间组的元数据在图像/画布尺寸调整与裁剪中存活旧构建版本拒绝 v2而不是错误渲染分组文档折叠状态不序列化仅会话内。v3不透明度与混合模式opacity/blendModeopacity0–1 的有限值缺省 1blendModeNormal、Multiply、Screen、Overlay、Darken、Lighten、Difference、Color Dodge、Color Burn缺省 Normal组记录强制要求缺省值opacity1 且 Normal其子图层可拥有独立效果——这与 LayerGroups.swift 中LayerOpacity.effective的“组透明度乘进每个子图层”语义呼应50% 图层在 50% 组内实际显示 25%但面板仍显示 50%效果在合成期应用调整源图尺寸时作为元数据保留声明旧版本的文件不能包含非默认外观值manifest.version 3 || (opacity 1 blend .normal)。v4图层蒙版maskFile/maskEnabled蒙版文件命名必须为layer UUID.mask.png位于images/下存在蒙版时maskEnabled缺省为 true无蒙版的记录两者都省略本版本组不能携带蒙版声明 v1–v3 的文件不能包含蒙版元数据蒙版存储为8-bit 灰度覆盖值、无 alpha白显黑隐中间灰为半透明LayerMask.swift 的LayerMask.isValid要求colorSpace?.model .monochrome、bitsPerComponent 8、alphaInfo .none蒙版的归一化范围与图像的局部矩形一致同一变换同时作用于图层与蒙版均匀的 1×1 蒙版合法且受鼓励——LayerMask.solid(revealing:)用一个字节构造全白/全黑蒙版避免在绘画前分配全分辨率像素蒙版像素与缩略图是不可变资产由历史记录共享LayerMask的以asset.image 比较引用尺寸行为Image Size 按图像变换重采样蒙版Canvas Size 与 Crop 保留蒙版像素蒙版像素预算独立另 1 亿像素禁用disabled的蒙版仍嵌入并可编辑只是不参与合成“编辑图像还是蒙版”的目标选择是会话状态重开后回到图像像素。v5实时蒙版 / 剪贴蒙版maskSourceIDmaskSourceID是一个非组图层的 UUID在文档坐标中提供实时 alpha与目标图层自身的栅格蒙版相乘源图层的像素、变换、不透明度、栅格蒙版以及上游实时蒙版共同贡献覆盖值可见性与 RGB 颜色不参与源图层保持独立校验拒绝引用缺失、自引用、循环、组端点、链长超过 256 节点LiveLayerMask.swift 的LiveMaskGraph.validatepath.count 256、源不得为组/调整层删除源图层时可选择把实时覆盖烘焙进依赖图层的像素保留其栅格蒙版或移除链接——作为一次可撤销操作LiveMaskBaker.bake与deleteWithLiveMaskChoice链接在图像/画布尺寸调整与裁剪后存活旧版本缺省为无实时蒙版旧构建拒绝 v5UI 术语这些 alpha 链接在界面上称为剪贴蒙版clipping mask。Option-点击可将下一层兄弟的基底赋给该层或释放连接多个被剪贴图层共享一个基底在其上方缩进显示移出连续堆栈即自动释放——底层maskSourceID表示不变toggleClippingMask/releaseDetachedClipping。v6组文件夹蒙版v6 允许maskFile/maskEnabled出现在组记录上文件夹没有图像其蒙版覆盖文件夹自身的变换矩形即创建文件夹时的画布尺寸Image Size 通过该变换重采样Canvas Size 与 Crop 保留像素与图层蒙版行为完全一致组是pass-through启用的文件夹蒙版会乘到每个后代图层的覆盖值上与该图层自身蒙版及任何外层文件夹蒙版相乘剪贴蒙版覆盖值不受影响LayerMask.swift 的FolderMaskClip正是用 Core Graphics 的嵌套 mask clip 实现这一乘法声明 v1–v5 的文件不能给组加蒙版旧构建拒绝 v6。v7调整图层源码现状文档未覆盖project-format.md正文写到 v6并预告“未来可编辑特性必须扩展 schema 并补充 round-trip 测试”。当前源码正是这一承诺的实现ProjectManifest.version已提升为7ProjectStore.swift校验范围同步扩展为(1...7)。v7 在图层记录上新增可选adjustment字段LayerAdjustment.swift支持六种调整Hue/Saturation、Levels、Curves、Exposure、Gradient Map、Grain。校验规则包括调整图层不得是组、不得携带图像文件layer.imageFile nil、要求manifest.version 7、且adjustment.isValidProjectStore.swift。LiveMaskGraph.validate同时禁止调整图层作为实时蒙版源records[source]?.adjustment nil。六、可编辑文本text元数据与 PNG 兜底像素图层记录可携带可选text元数据TypeTool.swift 的LayerTextStyle字段包括内容、PostScript 字体名、像素字号、RGB 颜色、对齐、字距tracking、行距leading以及可选的boxSize段落边界。关键语义文本在边界内自动换行改变boxSize触发重排reflow而不缩放字号——boxIsValid要求每边 16–30000、总面积 ≤ 1 亿像素PNG 始终是显示与导出的兜底旧读者忽略该元数据直接显示已栅格化的像素变换、复制、蒙版、画布尺寸变更都会保留文本元数据破坏性像素操作会栅格化文本下次保存时省略元数据字体缺失时编辑回退到系统字体但已保存的 PNG 在编辑前保持原外观数值边界内容 ≤ 100000 UTF-16 单元、字号 1–2000、tracking −100–1000、leading 0–50000 表示自动取字号 120%与 Photoshop 的 Leading 语义一致文本图层名取内容前 40 字符并压平空白layerName(for:)。七、图层效果effects记录与渲染管线project-format.md记录了effects记录中的stroke描边与shadow投影当前源码中的LayerEffectsLayerEffects.swift进一步包含四种效果stroke、shadow、colorOverlay纯色叠加、innerShadow内阴影。每个效果支持可选enabled可见性缺省可见隐藏的效果保留全部参数并继续列在图层下描边尺寸支持0–500 图层像素StrokeEffect.maxSize 500投影角度 −360–360°、距离 0–5000、模糊 0–500效果含可见性随项目保存并参与文档撤销setEffects走beginEdit/endEdit渲染时机效果在合成期绘制从不解构像素调整源图尺寸时作为元数据保留性能策略画布预览在串行后台工作线程上运行共享像素预算LayerEffectsRenderer.Cache上限 64 MiB、最多 8 个条目按最近使用淘汰导出时渲染全分辨率效果有 Metal 时走MetalLayerEffects否则 CPU 路径效果会先应用图层自身蒙版masked再生成描边/阴影因此描边跟随“实际显示的形状”而非矩形包围盒——与 Photoshop 一致。八、会话态与文档生命周期什么不落盘.comp格式刻意只保存“可复现的事实”把交互态留在会话内撤销历史与视口是会话级的打开后历史干净、不可撤销、未修改标记为 falseprojectRoundTripSurvivesSourceRemovalAndPackageMove断言!reopened.isModified与!reopened.canUndo打开行为固定适配画布fit canvas、恢复选区、从干净历史开始installProject路径导出是展平的派生品PNG/JPEG 导出输出合成后的位图ProjectController.exportPNG/exportJPEG经ImageExporter不会把项目标记为“已保存”——ImageSizeTests.swift 验证导出 PNG 携带与文档一致的 DPI 元数据如 300 ppi但它不是项目格式的一部分分辨率语义Image Size 添加可选resolution1–9600 ppi旧清单缺省 72该加法字段保持 v1 兼容。重采样写入新的图层像素与边界撤销仅在当前会话内保留旧源undo/redo测试覆盖未来演进路径任何新的可编辑特性都必须扩展 schema、遵守“旧版本必须拒绝新特性文件”的不变量并补充 round-trip 测试——v7 调整图层正是这一流程的实例。九、兼容性速查表版本新增字段旧版本文件含新字段时旧构建行为v1基线transform/name/visibility/imageFile——v2parentID、isGroupv1 文件出现即拒绝拒绝 v2v3opacity、blendModev1–v2 文件不得含非默认外观值拒绝 v3v4maskFile、maskEnabled图层v1–v3 文件不得含蒙版元数据拒绝 v4v5maskSourceIDv1–v4 不得含实时蒙版引用拒绝 v5v6组上的maskFile/maskEnabledv1–v5 不得给组加蒙版拒绝 v6v7源码现状adjustment调整图层v1–v6 不得含调整记录拒绝 v7所有校验的统一入口是ProjectStore.validateProjectStore.swift配合LayerHierarchy.validate与LiveMaskGraph.validate形成三层防线格式身份与版本、逐图层字段约束、跨图层图结构分组层级 实时蒙版链。十、延伸阅读格式规范原文docs/project-format.md保存/加载/校验实现Compositor/IO/ProjectStore.swift打开/保存/导出流程Compositor/IO/ProjectController.swift分组层级与文件夹语义Compositor/Document/LayerGroups.swift蒙版模型与校验Compositor/Document/LayerMask.swift剪贴蒙版与烘焙Compositor/Document/LiveLayerMask.swift图层效果渲染Compositor/Document/LayerEffects.swift可编辑文本Compositor/Document/TypeTool.swift调整图层v7Compositor/Document/LayerAdjustment.swift格式往返与失败保护测试CompositorTests/ProjectTests.swift、CompositorTests/ImageSizeTests.swift若要在自己的工具链中读写.comp建议直接以ProjectStore的save/load为参考蓝本先完整校验、再原子替换任何一条规则未通过都不得触碰正在使用的文档。赞分享图像处理桌面应用【免费下载链接】CompositorThe Photoshop alternative for Mac项目地址https://gitcode.com/gh_mirrors/compos/Compositor点击查看免费下载相关推荐ScyllaDB SSTable 存储格式完全指南持久化文件结构、版本演进与 sstable_format 配置ScyllaDB SSTable 存储格式完全指南持久化文件结构、版本演进与 sstable_format 配置 SSTableSorted Strings数据库分布式数据库后端大数据Velero 备份输出文件格式完全指南tar 包结构、元数据 JSON 与版本演进Velero 备份输出文件格式完全指南tar 包结构、元数据 JSON 与版本演进 导读 本文以 Velero 官方文档《Output file format云原生灾备存储后端gods-eye-view 场景文档Scene Document格式完全指南版本化 JSON 项目、迁移规则与导入校验gods eye view 场景文档Scene Document格式完全指南版本化 JSON 项目、迁移规则与导入校验 导读 gods eye view创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考