{"id":51625949,"url":"https://github.com/diskd-ai/dwg2png","last_synced_at":"2026-07-13T01:02:51.080Z","repository":{"id":367389786,"uuid":"1280174420","full_name":"diskd-ai/dwg2png","owner":"diskd-ai","description":"Pure-Rust DWG -\u003e multipage PNG renderer + lossless position-referenced text layer \u0026 metadata indexer for RAG/VLM ingestion of CAD drawings","archived":false,"fork":false,"pushed_at":"2026-06-25T18:58:22.000Z","size":59,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-25T20:21:31.233Z","etag":null,"topics":["acadrust","autocad","blueprint","cad","cad-rendering","dwg","dxf","engineering-drawings","ocr-free","png","rag","rasterizer","rust","text-extraction","tiny-skia","vlm"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/diskd-ai.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-25T10:37:44.000Z","updated_at":"2026-06-25T20:07:35.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/diskd-ai/dwg2png","commit_stats":null,"previous_names":["diskd-ai/dwg2png"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/diskd-ai/dwg2png","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diskd-ai%2Fdwg2png","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diskd-ai%2Fdwg2png/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diskd-ai%2Fdwg2png/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diskd-ai%2Fdwg2png/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/diskd-ai","download_url":"https://codeload.github.com/diskd-ai/dwg2png/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diskd-ai%2Fdwg2png/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35406584,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-12T02:00:06.386Z","response_time":87,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["acadrust","autocad","blueprint","cad","cad-rendering","dwg","dxf","engineering-drawings","ocr-free","png","rag","rasterizer","rust","text-extraction","tiny-skia","vlm"],"created_at":"2026-07-13T01:02:46.988Z","updated_at":"2026-07-13T01:02:51.062Z","avatar_url":"https://github.com/diskd-ai.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# dwg2png\n\nPure-Rust **DWG \u0026rarr; multipage PNG** renderer and **metadata indexer** for a\nSaaS backend that indexes DWG files. Parses native DWG (R13\u0026ndash;R2018) with\n[`acadrust`](https://github.com/hakanaktt/acadrust) (MPL-2.0, no C deps), renders\neach layout (Model space + paper-space sheets) to PNG with\n[`tiny-skia`](https://github.com/RazrFalcon/tiny-skia) on the CPU, and extracts a\nsearchable index document (layers, blocks, title-block attributes, text,\nlayouts) as JSON.\n\nNo GPL (LibreDWG avoided), no FFI, no GPU, no external CAD engine.\n\n## Download\n\nPrebuilt binaries for macOS (Intel + Apple Silicon), Linux, and Windows are\nattached to each [release](https://github.com/diskd-ai/dwg2png/releases).\nDownload the archive for your platform, extract `dwg2png`, and run it.\n\n```sh\n# macOS (Apple Silicon) example\ntar -xzf dwg2png-aarch64-apple-darwin.tar.gz\n./dwg2png --help\n```\n\nOr build from source: `cargo build --release` (Rust stable).\n\nReleases are produced automatically by `.github/workflows/release.yml` when a\n`v*` tag is pushed.\n\n## Usage\n\n```sh\n# Render + index a file or a whole directory tree of .dwg files\ndwg2png \u003cfile-or-dir\u003e [more...] --out out [--size PX] [--tiles] [--font TTF] [--no-compare]\n\n# Recommended for VLM ingestion: high-res + readable tiles + text layer\ndwg2png drawings/ --out out --size 6000 --tiles\n```\n\nFlags: `--size` = long-edge pixels (default 3000, up to 12000). `--tiles` =\nalso emit ~1500 px readable crops (`--tile-size N` to change). `--font` defaults\nto `/System/Library/Fonts/Supplemental/Arial.ttf` (Cyrillic); override via\n`DWG2PNG_FONT`. When a sibling PDF matches a DWG name and `pdftoppm` is on\n`PATH`, the report shows a side-by-side against the plotted PDF.\n\nOutputs under `--out`:\n\n- `img/fNN-pMM.png` \u0026mdash; one PNG per page (`p00` = Model space, then each paper sheet)\n- `labels/fNN-pMM.json` \u0026mdash; **position-referenced text layer**: every label with exact text, pixel `x,y,w,h`, screen rotation, color, and layer\n- `tiles/fNN-pMM/rRcC.png` + `tiles.json` \u0026mdash; readable crops with per-tile labels (when `--tiles`)\n- `json/fNN.json` \u0026mdash; the searchable `IndexDoc` per file\n- `report.html` \u0026mdash; self-contained report: thumbnails, a **toggleable SVG text overlay**, ground-truth comparisons, and the tile crops\n\n### Reading all labels (VLM / search)\n\nTiny CAD labels are sub-pixel against a large drawing extent, and VLMs downscale\nimages on input \u0026mdash; so no single raster makes every label legible. Two\ncomplementary channels solve this:\n\n1. **Text layer** (`labels/*.json`) \u0026mdash; the strings come straight from the DWG,\n   so they are 100% accurate (no OCR), each anchored to a pixel position. This is\n   the reliable channel for \"read every label.\"\n2. **Tiles** (`--tiles`) \u0026mdash; ~1500 px crops where text is large enough to read\n   visually; feed tiles (plus the matching per-tile labels) to a VLM.\n\nThe report's \"Toggle text layer\" button overlays the text as crisp vector SVG\nthat stays sharp at any zoom.\n\n## Run in Docker\n\nA minimal container (Debian slim + the stripped binary + DejaVu Sans for\nLatin/Cyrillic) is provided. No GPU, no C libraries, no external CAD engine.\n\n```sh\ndocker build -t dwg2png:latest .\n\n# one-shot conversion of a mounted folder\ndocker run --rm -v \"$PWD/input:/work/input:ro\" -v \"$PWD/output:/work/output\" \\\n  dwg2png:latest /work/input --out /work/output --size 6000 --tiles --no-compare\n```\n\nOr via Compose (mounts `./input` and `./output`):\n\n```sh\nmkdir -p input output \u0026\u0026 cp *.dwg input/\ndocker compose run --rm dwg2png\n```\n\nThe font is set via `DWG2PNG_FONT` in the image; override with `--font` or a bind\nmount to use a different typeface.\n\n## Requirements \u0026 performance\n\nMeasured in-container on real DWG 2018 files (full numbers in\n[`MEASUREMENTS.md`](MEASUREMENTS.md)):\n\n| | |\n|---|---|\n| Image size | **81 MB** (2.3 MB binary + slim base + font) |\n| Typical file (≤1 MB, 3 pages) | **~1–2 s**, **200–450 MB** RAM |\n| Worst case (46 MB drawing) | ~27 s, **~2.8 GB** RAM (parse-bound) |\n| Recommended memory limit | **1 GB** normal DWGs · **4 GB** if large site plans possible |\n| CPU | 1 core per file; scale out with replicas (one DWG per run) |\n\nMemory tracks **DWG size**, not render resolution — the parser holds the model\nin memory. Gate very large uploads or route them to a high-memory queue.\n\n## Use in RAG chains\n\ndwg2png turns an opaque binary DWG into retrievable, citable artifacts. Run the\ncontainer as an ingestion step, then index its output:\n\n```\nDWG ──[dwg2png container]──▶  labels/*.json   (exact text + pixel bbox + page + layer)\n                              json/*.json     (per-file index: layers, blocks, attributes)\n                              tiles/*.png      (~1500px readable crops for VLM input)\n                              img/*.png        (full-page previews)\n```\n\nTwo retrieval channels, both grounded:\n\n- **Text RAG (no OCR).** Each entry in `labels/*.json` is an exact string with a\n  pixel `x,y,w,h`, `page`, `layer`, and `color`. Embed labels (individually or\n  grouped by proximity/layer) and store the geometry as metadata. Retrieval is\n  lossless and every answer can cite the precise label location. The per-file\n  `json/*.json` adds title-block attributes (e.g. cadastral numbers, areas) and\n  the block/layer inventory as structured fields.\n- **Multimodal RAG.** Embed `tiles/*.png` (image embeddings) for visual queries;\n  each tile's `tiles.json` carries the labels inside that crop, so a retrieved\n  tile arrives with its text already extracted — feed both to a VLM.\n\nWhy it fits RAG: the text is 100% accurate (straight from the DWG, no OCR drift),\npositionally grounded for citations, multimodal, deterministic, and fully\noffline. A practical chunking strategy: one chunk per label cluster (same layer,\nnearby bbox) with `{file, page, layer, bbox}` metadata; link clusters to their\ntile image for multimodal answers.\n\n## Architecture (boundaries)\n\n```\nparse (acadrust adapter) ─→ tessellate/pages (pure geometry) ─→ render (tiny-skia) ─→ PNG\n                                       └────────────────────────→ metadata ─→ IndexDoc (JSON)\nreport renders results to HTML.\n```\n\n| Module | Responsibility |\n|--------|----------------|\n| `lib.rs` | composition root: parse (only acadrust I/O), orchestrate, crash isolation |\n| `model.rs` | pure domain types: `P`, `Aff`, `Rgb`, `Prim`, `Bounds`, `Page`, `Overlay` |\n| `color.rs` | ACI / ByLayer / ByBlock \u0026rarr; RGB (color 7 \u0026rarr; black on white paper) |\n| `tessellate.rs` | entity \u0026rarr; primitives + text `Label`s; arc/bulge sampling; INSERT recursion; Text/MText/Attribute/Dimension/MultiLeader |\n| `text.rs` | TrueType glyph outlines (ab_glyph) \u0026rarr; filled contours; MTEXT code stripping |\n| `pages.rs` | Layout enumeration; model framing; **paper-space viewport projection** (geometry + labels) |\n| `render.rs` | world\u0026rarr;screen transform, color-batched stroke/fill, viewport clip masks, **pixel-space text layer**, **tiling** |\n| `metadata.rs` | `IndexDoc`: histogram, layers, blocks, attributes, text, layouts |\n| `report.rs` | HTML report |\n\nacadrust is imported only in `lib.rs`, `pages.rs`, `tessellate.rs`, `metadata.rs`\n\u0026mdash; the rest depends on the pure `model` types, so the parser can be swapped\nwithout touching geometry or rendering.\n\n## What it renders\n\nLine, LwPolyline, Polyline/2D/3D (with bulge arcs), Circle, Arc, Ellipse, Spline\n(fit/control points), Solid, Point, Text, MText, Attribute values, and INSERT\nblocks (recursive, with composed transform and ByBlock color inheritance).\nPaper-space **viewports project model geometry** into the sheet at the plotted\nposition, scale, and twist, clipped to the viewport rectangle.\n\n## Verified on real data\n\nRun against 11 real DWG 2018 (AC1032) construction/survey files\n(heat-network as-builts), 4\u0026ndash;46 MB:\n\n- **11/11 parsed, 23 pages rendered, 0 crashes.**\n- Parse 33\u0026ndash;85 ms for typical files; the 46 MB file in ~20 s.\n- The corrupt/recovered file (bad header) **degraded to a placeholder via\n  failsafe instead of crashing** \u0026mdash; the SaaS crash-isolation requirement.\n- Cyrillic text, layer colors, title-block attributes (e.g. cadastral numbers,\n  areas) all extracted and rendered correctly.\n- Side-by-side vs a plotted reference PDF shows matching network topology,\n  building footprints, and utility runs.\n\n## Known v1 limitations\n\n- **Not rendered (counted in metadata):** Hatch fills, Dimension geometry,\n  Leader/MultiLeader, MLine, raster images, 3D solids. The drawing remains\n  recognizable from lines/polylines/text/blocks.\n- **Splines** use fit points when present, else the control polygon\n  (no De\u0026nbsp;Boor) \u0026mdash; chosen for crash-safety on malformed knots.\n- **Text** ignores horizontal/vertical alignment offsets; SHX fonts are\n  substituted with the configured TrueType font.\n- **Lineweights** render as hairlines (constant ~1 px).\n- **Per-viewport UCS / layer freeze** not applied; a viewport aimed at an empty\n  model region renders empty (correct, but sparse).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiskd-ai%2Fdwg2png","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiskd-ai%2Fdwg2png","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiskd-ai%2Fdwg2png/lists"}