尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

darktable MCP 服务器:用 AI Agent 通过 stdio 驱动 darktable 原始开发引擎的完整指南

发布时间:2026/9/15 19:22:07

资讯中心
01
ARTICLE

darktable MCP 服务器:用 AI Agent 通过 stdio 驱动 darktable 原始开发引擎的完整指南

darktable MCP 服务器:用 AI Agent 通过 stdio 驱动 darktable 原始开发引擎的完整指南
darktable MCP 服务器用 AI Agent 通过 stdio 驱动 darktable 原始开发引擎的完整指南【免费下载链接】darktabledarktable is an open source photography workflow application and raw developer项目地址: https://gitcode.com/GitHub_Trending/da/darktable导读本文介绍 darktable 仓库中的darktable-mcp——一个无头headless的 Model Context Protocol 服务器它将 darktable 的 RAW 开发引擎以 JSON-RPC 2.0 协议暴露给 AI Agent。读完本文你将掌握它的构建与运行方式、--read-only等安全选项的语义、与 Claude Code / Claude Desktop 的接入方法以及render、image_stats、import_images、export_images等 18 个工具的完整参数与底层实现原理可以直接把 渲染这张 RAW 并给我看、测量 agx 参数对暗部的影响 这类自然语言指令交给 Agent 执行。darktable-mcp是darktable-cli的兄弟命令行程序它直接链接libdarktable因此拥有真实的模块自省introspection、进程内像素管道pixelpipe以及原生的 styles/history 支持——不需要手写 XMP 或注入 SQL。定位与架构概览darktable-mcp是一个标准 stdio MCP 服务器基于 JSON-RPC 2.0 通信。它不是一个 GUI 插件而是一个独立的后台工作进程专门让 LLM/AI Agent 以结构化方式使用 darktable 的暗房能力。从源码结构看它由四层组成详见 src/mcp/src/mcp/ main.c process lifecycle: dt_init boot, --core passthrough, stdio loop mcp_jsonrpc.c/.h transport: framing, JSON-RPC dispatch, error objects mcp_tools.c/.h tool registry JSON - C marshalling dt_bridge.c/.h the ONLY unit that calls libdarktable其中 dt_bridge.c 是唯一调用libdarktable的单元将所有库 API 调用隔离在其中因此当 darktable 模块参数版本升级等 API 变化发生时影响范围被限制在这个文件内。参数始终通过自省接口get_p/get_introspection_linear寻址绝不使用固定的字节偏移从而保证服务器跨模块版本保持正确见 dt_bridge.c 附近的设计注释。构建darktable-mcp在默认构建中就会被编译。CMake 选项为USE_MCP默认ON可通过-DUSE_MCPOFF或./build.sh --disable-mcp关闭。它只依赖json-glib-1.0这本来就是 darktable 的既有依赖因此无需新增任何第三方库见 src/mcp/CMakeLists.txt其中通过pkg_check_modules(JSON_GLIB REQUIRED json-glib-1.0)检查依赖并链接lib_darktable。# 作为普通构建的一部分 ./build.sh # 或者只构建这一个目标 cmake -B build . cmake --build build --target darktable-mcp -j二进制产物位于build/bin/darktable-mcp。运行darktable-mcp [--read-only] [--core darktable core options...]参数解析规则--read-only与--core--read-only是服务器自己的标志必须放在--core之前。--core之后的所有内容都会被原样转发给dt_init所以 darktable 的核心选项在这里与darktable/darktable-cli完全一致--configdir、--cachedir、--library、--conf keyvalue、-d domain等全部可用。从 main.c 的源码可以看到这一逻辑main()扫描--core的位置将其后的参数作为 core 参数数组同时检测--read-only是否被误放在--core之后此时会报错退出因为dt_init不认识这个选项。此外main()还会执行一个关键动作保留真正的 stdout 专用于 JSON-RPC——darktable 自身有时会向 stdout 打印日志因此服务端用dup2(STDERR_FILENO, STDOUT_FILENO)把 darktable 的日志重定向到 stderr从而保证 stdout 上只有干净的协议流量见 main.c。默认注入两种模式当既不给--library也不给--configdir时服务器会同时注入两个默认值因为这两者都意味着不碰任何东西--library :memory:—— 一个一次性throwaway目录库散装文件按需临时导入--conf write_sidecar_filesnever—— 不会在你的文件旁边写出任何.xmp。从源码看这个判断基于两个标志都未出现adhoc且只有当write_sidecar_files前缀的--conf也未出现时才注入后者main.c。只要命名了其中任何一个两个默认值都不会被注入。指定--configdir就会使用该目录自己的library.db——这和 darktable 其他任何地方的行为一致因此把服务器指向一个配置目录得到的是那个目录的目录库而不是一个空库。此时你等于选择了持久化你自己的write_sidecar_files偏好会生效编辑会写进 sidecar。--read-only的精确语义凡是携带stack的渲染都会修改图片见下文 Develop 部分。--read-only会拒绝所有会改动目录库的工具——stack渲染、reset_history、apply_style、save_style、import_style、set_rating、set_color_label——同时保留只读操作和普通渲染不受影响darktable-mcp --read-only --core --library /path/to/library.db这让你可以把 Agent 指向一个真实目录库而不允许它修改。内存库虽然也能阻止持久化但代价是失去对你真正想处理的目录库的访问。--read-only背后还有一些精细的补偿逻辑。darktable 中渲染并非完全没有副作用当管道第一次运行在 history 为空的图片上时darktable 会写出plugins/darkroom/workflow自动应用的模块并同步 sidecar。--read-only会把这一点拿回来——在渲染期间抑制.xmp并在请求结束后清除自动应用的 history让图片在请求结束时恢复为空 history 和它开始时携带的标志源码中由dt_mcp_pristine_t与_pristine_hold/_pristine_release实现见 dt_bridge.c。它不会撤销两件事因为这两者都不是编辑读取 RAW 会填充图片行上的缓存传感器列raw_black、raw_maximum加载一张已经有 history 的图片在读取时也会重写这些行及其哈希。按input.path渲染散装文件仍然可行因为那次导入是临时性的在请求返回前会被撤销见下文 Input 部分对目录库的净效果为零。唯一残留的是data.db中共享的darktable|format|ext标签定义——它不指向任何图片darktable 自己也从不删除这类行GUI 中删除图片同样会留下它对应dt_image_remove()见 src/common/image.c。import_images会被拒绝因为它是用于持久化的。目录库模式临时ad-hoc默认:memory:——一次性目录库。仅在既未给--library也未给--configdir时使用。真实目录库——--core --library /path/to/library.db或直接用--core --configdir /path/to/dir使用该目录下的library.db。此时目录库类工具能看到已存在的图片、它们的编辑和已保存的样式。注意darktable 会在library.db/data.db上持有 PID 锁所以目录库模式运行时GUI 不能正持有那个目录库或者对副本操作。接入 Claudedarktable-mcp是标准 stdio MCP 服务器。建议给它一个专用的 config/cache 目录服务器会锁住它打开的任何目录库而拥有自己的目录意味着那永远不会是 GUI 正在持有的那个两者可以同时运行。下面的例子还给了服务器一个属于自己的目录库——把图片导入进去目录库工具就能看到它们mkdir -p ~/.config/darktable-mcpClaude Codeclaude mcp add darktable -- \ /path/to/build/bin/darktable-mcp \ --core --configdir ~/.config/darktable-mcp \ --cachedir ~/.config/darktable-mcp/cache默认作用域是 local当前项目加-s user对所有项目生效或-s project写入共享的.mcp.json。用claude mcp list或会话内/mcp检查用claude mcp remove darktable移除。Claude Desktop把同一个服务器加到claude_desktop_config.jsonSettings → Developer → Edit Config并重启应用{ mcpServers: { darktable: { command: /path/to/build/bin/darktable-mcp, args: [--core, --configdir, /home/you/.config/darktable-mcp, --cachedir, /home/you/.config/darktable-mcp/cache] } } }然后直接用自然语言提问例如Using darktable, render this raw and show it或measure image_stats with agx target_black at 0.008 vs 0.0008。要操作真实目录库时把参数换成--core --library /path/to/library.db该目录库对应的 GUI 必须已关闭。协议标准 MCP 握手走 stdio既接受默认的每行一个 JSON 对象newline-delimited JSON也接受Content-Length:帧LSP 风格。支持的方法initialize、notifications/initialized、tools/list、tools/call、ping、shutdown。从 mcp_jsonrpc.c 可以看到协议版本常量SERVER_NAME为darktable-mcp、SERVER_VERSION为0.1.0、PROTOCOL_VERSION为2025-06-18同时定义了标准 JSON-RPC 错误码-32700解析错误、-32600无效请求、-32601方法未找到、-32602无效参数。帧检测逻辑在读取循环中完成一旦收到以Content-Length:开头的行后续消息就切换到帧模式mcp_jsonrpc.c。一次典型的握手// → request {jsonrpc:2.0,id:1,method:initialize,params:{}} // ← reply {jsonrpc:2.0,id:1,result:{protocolVersion:2025-06-18, capabilities:{tools:{listChanged:false}}, serverInfo:{name:darktable-mcp,version:0.1.0}}}工具总览服务器通过tools/list暴露 18 个工具分为五组。所有工具的参数 schema 与描述文本都存放在数据目录的 data/mcp_tools.json 中安装后位于share/darktable/mcp_tools.json启动时通过dt_loc_get_datadir()加载见 main.c。自省Introspection工具输入输出list_modules–[{operation, version, have_introspection, doc_url}]module_schema{operation}各字段的{name, type, offset, min, max, default}枚举值会列出doc_urldecode_params{operation, blob_hex}{operation, version, fields:{…}}—— 从十六进制op_paramsblob 解出命名值encode_params{operation, fields:{…}}{operation, blob_hex}—— 先填充默认值再应用 fields枚举接受符号名doc_url是该模块在 darktable 用户手册中的页面链接可用于获取每个参数含义的文字说明。从源码看list_modules遍历darktable.iop链表并调用每个模块的version()与have_introspection标志dt_bridge.cmodule_schema则通过get_introspection()/get_introspection_linear()遍历标量字段输出类型名float/double/int/uint/int8/uint8/short/ushort/bool/enum、字节偏移、范围与默认值dt_bridge.c。编码与校验的关键细节encode_params中数值超出字段自省范围时是拒绝而不是截断clamp——源码注释明确解释静默修正的值渲染出来可能看起来没问题却会让调用方误以为自己发的数字被采用了。枚举字段既可以传符号名也可以传整数值dt_bridge.c。字段范围来自模块源码中的范围注释没有范围注释的字段取该类型的完整范围见 src/common/introspection.h 附近所以实际只拒绝模块真正声明为越界的值。输入Inputrender、image_stats和export_images既可以接受imgid也可以接受path两者含义完全不同input行为{imgid}常规路径。编辑会持久化XMP sidecar 会随之更新。{path}不在目录库中临时scratch文件被导入以便 darktable 开发它随后图片行再次被删除——包括 sidecar 复制出的 darktable 文件以及所在 film roll。不保留 history、sidecar 或任何东西。磁盘上的文件永远不会被触碰。{path}已在目录库中被拒绝并指出对应的imgid供你决定。为什么路径必须先变成图片因为 darktable 无法开发一个裸文件——history、sidecar 和模块默认值都绑定到目录库中的一行记录。所以路径总是要先导入成一张图片。Scratch 导入就是在不每次让目录库多一行记录的情况下查看文件的实现方式源码实现见 dt_bridge.c 的_resolve_input以及 dt_bridge.c 的_drop_scratch——它按基线删除本次导入创建的行、清掉module_order残留该表没有外键不会随图片自动删除、并在 roll 为空时移除 film roll同时通过_xmp_mute临时把write_sidecar_files设为never避免导入同步 sidecar。推荐实践优先使用import_images导入后再按imgid操作。这是 darktable 的正常工作流是唯一保留编辑的路径也能让 Agent 的改动在你的目录库中可见。Path 输入是用来看一眼文件不是用来处理文件。开发Develop工具输入输出render{input:{path\|imgid}, width?, height?, stack?, disable_tone_mappers?, history_end?}MCP image contentbase64 PNGimage_stats同render每通道{min, max, mean, p1, p50, p99, clip_lo, clip_hi}一个stack是{operation, params:{…} \| blob_hex, multi_priority?, enabled?}的数组叠加在图片的基础管道之上。disable_tone_mappers:true会关闭 darktable 自动应用的任何一个 tone mapper即plugins/darkroom/workflow所选的那个让你在 stack 里加的 tone mapper 独占 tone 曲线——并且和 stack 一样这个开关会写入图片的 history 和 sidecar比请求活得更久。stack 条目可以携带before或after命名另一个模块把它放到管道中的那个位置——这是相对定位而不是裸的iop_order一个没人能合理选择的晦涩数字。get_history会报告每个模块的iop_order方便你先读取当前排列注意 history 条目的num是编辑发生的顺序这是另一回事。源码中before/after移动会先经过dt_ioppr_check_can_move_before/after_iop()的管道规则校验与 GUI 中 src/develop/imageop.c 附近的移动限制一致防止写出一条非法的自定义顺序dt_bridge.c。stack 会被写入图片。对于imgid它成为图片的 historyXMP sidecar 在库的偏好允许时随之更新——没有一次性副本所以一次渲染也是提交一次编辑的方式。history_end选择在叠加 stack 之前保留多少现有 history。当你不想这样时请用--read-only运行或使用内存库。history_end在render和image_stats上需要小心带 stack 时它会重写图片的 history永久丢弃history_end之后的条目因为基础状态在写 stack 之前会被截断。不带 stack 时它只选择渲染什么、不改变任何东西——在export_images中它永远只做这件事。从 dt_bridge.c 可以看到带 stack 时实现先把 history 截断到history_end并重置为-1然后dt_dev_pop_history_items_ext处理其余部分。在 scratch 渲染上stack 仍然塑造你拿到的像素但没有任何东西能活过这次请求——这正是image_stats可以在不留任何痕迹的情况下用于比较参数的原因。渲染的底层实现render并不走dt_imageio_preview那个辅助函数通过一个仅 GUI 可用的 cairo 包装构建 surface无 GUI 时会崩溃而是通过一个内存导出格式模块 纯 cairo 渲染成 RGB24 surface再用cairo_surface_write_to_png_stream编码为 PNGdt_bridge.c。image_stats则对渲染结果建立每通道 256 级直方图计算 min/max/mean、p1/p50/p99 百分位以及 0 和 255 处的裁剪计数dt_bridge.c。width/height 是边界框而非目标尺寸图片按宽高比适配进width × height内较小的一边决定结果省略或传 0 表示该维不限此时由另一维单独约束但不会放大超过图片自身尺寸两维都给出则允许放大。render两维都不给时默认1024x1024image_stats默认512x512见 data/mcp_tools.json 中对应 schema 描述。配置Configuration工具输入输出list_conf{prefix?}已声明设置[{key, value, type, default, min?, max?, values?}]get_conf{key}单个设置同样的结构配置工具在设计上是只读的。有些设置会改变render和export_images的输出——plugins/darkroom/workflow决定自动应用哪些模块write_sidecar_files决定编辑是否到达.xmp——所以能读取它们就能解释一些否则看起来很怪的结果。没有set_conf会话中途改设置会静默地使之前收集的所有结果失效且没有任何记录说明发生过这件事。请改用--conf keyvalue重启让改动成为一次可见的会话边界。源码中list_conf只遍历darktable.conf-x_confgen中已声明的键darktablerc里还有窗口几何等运行时涂鸦对调用方没有意义并用与偏好对话框相同的方式解析枚举的[a][b][c]存储格式dt_bridge.c。目录库Library / Catalog工具输入输出import_images{paths[]?, folder?, recursive?}{images:[{path, status, imgid?, error?}], imported, already, failed}list_images{limit?, film_roll?, folder?, rating?, color?, rejected?}[{imgid, path, rating, color_labels?, rejected?}]list_film_rolls–[{film_roll, name, folder, images}]get_metadata{imgid}相机与镜头、EXIFISO、快门、光圈、焦距、拍摄时间以及传感器raw黑电平与白点get_history{imgid}按模块解码的编辑栈[{num, operation, version, enabled, iop_order, multi_priority, fields}]reset_history{imgid}{ok:true}—— 把图片的编辑清回导入状态set_rating{imgids[], rating?, reject?}{ok:true}set_color_label{imgids[], color, toggle?}{ok:true}list_styles{filter?, limit?}{total, styles:[{name, description}]}apply_style{name, imgid \| imgids[], overwrite?}{ok:true}save_style{name, description?, imgid}{ok:true}import_style{path}{ok:true}.dtstyle→ styles 数据库export_images{input \| imgids[], out_path?, out_dir?, format?, quality?, width?, height?, upscale?, high_quality?, …}{ok, exported, paths[]}—— 写文件并返回落点导入。import_images是文件进入目录库的方式传paths或传folder配合recursive遍历子目录来导入整组拍摄。重复导入是幂等的——已在库中的图片以already状态返回并带有它已有的imgid绝不会产生重复。遍历目录时只保留dt_supported_image()能识别的文件sidecar 和杂散文件被静默跳过而显式指定的路径总是会被尝试失败时会返回原因dt_bridge.c。浏览。film roll 是 darktable 中一个导入的文件夹的单位也是摄影师对一组拍摄的称呼所以list_film_rolls是 Agent 发现过滤依据的方式film_roll精确匹配一个folder是子串匹配、可以覆盖包含多个 roll 的父目录。rating是最小值color和rejected进一步收窄。注意list_images的 SQL 会把 rating 存在flags的低 3 位、DT_IMAGE_REJECTED(8) 单独存放因此被拒图片仍保留它原有的星级颜色名必须严格是red, yellow, green, blue, purple之一否则直接报错而不是返回空列表dt_bridge.c。筛选Culling。set_rating和set_color_label接受列表因为一张一张地评星标色是处理整组拍摄最慢的方式。拒绝reject是与星级并列的标志而非星级数值所以传reject:true而不是数字被拒的帧保留它原有的星。两个工具都是幂等的darktable 的 GUI 会在重复评分时把评分关掉——这是键盘操作习惯没有任何 API 调用方需要它——所以桥接层把这类图片从待处理列表中剔除保证重复调用无副作用dt_bridge.c。样式Styles。一个目录库可能存有数百个样式完整列表可长达几十 KB所以list_styles接受filter子串同时匹配名称和描述与 darktable 自己的样式列表一致和limit。total总是统计所有匹配数因此列表被截断也能一眼看出。批量Batch。apply_style和export_images既接受单数imgid/out_path也接受复数imgids/out_dir两者都给时列表优先。批量导出的文件名取自源文件与darktable-cli指向目录时的行为一致。不同 roll 之间、RAW 与同名 JPEG 之间都可能重名冲突由 darktable 自己的冲突设置plugins/imageio/storage/disk/overwrite决定默认取一个空闲的_01名字而不是覆盖已有文件。该设置只决定导出前磁盘上已存在的文件怎么办同一批次内两个源解析到同一目标时总是各取独立名字否则一张图覆盖另一张的输出就丢图了。目标目录不存在时会自动创建。批次在第一个写不动的图片处停止错误信息同时点名已经写在磁盘上的文件和从未尝试过的图片重试既不会重复也不会跳过。导出到哪里。命名out_path单图或out_dir多图或者都不命名让 darktable 决定——与它自己的导出模块完全一致plugins/imageio/storage/disk/file_directory默认值是$(FILE_FOLDER)/darktable_exported/$(FILE_NAME)——每个源文件旁边的darktable_exported/文件夹绝不是服务器的当前工作目录调用方无从知道那是哪。回复会列出解析出的paths所以即使让 darktable 自己选Agent 也会知道文件去了哪。从源码看未指定目标时的路径生成通过dt_variables_expand_path展开变量并应用冲突策略_resolve_conflictdt_bridge.c。跳过目标。把plugins/imageio/storage/disk/overwrite设为 3已有文件就被保持原样那张图什么都不写。回复总是携带skipped字段非零时在skipped_paths中点名这些目标一次什么都没写成的导出否则看起来和成功导出毫无区别。只有本来就存在的文件才会被跳过绝不会跳过同一次调用中另一张图刚刚占用的名字。你自己命名的out_path永远不受该策略约束。导出不带编辑。与render不同export_images不接受stack或disable_tone_mappers请求里带任何一个都会被拒绝两者都会提交到图片的 history接受它们就等于写一个 JPEG 的同时悄悄改动它来源的图片。请先编辑带 stack 的render或apply_style再导出。history_end是安全的、可以保留因为它只选择应用多少现有 history不改变任何东西。导出从未开发过的图片仍会物化 darktable 自动应用的 history与render完全一样见下文注意事项--read-only会把它拿回来。省略width/height时按全分辨率导出与 darktable 自己的导出一致。格式。format选择输出模块——jpeg、png、tiff、webp、jxl、avif、exr、pfm、ppm、j2k以你构建中可用的为准jpg和tif作为别名接受。省略时由out_path的扩展名决定再无其他依据时使用 darktable 自己的导出格式设置plugins/lighttable/export/format_name出厂为jpeg。quality适用于有损格式格式提供的其他一切来自它自己的plugins/imageio/format/…设置可用list_conf读取。upscale允许导出大于源图high_quality选择更慢但重采样质量更高的路径。源码中_write_export通过dt_imageio_export_with_flags驱动真实格式模块quality 临时写入模块自己的 conf 键并在取参后恢复dt_bridge.c。get_metadata的raw块由rawprepare填充所以只有图片至少走过一次管道才会出现——需要黑电平和白点就先渲染一次。完整示例测量 RAW 上某个agx参数的暗部下限效果同时关闭默认 tone mapper{jsonrpc:2.0,id:2,method:tools/call,params:{ name:image_stats, arguments:{ input:{path:/photos/DSCF0001.RAF}, width:512,height:512, disable_tone_mappers:true, stack:[{operation:agx, params:{curve_target_display_black_ratio:0.0008}, enabled:true}]}}}结果的 text 是 JSON形如{width:512,height:341,channels:{g:{p1:6,p50:71,…},…}}。把这个例子的disable_tone_mappers去掉、把stack里换成target_black: 0.008再对比两次的p1/clip_lo就能定量描述参数对暗部阴影的影响——这正是image_stats设计要解决的无痕参数比较场景。自定义工具描述与 Schema每个工具的表现层——name、description、inputSchema——都存放在 darktable 数据目录的 data/mcp_tools.json 中安装到share/darktable/mcp_tools.json与noiseprofiles.json等同目录启动时通过dt_loc_get_datadir()加载。只有工具行为handler被编译进二进制按name与元数据条目匹配。因此你可以改写某个 description用来引导模型选择哪个工具或收紧inputSchema然后重启服务器——无需重新编译。真正新增工具仍需要在 src/mcp/mcp_tools.c 里写一个 C handler。一个name没有对应 handler 的 JSON 条目会被忽略并在 stderr 上给出警告。注意事项与限制无头渲染走内存导出格式模块 纯 cairo而非dt_imageio_preview那个辅助函数通过仅 GUI 可用的 cairo 包装构建 surface无 GUI 时会崩溃。首次渲染一个 RAW 要跑 demosaic 加完整管道可能需要几秒给客户端留充足的超时。版本升级decode_params目前要求 blob 与模块当前的参数大小一致。把旧版本 blob 先喂给dt_iop_legacy_params是计划中的补充。imgid输入的编辑会持久化。一个stack会被提交到图片的 history所以探索变体的 Agent 会把最后一个变体留在图上且没有撤销。reset_history可以清空一张图--read-only或内存库可以阻止写入。Scratch 渲染input.path按设计什么都不保留。首次渲染会物化自动应用的 history。任何render、image_stats或export_images之后一张空 history 的图片会带着十几个条目回来请求中没有stack时也一样darktable 第一次在该图上运行管道时会写出plugins/darkroom/workflow自动应用的模块并同步 sidecar。darktable-cli的行为完全相同所以这是 darktable 自己的默认渲染被记录下来而不是服务器做的编辑。需要让图片保持原样就用--read-only它会压住.xmp并在请求返回前再次清掉那段 history。请求中途崩溃可能遗留一个 scratch 行因为清理在请求结束时才运行。它会以一张意外出现的图片显示在目录库里。不包含驱动一个在运行/打开的 darktable GUI这是一个后台 worker。相关源码参考服务器入口与生命周期src/mcp/main.c唯一的 libdarktable 桥接层导入、渲染、统计、目录库、导出src/mcp/dt_bridge.c、src/mcp/dt_bridge.hJSON-RPC 传输层src/mcp/mcp_jsonrpc.c、src/mcp/mcp_jsonrpc.h工具注册与 JSON↔C 编组src/mcp/mcp_tools.c、src/mcp/mcp_tools.h工具描述与 Schema 数据data/mcp_tools.json构建集成与依赖声明src/mcp/CMakeLists.txt相关底层实现图片删除行语义 src/common/image.c、管道移动限制 src/develop/imageop.c、自省字段范围约定 src/common/introspection.h【免费下载链接】darktabledarktable is an open source photography workflow application and raw developer项目地址: https://gitcode.com/GitHub_Trending/da/darktable创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。