
简介压缩包内整理了 libdwg-0.4 与 libredwg 的完整开源源码目标是为开发者提供可读写 AutoCAD DWG 文件的 C 语言库尤其适合需要绕过商业授权、自主解析或生成 DWG 数据的开发和移植场景。包内共 71 个文件、约 578KB除 20 个 C 源文件和 9 个头文件外还包含 configure、Makefile、m4/libtool 等构建脚本以及 README、INSTALL、AUTHORS、NEWS、ChangeLog 等文档基本覆盖了从代码阅读、环境配置、编译安装到库调用的完整链路另有 4 个样例 DWG 和 1 个 DXF 文件可做格式对照便于验证解析结果。目前已有 870 人学习属于轻量但完整的开源库资源。通过阅读 decode_r2000、decode_r2004 等核心模块可理解 DWG 对象的解码流程与变量处理方式配合包内 PDF 文档也能在遇到依赖缺失或构建选项报错时快速定位问题。对想深入 DWG 格式或在项目中集成读写能力的中高级开发者这份代码包能提供可直接扩展的起点。1. 打不开的 DWG 文件我为什么从 libdwg-0.4 开始一次图纸清查任务几十份 DWG 文件等着提取图层和块信息手头没有现成的转换接口。在线转换服务试了几个大文件基本传不动装完一堆商业试用版又提示导出有水印。最后落到开源方案 libdwg 上也就是 libredwg 早期快照 libdwg-0.4。这个压缩包里带完整源码、示例数据和编译脚本定位是“能读、能转、不能写”的 DWG 解析工具链。对需要批量读图元、转 DXF、做图纸内容统计的工程场景特别合适对 CAD 二次开发者则是理解 DWG 内部结构的一个低成本入口。适合两类人一类是需要在服务器上批量处理 dwg 文件的实施工程师另一类是想要轻量级图纸解析、又不想接重型商业 SDK 的开发者。2. DWG 格式为什么难啃版本机制与 libdwg 的选型边界选库之前先想清楚一件事DWG 不是一个“通用二进制格式”它是一套随 AutoCAD 版本演化、混合了压缩、CRC 校验和私有对象序列化的容器。选错解析库后面每个版本都会踩坑。2.1 DWG 文件开头那 6 个字节决定了后面所有解析逻辑拿到任何 DWG 文件第一件事是看文件头部的版本字符串。常见的有 AC1009R11/R12 时代、AC1012R13、AC1014R14、AC1015R2000、AC1018R2004、AC1021R2007、AC1024R2010再往后还有 2013、2018 等更新版本。这些前缀不只是一个序号它对应着内部对象编码方式、句柄表结构、图层和块定义在文件里的存放位置。libdwg-0.4 的版本判断表主要覆盖到 AC1015 及以前对 AC1018 能解析一部分基础对象再用新版本编辑器存出来的图纸就很容易超出它的能力。解析器做的是“按版本查表按偏移量读块”的工作。版本表不全后面读出来的对象就是残缺的。所以看一个 DWG 解析库能不能用先看它内置的版本表覆盖到哪一年而不是看它宣传的“支持 DWG”。这是我从 0.4 这个老版本开始而不是直接上最新主线的原因之一老版本的表简单适合把解析流程读明白。2.2 libdwg-0.4 与 libredwg同一代码线的两个时期libdwg 是早期项目名libredwg 是后来的主线名称两者代码有清晰血缘关系。libdwg-0.4 这个压缩包内部结构相当直接src 下有 dwg.c、dwg.h、out_dxf.c、out_json.c 这类文件编译目标也少主要是 dwgread、dwg2dxf、dwg2SVG 这几个工具。主线 libredwg 则多了很多新功能比如写入 DWG、dwg2JSON 工具、对高版本文件更好的容错但代码量和依赖复杂度也上来了。实际选型时我一般这样判断如果只是想在 Linux 服务器上快速得到一套可用的命令行解析工具0.4 的编译成本和体积更合适如果业务里混着大量 2004 以后的新版本图纸那直接上主线 libredwg 更省事。0.4 适合先跑通流程、研究代码结构遇到版本缺口再平移到主线迁移成本不算高因为核心 API 的命名习惯保留了相当多。另外发行版软件仓库里可能已经有编译好的 libredwg 二进制但版本往往比较旧而且不会带示例数据和完整头文件。自己动手从源码包编译拿到的是当前代码线里最完整的一套结构排错时也更容易定位问题到底出在哪个解析阶段。2.3 能力边界什么能读什么读不到明确这个库能做什么比会做什么更重要。libdwg-0.4 能读取的常见内容有图层名称和颜色索引、块定义、文本实体、直线/多段线/圆弧/圆的几何坐标、标注样式、线型和布局基础信息。这些覆盖了大部分批量提取需求。读不到的或者说拿不准的有受保护的自定义对象Custom Object代理数据、较新版本里引入的材质和渲染参数以及部分嵌套块的注释性缩放数据。还有一个不可忽视的边界0.4 阶段的代码基本没有写入能力。这意味着你不能用它在 DWG 里改一个图层颜色再存回去。它的定位是只读提取和格式转换而不是 DWG 编辑器。如果你要的是一套完整的读写 SDK那需要换路线但作为“把 DWG 里的内容挖出来”这个目的libdwg 的边界是够用的关键是别拿它当全能工具用。维度libdwg-0.4 快照libredwg 主线商业 SDK仅作对比版本覆盖AC1015 及以前较稳较新覆盖范围大得多几乎全版本写入支持无部分支持有部署复杂度依赖少编译快依赖与代码量更大需要授权和集成典型场景批处理、流程验证解析新版本 DWG产品级 CAD 功能表格里这个对比可以帮你判断手里图纸主要是老版本0.4 够用图纸来源杂、版本跨度大直接多花点时间编译主线。我在一个项目里同时保留两个编译产物老图纸走 0.4新图纸走主线日常处理并行跑效率比单一方案高不少。3. 从 RAR 包到可执行文件libdwg 编译配置与依赖处理源码类资源的第一个坎永远是编译环境。libdwg-0.4 编译不折腾但它依赖几个系统库漏掉一个 configure 就报错。3.1 解包与依赖清单拿到 libdwg-0.4.RAR 后先在干净的目录里解开unrar x libdwg-0.4.RAR cd libdwg-0.4 ls解包后先看 README 和 configure.ac里面会列出需要的构建工具autoconf、automake、libtool、flex、bison以及运行时依赖 zlib 和 mxml。mxml 是 minixml 的缩写一个轻量级 XML 解析库libdwg 用它输出部分对象数据。在 Debian/Ubuntu 系上我一般这样装依赖sudo apt-get install -y autoconf automake libtool flex bison zlib1g-dev libmxml-devCentOS/RHEL 系的包名不同需要启用 EPEL 源后安装sudo yum install -y autoconf automake libtool flex bison zlib-devel minixml-devel这里有个常见区分点zlib1g-dev 是开发头文件包光装 zlib1g 不够同样 libmxml-dev 才是带 mxml.h 的包libmxml1 只是运行库。漏掉 -dev 后缀configure 阶段就会卡住。3.2 configure 参数与编译过程0.4 的源码包一般自带 configure 脚本如果解出来的目录里没有先跑一遍 autogen.sh 生成它。我的编译参数通常是这样./autogen.sh CFLAGS-O2 -g ./configure --prefix/usr/local --disable-trace make -j4 sudo make install逐个参数解释一下CFLAGS 里的 -O2 是优化级别-g 保留调试符号万一程序崩溃可以看栈信息--prefix 控制安装路径我习惯装到 /usr/local 而不是 /usr避免和系统自带的旧版本 libdwg/libredwg 冲突--disable-trace 关闭内部调试输出这些 trace 日志在生产场景里会刷屏且拖慢速度。如果打算研究解析过程可以不加这个参数trace 信息能显示每个对象读取时的偏移量和类型判断路径。make -j4里的 -j4 是四路并行编译机器核数多可以调高一点。编译过程中如果报错优先看两个地方config.log 里的头部以及 src/Makefile 里的编译命令。config.log 会告诉你到底是缺头文件还是缺函数库这个信息比终端里飘过的最后几行报错可靠得多。我曾因为没装 libtool 导致 configure 中途失败config.log 里明确写了 ltmain.sh not found装完 libtool 后重跑 autogen.sh 就正常了。不建议在 0.4 上启用 --enable-write 这样的写支持参数这个版本对写入的支持本来就残缺强行打开反而会在运行时产生一堆未达预期的分支代码。如果确实需要写入能力直接换 libredwg 主线把 --enable-write 留到主线配置里再开。3.3 验证安装结果编译完成后先用版本命令验证工具是否可用/usr/local/bin/dwgread -v dwg2dxf 21 | head -20-v输出编译时嵌入的版本信息能确认工具来自你自己编译的库。然后进源码包的示例目录跑一个样本文件find . -name *.dwg | head -5 ./programs/dwgread ./test-data/example.dwg我在一个老开发板环境里做过一次验证test-data 目录下放着一个 R2000 格式的示例图纸dwgread 能直接输出它的图层列表和实体数量。如果你手里的压缩包里没有样本用旧版 AutoCAD 新建一个带几根直线、一个圆弧、一个块引用的图纸另存为 R2000 格式同样能验证。关键是先小后大不要拿一个几百 MB 的生产图纸当第一个测试对象那样出问题时分不清是版本不支持还是文件损坏。4. 提取 DWG 数据dwgread、dwg2dxf 与 C 接口实操编译通过只是热身真正落地是提取数据。这章按使用深度分三层命令行直接看、转中间格式、在 C 代码里集成。4.1 用 dwgread 看图层和实体dwgread 是 libdwg 的瑞士军刀常用参数包括 -s汇总、-l列出、-o输出到文件。我常用的提取命令dwgread -s -l drawing.dwg -o drawing_info.txt-s 输出文件级别的摘要比如 DWG 版本、对象总数、图层数量-l 是逐条列出对象信息包含图层名、实体类型、颜色索引和关键几何参数。输出会重定向到单独文件避免在终端里刷屏。实际读出来的内容类似下面这样实际字段以你的编译版本为准OBJECTS: 12 LAYER: 0 color 7 flag 1 LAYER: 墙体 color 3 flag 0 TEXT: layer 墙体, pos (120.50, 80.00, 0.00), height 2.50 LINE: layer 墙体, start (0.00, 0.00), end (100.00, 50.00) ARC: center (50.00, 50.00), radius 20.00, angle 0.00 - 180.00这段输出足够支撑图层维度统计和实体分布分析。需要注意不同小版本的输出格式可能会调整字段顺序写脚本解析时最好用关键字匹配而不是按列号取值列号太容易被版本差异打乱。dwgread 还支持按图层过滤不过 0.4 的过滤参数在分支间不统一有些版本支持 --layer 之类的选项有些则不支持。我一般不在命令行层面过滤而是把完整列表导出来再用外部脚本过滤这样信息保留得更全排查问题时不用重新读一遍文件。4.2 用 dwg2dxf 转成 DXF 中间格式DXF 是文本化的交换格式比 DWG 容易处理得多。libdwg-0.4 自带的 dwg2dxf 工具可以把 DWG 转成 DXFdwg2dxf drawing.dwg drawing.dxf默认输出到标准输出重定向成文件即可。DXF 文件用普通文本编辑器就能打开组码和值一一对应。例如图层名对应组码 8实体类型对应组码 0文本内容对应组码 1。0.4 转出来的 DXF 整体可用但一个细节值得留意对圆弧和样条曲线转换结果里的拟合精度可能偏低。如果后续要做几何计算用圆周上三个点重建圆弧更稳妥直接信任 DXF 里的 ARC 组码可能会带入轻微的弧度偏差。转完 DXF 后我习惯跑一下wc -l drawing.dxf看行数行数异常少说明转换在早期阶段就退出或截断了。还有一个常用派生做法把 DXF 作为中转传给 Python 的 ezdxf 库做后续分析。先转 DXF 再进 Python比直接解析 dwgread 的文本输出更结构化组码语义明确不容易因为输出格式微调而导致脚本失效。4.3 在 C 程序里直接集成需要把 DWG 解析嵌进自己的服务时可以直接链接 libdwg 的静态库。最小读取流程如下#include stdio.h #include stdint.h #include dwg.h int main(int argc, char *argv[]) { if (argc 2) { fprintf(stderr, usage: %s file.dwg\n, argv[0]); return 1; } Dwg_Data dwg {0}; // 0.4 部分快照里的入口叫 dwg_read_fd解包后先 grep dwg.h 确认 int err dwg_read_file(argv[1], dwg); if (err ! DWG_ERR_OK) { fprintf(stderr, read failed: %d\n, err); return 1; } printf(objects: % PRIu64 \n, (uint64_t)dwg.header.num_objects); // 遍历对象按类型做分发处理 // for (i 0; i dwg.header.num_objects; i) { ... } dwg_free(dwg); return 0; }函数名在不同快照里有差异这是老版本代码常见情况。以 dwg_read_file 为例它接收文件路径和空的结构体指针解析成功会填充 Dwg_Data 里的头部信息、对象表和块表。返回 DWG_ERR_OK 时才能继续使用数据否则结构体内部状态不可靠。编译链接时注意顺序问题静态库的依赖要放在后面gcc -o demo demo.c -ldwg -lmxml -lz-ldwg必须在-lmxml和-lz前面。链接器按从左到右的顺序解析符号libdwg.a 里的符号引用了 mxml 和 zlib 的函数如果系统库写在 libdwg 前面链接器可能报 undefined reference。这个问题在第五章会细讲。如果你想把解析结果直接接到别的语言常见做法是让 C 程序输出 JSON 或 CSV再交给上层处理。0.4 自带的 out_json 支持不完整我不建议在 0.4 上依赖 JSON 输出直接自己控制 C 代码的输出格式更可靠。4.4 用 Python 包一层命令行工具不想碰 C 时可以用 Python 的 subprocess 调 dwgread 或 dwg2dxfimport subprocess proc subprocess.run( [dwgread, -s, -l, drawing.dwg], capture_outputTrue, textTrue ) print(proc.stdout)这个方案的好处是快速、不需要写 C 代码坏处是每次调用都会拉起一个进程大批量处理时启动开销明显。我的习惯是几十个文件以内用命令行最省事几百个文件就写 C 扩展或常驻服务避免反复进入进程。Python 只负责把 dwgread 的输出按行拆开用正则把 LAYER 和实体类型抽出来简单可靠。5. 避坑指南五个容易翻车的问题与处理办法源码包编译和使用过程中我前前后后踩了一堆坑挑五个最有代表性的写在这里。每一条都是现象、原因、解决三步照着检查能省不少时间。5.1 configure 提示找不到 mxml.h现象configure 执行到一半终端显示checking for mxml.h... no然后直接退出。原因系统里没有安装 minixml 的开发头文件包或者装了但不在默认搜索路径里。有些最小化安装的服务器只装了运行库头文件没装。解决Debian 系执行sudo apt-get install libmxml-devCentOS 系执行sudo yum install minixml-devel。如果公司内网不能装系统包那就单独把 minixml 源码编到自定义目录再指定路径重跑 configureCPPFLAGS-I/opt/mxml/include LDFLAGS-L/opt/mxml/lib ./configureCPPFLAGS 告诉预处理器去哪里找头文件LDFLAGS 告诉链接器去哪里找库。这个套路在依赖缺失时通用不只是 mxml。5.2 打不开 2013 年以后的新版图纸现象dwgread 执行后报错提示 DWG version 无法识别或者直接显示Invalid DWG version后退出。原因0.4 的版本表里没有对应年份的版本标识解析器不知道按什么布局去读对象。这不是文件损坏是库本身不认识这种格式。解决两个方向。一是换 libredwg 主线版本它的版本表新得多二是请图纸提供方另存为 R2000 或 R2004 格式这是工程协作里的常见做法。我在一次跟某设计单位协作时约定所有送审图纸统一另存为 R2000之后解析稳定性明显提升。如果你处理的是历史归档图纸这个方案尤其好用因为老图纸基本都是 R2000 及更早版本。5.3 图层名和属性块里的中文乱码现象dwgread 输出里中文图层名变成类似\xd6\xd0\xce\xc4的转义序列或者变成一串乱码。原因DWG 内部对文本有两种常见编码方式一种是 GBK/GB18030一种是 UTF-8。libdwg-0.4 默认按 Latin-1 或 ASCII 处理字节流遇到 GBK 多字节汉字自然显示不对。解决把 dwgread 的输出按原始字节对待不要让它经过终端字符集转换层然后手动用 iconv 转码。例如dwgread -s -l drawing.dwg -o raw.txt iconv -f GBK -t UTF-8 raw.txt -o clean.txt如果转换后还是乱码用xxd raw.txt | head看字节范围能判断实际编码是 GBK 还是 UTF-8。UTF-8 的字节模式有规律可循GBK 汉字两个字节都大于 0x80。确认后调整 iconv 的参数即可。严格说这不是 libdwg 的 bug是它没做自动编码探测跨语言场景里这类问题很常见习惯上要养成“文本进程序后先定编码再处理”的意识。5.4 静态链接时一堆 undefined reference现象编译集成代码时gcc 报错提示undefined reference to inflate或者undefined reference to mxmlNewXML。原因链接顺序错了。默认情况下链接器从左到右处理库libdwg.a 里的目标文件引用了 zlib 和 mxml 的符号但这两个库写在前面时那些符号还没被标记为需要解析等到 libdwg.a 被处理时就找不到定义了即使后面写了-lz也没用。解决调整库顺序把被依赖的库写在最后gcc -o demo demo.c -ldwg -lmxml -lz如果项目比较大还可以在链接参数里加-Wl,--start-group -ldwg -lmxml -lz -Wl,--end-group让链接器在组内循环解析符号就不依赖书写顺序了。这个方法在写 Makefile 时尤其省心。5.5 dwg2dxf 退出码是 0但输出文件是空的现象脚本里执行dwg2dxf in.dwg out.dxf命令返回码是 0脚本判断成功但 out.dxf 文件大小是 0 字节。原因0.4 部分分支在读取异常时并没有设置非零退出码错误信息打到 stderr 却被脚本忽略了。只在 stdout 里没有内容文件自然为空。这种情况最容易在无人值守脚本里造成误判下游程序拿到空文件后还可能产生连锁错误。解决脚本里不能只判断退出码要检查输出文件的尺寸dwg2dxf in.dwg out.dxf 2err.log if [ ! -s out.dxf ]; then echo conversion failed, see err.log exit 1 fi-s测试文件存在且大小非零这个判断能兜住“假成功”的情况。现在我对所有转换工具的输出都默认加一层文件大小校验不管是 dwg2dxf 还是别的命令行转换器这个习惯救过很多次。6. 进阶技巧批量统计图纸内容与解析结果校验工具到这一步能跑、能坑也能避了剩下的是怎么把它用出效率。这章讲批量处理和结果验证也是我日常干活时最依赖的套路。6.1 批量扫描目录并统计图层分布批量处理时我通常会写一个循环脚本把 dwgread 的输出按图层维度聚合。一个简单的做法是用 awk 直接提取图层行再排序#!/bin/bash for f in $; do echo $f dwgread -s -l $f 2/dev/null \ | grep -E ^LAYER \ | awk {print $2} \ | sort | uniq -c done这段脚本对传入的所有 DWG 文件做一次实体输出然后把图层行里第二列的图层名取出来计数最后按名称排序。输出的数字就是每个图层里出现的对象数量虽然不是严格的“实体按图层分布”但作为批量筛查已经足够。真实项目的图纸可能包含几十个图层用这个脚本跑一遍哪些图层使用频率高一眼就能看出来再决定后续按什么口径抽数据。6.2 用 DXF 中间态对接下游几何分析0.4 的 JSON 输出不完整所以我更愿意让 dwg2dxf 打头阵再把 DXF 交给 Python 的 ezdxf 做结构化处理。示例import subprocess import ezdxf subprocess.run( [dwg2dxf, drawing.dwg], stdoutopen(mid.dxf, wb), checkTrue ) doc ezdxf.readfile(mid.dxf) for e in doc.modelspace(): print(e.dxftype(), e.dxf.layer)这个流程兼顾了 libdwg 的解析能力和 ezdxf 的模型空间遍历能力。ezdxf 的 modelspace 会返回所有图元对象访问 dxftype 拿到实体类型访问 dxf.layer 拿到所属图层。对于转换引入的圆弧拟合误差在 ezdxf 里重建圆弧的时候按三点重建误差评估可控。6.3 解析结果的交叉校验方法解析库的输出是不是可信永远值得验证。我的做法分三步一是实体计数对比把 dwgread 输出里的实体类型和数量跟 AutoCAD 里 LIST 命令的结果抽样对比每次抽三到五个块二是几何抽样取一条直线和一个圆弧在源文件里记录端点坐标和半径和 DXF 中间态里的同义组码比对数值差异超过 1 毫米就要警惕三是编码校验对所有文本类图元做字节级检查确认中文和符号没有被转坏。我从那次图纸清查之后每次拿到新一批 DWG 都强制先跑一遍dwgread -v确认版本再对前三个文件做交叉校验通过后才把整套解析流程放到全量数据上。这套流程帮我挡掉了不少由于图纸版本混用而带来的脏数据前期慢几分钟后期能少返工好几天。希望这些拆解和踩坑记录能帮到正打算拿 libdwg-0.4 处理图纸的你。本文还有配套的精品资源点击获取