odf

Pure-Crystal OASIS OpenDocument Format 1.3 library shard with zero runtime dependencies, providing native .ods spreadsheet generation, live OpenFormula cells, XXE-safe reading, and an extensible core for .odt, .odp, and .odg.

odf Banner

Pure-Crystal OASIS OpenDocument Format 1.3 library shard with zero runtime dependencies, starting with full .ods spreadsheet reading and writing and architected for community expansion across .odt, .odp, and .odg.

Version 0.1.0 Crystal >= 1.21.0 Zero Dependencies ODF 1.3 Standard Ameba Clean Flaw Clean

Sphinx Documentation Crystal API Documentation License: GPL-3.0-or-later Docs License: GFDL-1.3-or-later Donate using Liberapay

GitLab Project Metadata:

  • Description: Pure-Crystal OASIS OpenDocument Format 1.3 library shard with zero runtime dependencies, providing native .ods spreadsheet generation, live OpenFormula cells, XXE-safe reading, and an extensible core for .odt, .odp, and .odg.
  • Topics: crystal, crystal-lang, opendocument, odf, ods, libreoffice, spreadsheet, openformula, foss, gplv3

Overview

odf (module Odf) is a native, pure-Crystal implementation of the OASIS OpenDocument Format (ODF 1.3), built exclusively on Crystal's standard library (XML, Compress::Zip, and Digest::CRC32).

It requires zero C bindings, zero external shards, and zero Python/Java subprocesses, allowing Crystal CLI tools, web services, and financial engines to compile into self-contained static binaries (including Alpine/musl targets) while generating and reading standards-compliant LibreOffice/Collabora/Nextcloud Office documents.

Scope and Extensible Architecture

odf separates the ODF 1.3 package, security, and stylesheet layer from document-domain modules:

Layer/Module MIME Type and Extension Target Release Status
Odf::Package & Odf::Xml ZIP container, STORED mimetype, manifest.xml, XXE/Zip-bomb/symlink guards v0.1.0 Implemented — v0.1.0
Odf::Styles & Odf::Formula Fonts, cell/border/number/currency/date styles, page layouts, OpenFormula of:= v0.1.0 Implemented — v0.1.0
Odf::Spreadsheet Writer application/vnd.oasis.opendocument.spreadsheet, .ods v0.1.0 Implemented — v0.1.0
Odf::Spreadsheet Reader application/vnd.oasis.opendocument.spreadsheet, .ods v0.1.0 Implemented — v0.1.0
Odf::Text application/vnd.oasis.opendocument.text, .odt v0.2.0+ Open for Community, Phase 3
Odf::Presentation application/vnd.oasis.opendocument.presentation, .odp v0.3.0+ Open for Community, Phase 3
Odf::Drawing application/vnd.oasis.opendocument.graphics, .odg v0.4.0+ Open for Community, Phase 3

v0.1.0 Capabilities

  1. Strict ODF 1.3 Package Conformance: Emits ZIP archives with an uncompressed CompressionMethod::STORED mimetype entry and precomputed CRC32 at byte offset 30, valid META-INF/manifest.xml, styles.xml, and content.xml.
  2. Declarative Odf::Spreadsheet Workbook Writer:
    • Multiple worksheets, explicit column widths, and row heights.
    • Typed cells: text, integer, float, currency, percent, boolean, date, and time.
    • Live OpenFormula (of:=...) expression cells with deterministic cached numeric/string fallback values.
    • Custom cell styles: typography, background fills, borders, horizontal/vertical alignment, number precision, currency symbols, and conditional negative-number coloring.
    • Layout controls: merged cell spans (number-columns-spanned and number-rows-spanned), frozen header rows/columns, landscape/portrait print scaling, and autofilter table:database-range definitions.
  3. Defensive Odf::Spreadsheet Reader:
    • XXE-safe XML parsing enforcing XML::ParserOptions::NONET and disabling external entity expansion.
    • Decompression byte-budget quotas (max_entry_bytes, max_total_bytes, and max_entries) preventing Zip-bomb denial-of-service.
    • Automatic expansion of ODF table:number-columns-repeated and table:number-rows-repeated run-length attributes with bounded cell-allocation limits.
  4. Open Odf::Document Extension Contract: Any ODF document class implementing #media_type, #styles_registry, and #emit_body (with optional #emit_automatic_styles, #settings_xml, and #extra_entries hooks) plugs directly into Odf::Package::Writer without modifying archive or manifest internals.

Installation

Add odf to your application's shard.yml:

dependencies:
  odf:
    gitlab: renich/odf
    version: ~> 0.1.0

Then run:

shards install

Usage

Writing a Multi-Sheet .ods Workbook with Live Formulas

require "odf"

workbook = Odf::Spreadsheet::Workbook.new do |wb|
  wb.currency_style("usd", symbol: "$", decimals: 2, negative_red: true)

  wb.sheet("Hardware_BOM") do |sheet|
    sheet.columns("22mm", "64mm", "38mm", "42mm")
    sheet.freeze(rows: 1)

    sheet.header_row(["Qty", "Component", "Unit Price", "Line Total"])
    sheet.row do |row|
      row.integer(9)
      row.text("Dell PowerEdge R7725 Ceph OSD")
      row.currency(638_017.63, style: "usd")
      row.formula("=[.A2]*[.C2]", cached: 5_742_158.67, style: "usd")
    end
    sheet.row do |row|
      row.integer(5)
      row.text("Dell PowerSwitch Z9432F-ON 400GbE")
      row.currency(24_750.00, style: "usd")
      row.formula("=[.A3]*[.C3]", cached: 123_750.00, style: "usd")
    end
    sheet.row do |row|
      row.empty
      row.text("Total Discounted CapEx", bold: true)
      row.empty
      row.formula("=SUM([.D2:.D3])", cached: 5_865_908.67, style: "usd", bold: true)
    end

    sheet.autofilter("A1:D3")
  end
end

workbook.save("cluster_bom.ods")

Reading an .ods Workbook Safely

require "odf"

doc = Odf::Spreadsheet::Reader.open("cluster_bom.ods")
sheet = doc.sheet("Hardware_BOM")

sheet.rows.each_with_index do |row, idx|
  puts "Row #{idx + 1}: #{row.map(&.to_s).join(" | ")}"
end

Community Contributions Beyond Spreadsheets

v0.1.0 focuses deliberately on Odf::Spreadsheet (.ods) so the core package, style registry, and security boundaries are battle-tested in production (cl8r, dq, qtr).

Community contributors interested in adding:

  • Odf::Text (.odt) — headings, paragraphs, lists, tables, headers/footers, and page breaks
  • Odf::Presentation (.odp) — master slide layouts, text frames, speaker notes, and SVG embeds
  • Odf::Drawing (.odg) — vector shapes, connectors, and layered canvases

are warmly encouraged to join! Check Extensibility Contract, Phase 3 Roadmap, and CONTRIBUTING.rst to get started.


Build System Targets

Target Description
make setup Installs dev shards (ameba, flaw), configures .githooks, and runs verification
make test Runs the Crystal spec suite (crystal spec --error-trace)
make lint Runs crystal tool format --check, Ameba static analysis, and Flaw SAST scanner
make diagrams Compiles D2 architecture and roadmap .d2 diagrams to .svg
make doc-check Lints all reStructuredText documentation with crstlint and rstcheck
make check Runs doc-check, test, and lint
make coverage Generates HTML code coverage reports under coverage/ using kcov
make ci Runs the non-mutating CI verification pipeline
make docs Builds Crystal API reference and Sphinx HTML/dirhtml documentation

Documentation Suite

Complete specifications, Architecture Decision Records, and phased roadmaps live under docs/:

Domain Scope Entry Point
Business Context Ecosystem gap, FOSS document sovereignty, stakeholders, and metrics Business Specs
Functional Specs Requirements [FUNC-001]..[FUNC-008] for package, styles, .ods, and extensibility Functional Specs
Technical Blueprint Modules [TECH-001]..[TECH-007], Crystal types, security limits, and coding rules Technical Specs
ADR Log Architectural rationale for zero-dependency ODF 1.3 design and licensing ADR Index
Project Roadmap Sequenced Phases 1–3 with task dependencies, critical path, and D2 diagrams Project Roadmap
User & Dev Guides Quickstart guide and Odf::Document extension tutorial User Manual

Contributing and Code of Honor

All human and AI contributions must uphold the Universal Code of Honor and follow the Contributing Guidelines.


License

  • Software Source Code: GNU General Public License v3.0 or later (LICENSE).
  • Documentation: GNU Free Documentation License v1.3 or later, with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts (LICENSE-DOCS).
  • Embedded Documentation Code Examples: Dual-licensed under the MIT License and GPL-3.0-or-later so snippets in README.md and docs/ can be copied freely into downstream projects.

Copyleft © 2026 Rénich Bon Ćirić renich@evalinux.com.


Support and Donations

If you find this shard useful and wish to support its ongoing development, please consider donating:

Donate using Liberapay

Repository

odf

Owner
Statistic
  • 0
  • 0
  • 0
  • 0
  • 2
  • 2 days ago
  • October 29, 2026
License

GNU General Public License v3.0 or later

Links
Synced at

Thu, 29 Oct 2026 08:53:17 GMT

Languages