libdxfrw 实战指南:30 分钟写一个能读 DXF 和 DWG 的图纸文字提取器
libdxfrw 实战指南30 分钟写一个能读 DXF 和 DWG 的图纸文字提取器【免费下载链接】libdxfrwC library to read and write DXF/DWG files项目地址: https://gitcode.com/gh_mirrors/li/libdxfrw周五下午甲方丢过来 40 张.dwg施工图让你把每张图纸的标注文字、图号、说明全部导进系统——而你手头的程序只认.dxfAutoCAD 又没装。别急着谈外包libdxfrw这个免费开源的 C 库正是为这类场景准备的它既能读写 ASCII 和二进制两种 DXF也能从 R14 到 V2015 的 DWG 里解析出全部实体。这篇文章就带你沿着装库 → 读一个 DXF → 同时吞下 DWG → 批量导出台账这条主线把方案完整跑通。先搞清楚它值不值得用能力与边界在动手前先给这个库画个像避免你后面白费力气DXF 全格式读写ASCII 与二进制都能读写支持 R12、2000、2004、2007、2010 五个版本。DWG 只读解析内置 15/18/21/24/27 五个版本化阅读器对应 R14、R2004、R2007、R2010、R2013/R2015。回调式接口你只需要继承DRW_Interface实现几个回调解析细节全部由dxfRW/dwgR驱动。多构建系统CMake、Autotools、Visual Studiovs2013/libdxfrw.sln、MinGW 都支持Linux/macOS/Windows 通吃。自带参考实现仓库里的dwg2dxf和dwg2text两个工具就是现成的 API 教材。⚠️明确边界不支持 DWG 写入只能读GPL v2 协议商用需留意传染性条款。一句话总结它是图纸数据提取和DXF 生成的瑞士军刀但不是 DWG 编辑器。装好环境四条命令跑通一个验证推荐 CMake 路线依赖只有一个libiconv字符编码转换。Ubuntu/Debian 下执行sudo apt-get install build-essential cmake libiconv-hook-dev git clone https://gitcode.com/gh_mirrors/li/libdxfrw cd libdxfrw mkdir build cd build cmake .. -DCMAKE_BUILD_TYPERelease cmake --build . --config Release sudo cmake --build . --config Release --target install安装后头文件在/usr/local/include/静态库是/usr/local/lib/libdxfrw.a。验证环境是否就绪ls /usr/local/lib/libdxfrw.a echo lib OK看到lib OK就说明库装好了。macOS 用brew install cmake libiconvWindows 直接打开vs2013/libdxfrw.sln编译即可。第一个能跑的程序20 行读懂一张 DXFlibdxfrw的核心设计是回调接口你继承DRW_Interface按需实现实体回调然后把对象交给dxfRW::read()去驱动。下面这个最小读取器会打印文件里的每一条线和每一个圆#include cstdio #include libdxfrw.h class MyReader : public DRW_Interface { public: // ---- 以下回调全部置空只关心实体 ---- void addHeader(const DRW_Header*) override {} void addLType(const DRW_LType) override {} void addLayer(const DRW_Layer) override {} void addDimStyle(const DRW_Dimstyle) override {} void addVport(const DRW_Vport) override {} void addTextStyle(const DRW_Textstyle) override {} void addAppId(const DRW_AppId) override {} void addBlock(const DRW_Block) override {} void setBlock(const int) override {} void endBlock() override {} void addPoint(const DRW_Point) override {} void addRay(const DRW_Ray) override {} void addXline(const DRW_Xline) override {} void addArc(const DRW_Arc) override {} void addEllipse(const DRW_Ellipse) override {} void addLWPolyline(const DRW_LWPolyline) override {} void addPolyline(const DRW_Polyline) override {} void addSpline(const DRW_Spline*) override {} void addKnot(const DRW_Entity) override {} void addInsert(const DRW_Insert) override {} void addTrace(const DRW_Trace) override {} void add3dFace(const DRW_3Dface) override {} void addSolid(const DRW_Solid) override {} void addMText(const DRW_MText) override {} void addText(const DRW_Text) override {} void addDimAlign(const DRW_DimAligned*) override {} void addDimLinear(const DRW_DimLinear*) override {} void addDimRadial(const DRW_DimRadial*) override {} void addDimDiametric(const DRW_DimDiametric*) override {} void addDimAngular(const DRW_DimAngular*) override {} void addDimAngular3P(const DRW_DimAngular3p*) override {} void addDimOrdinate(const DRW_DimOrdinate*) override {} void addLeader(const DRW_Leader*) override {} void addHatch(const DRW_Hatch*) override {} void addViewport(const DRW_Viewport) override {} void addImage(const DRW_Image*) override {} void linkImage(const DRW_ImageDef*) override {} void addComment(const char*) override {} void writeHeader(DRW_Header) override {} void writeBlocks() override {} void writeBlockRecords() override {} void writeEntities() override {} void writeLTypes() override {} void writeLayers() override {} void writeTextstyles() override {} void writeVports() override {} void writeDimstyles() override {} void writeAppId() override {} // ---- 真正干活的回调 ---- void addLine(const DRW_Line d) override { printf(LINE (%.2f,%.2f) - (%.2f,%.2f)\n, d.basePoint.x, d.basePoint.y, // 起点 d.secPoint.x, d.secPoint.y); // 终点 } void addCircle(const DRW_Circle d) override { printf(CIRCLE 中心(%.2f,%.2f) 半径%.2f\n, d.basePoint.x, d.basePoint.y, d.radious); } }; int main() { MyReader r; dxfRW dxf(drawing.dxf); if (!dxf.read(r, false)) return 1; // false 不做 2D 投影保留原始坐标 return 0; }编译链接时别忘了两个库g -o myreader myreader.cpp -ldxfrw -liconv跑一下你会看到每根线段和圆的坐标被逐个打印。看懂这段代码你就摸清了整个库的架构DRW_Interface是唯一的契约读什么文件、怎么解析全由dxfRW内部完成。主线推进把示例升级成格式无关的文字提取器只打印坐标没什么用回到开头的真实需求——从图纸里批量提取文字。把上面的读取器扩展成支持 TEXT、MTEXT 的提取器顺便打通 DWG#include cstdio #include string #include libdxfrw.h #include libdwgr.h // 完整实现见上一步这里只展示扩展部分 void addText(const DRW_Text d) override { printf([TEXT] %s\n, d.text.c_str()); // 普通单行文字 } void addMText(const DRW_MText d) override { printf([MTEXT] %s\n, d.text.c_str()); // 多行文字 } // 格式无关导入同一个回调同时喂给 dxfRW 和 dwgR bool importFile(const char* path, DRW_Interface* cb) { std::string p(path); if (p.size() 4 p.substr(p.size()-4) .dxf) return dxfRW(path).read(cb, false); if (p.size() 4 p.substr(p.size()-4) .dwg) return dwgR(path).read(cb, false); return false; } int main(int argc, char** argv) { if (argc 2) return 1; MyReader r; if (!importFile(argv[1], r)) return 1; // DXF/DWG 一视同仁 return 0; }这里有个值得圈点的设计dwgR与dxfRW接口签名完全一致上层业务只认DRW_Interface一种回调底层是 DXF 还是 DWG 对你完全透明——这正是把文件批量处理写成循环的关键。配合 shell 管道你就能把所有图纸的文字汇总成台账./extractor floor_01.dwg 台账.txt ./extractor floor_02.dxf 台账.txt如果你的需求只是转换格式而不是写代码仓库自带的dwg2dxf直接可用./dwg2dxf input.dwg -v2000 -b output.dxf # 转成 2000 版二进制 DXF ./dwg2dxf filelist.txt -B outdir/ # 从清单批量转换参数含义-R12 / -v2000 / -v2004 / -v2007 / -v2010指定输出版本-b输出二进制-B批量模式-y静默覆盖。它的源码在dwg2dxf/dx_iface.h是理解读进来→写出去全流程的最佳范本。途中踩过的坑三个让我翻车的细节这套流程我写过不止一遍三个坑每次都有人踩坑一只实现几个回调编译直接失败。DRW_Interface的几十个 0纯虚函数一个都不能少。第一次写时我图省事只写了addLine编译器立刻教做人。正确做法是把空实现全部补齐上面代码已给出完整清单或者像dwg2dxf/dx_iface.h那样用内部数据类兜住所有回调。坑二版本号写错。想输出 2000 版 DXF我第一反应是写DRW::R2000——编译都过不了。版本枚举在drw_base.h里是AC 开头AC1009R12、AC10152000、AC10182004、AC10212007、AC10242010、AC10272013。坑三中文乱码就怀疑库。图纸文字的编码CP932/CP936/CP949/CP950 等由src/intern/drw_textcodec.cpp配合码表自动转换回调里拿到的通常是 UTF-8。乱码时优先检查源文件的 code page 声明和你的输出端编码而不是去改库源码。错误写法正确写法原因只实现addLine/addCircle全部纯虚函数补空实现否则编译不过DRW::R2000当版本号DRW::AC1015枚举是 AC 开头编码read()的ext传true要原始 3D 坐标就传falsetrue会应用 extrusion 投影改坐标想让库写 DWG先写 DXF 再用dwg2dxf转库不支持 DWG 写入藏在细节里的两个惊喜主流程跑通后这两个 API 能救你于水火惊喜一椭圆离散化精度控制。下游工具不认椭圆比如老版 R12时dxfRW::setEllipseParts(64)可以把椭圆离散成多段线再导出。分段数越大越圆滑代价是文件体积变大——遇到大椭圆变多边形的诡异现象调这个值就行。惊喜二调试开关 错误定位。解析失败时先打开调试输出dxf.setDebug(DRW::DEBUG);再配合dwgR::getError()和dwgR::getVersion()能快速分辨是版本不支持错误码BAD_VERSION还是文件损坏BAD_READ_ENTITIES等错误码枚举定义在src/drw_base.h。这一对组合拳能省掉你一半的排查时间。收个尾你的下一步动作回顾这条主线四条命令装好库 → 20 行读懂 DXF → 一个回调同时吞下 DXF/DWG → 批量提取文字汇成台账外加两处藏着的实用 API。整个过程你没写过一行文件解析代码全靠回调接口。现在最该做的动作把仓库 clone 下来用dwg2dxf转一张你手头的 DWG再把你项目里那个只认 DXF的导入函数替换成本文的importFile双入口版本。10 分钟后你会听到同事问这活你怎么这么快干完的。【免费下载链接】libdxfrwC library to read and write DXF/DWG files项目地址: https://gitcode.com/gh_mirrors/li/libdxfrw创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考