// STRYKE-OFFICE — OFFICE DOCUMENT I/O FOR STRYKE // EXCEL + WORD + POWERPOINT + ODF + PDF

stryke package · cdylib libstryke_office · loaded on use Office · all native (no LibreOffice/soffice)

Report GitHub Issues
// Color scheme

>_STRYKE-OFFICE

Read and write the whole office suite — no LibreOffice required. Excel/Calc (xlsx/ods), Word/Writer (docx/odt), PowerPoint/Impress (pptx/odp), PDF, and a full PIL-style image surface (png/jpeg/gif/bmp/webp/tiff — open/save/crop/resize/convert/paste/draw), entirely in native Rust. No soffice / LibreOffice / pandoc subprocess; the cdylib is self-contained.

Install

# from a release tarball
s pkg install -g github.com/MenkeTechnologies/stryke-office

# from a local checkout
cd ~/projects/stryke-office
cargo build --release
s pkg install -g .           # cdylib lands in ~/.stryke/store/office@<version>/

# one-liner
make install

This is a library — there is no CLI launcher. The cdylib is dlopened in-process on the first use Office.

Quick start

use Office

# spreadsheet: write xlsx, read back, re-emit as ods
Office::sheet_write("report.xlsx", [
    { name => "Sales", rows => [["product", "units"], ["widget", 120]] },
])
val $sheets = Office::sheet_read("report.xlsx")
Office::sheet_write("report.ods", $sheets)

# document: build a docx from structured blocks
Office::doc_write("memo.docx", [
    { kind => "heading", level => 1, text => "Quarterly Report" },
    { kind => "para", text => "Revenue grew 18%." },
])

# presentation + pdf
Office::slides_write("deck.pptx", [{ title => "Intro", body => ["point one"] }])
Office::pdf_write("out.pdf", ["Line one", "Line two"])

Format matrix

Spreadsheetread xlsx / ods / xls / csv / tsv · write xlsx, ods, csv, tsv, html, md
Documentread docx / odt / html / md / rtf / txt · write docx, odt, html, md, rtf, txt, pdf
Presentationread + write pptx, odp
PDFread text + pages · write text (A4) · merge/split/rotate/encrypt/forms/outline
Imageread + write png/jpeg/gif/bmp/webp/tiff/avif/ico/tga/qoi/pnm/dds/hdr/exr/ff · resize/crop/rotate/convert/paste · draw rect/line/circle/text · filters / color science / distortions (PIL-complete)

Output format comes from the path extension; override with format => "...". Every raster codec the image crate ships is enabled, so read and write cover the full image list above.

Surface at a glance

The Office namespace exposes 465 public functions across these families. The full reference for each is in the tables below.

sheet_* — 175read/write + dataframe analytics (group-by, pivot, join, stats, time-series, finance, sampling, export)
img_* — 111PIL-complete handle-based image surface
pdf_* — 47build/merge/split/encrypt/forms/outline/annotations/attachments
doc_* — 30read/write, structure, stats, summary, diff, convert
slides_* — 26read/write, reorder, merge, stats, convert
text_* — 20plain-text toolkit (grep/sort/uniq/sed/cut/…)
range/a1/r1c1 — 20A1 / R1C1 / range math (no workbook opened)
chart_* — 560+ chart types, raster + SVG + PDF
barcode_* — 4QR + 1D → image handle
converters & misc — ~27csv/md/html/xml/json/ndjson ↔ sheets, metadata, color, media extraction, mail-merge

Core I/O

Office::version()package version string
Office::info($path)universal inspector — identify any office/image file + type summary
Office::sheet_read($path, %opts)arrayref of { name, rows } — numbers stay numeric, empty cells undef; formulas => 1 attaches formula strings; delimiter for csv/tsv
Office::sheet_write($path, $sheets, %opts)$sheets: [{ name, rows => [[...]] }]; writes xlsx/ods/csv/tsv + html/md tables; format / defined_names / properties opts
Office::doc_read($path)list of paragraph strings (docx/odt)
Office::doc_write($path, $blocks, %opts)block: { kind => "para"|"heading"|"list"|"link"|"table"|"image"|"pagebreak", … }; header/footer/page_numbers/page_size
Office::slides_read($path)arrayref of { text => [...], notes => [...] } (pptx/odp)
Office::slides_write($path, $slides, %opts)slide: { title, body => [...] }
Office::pdf_read($path){ pages => [...], text }
Office::pdf_write($path, $lines)$lines: arrayref of strings (A4)
Office::pdf_build($path, $elements, %opts)multi-page: heading/paragraph/text/image/rect/line/table/pagebreak; page_size/margin

Spreadsheet analytics (sheet_*)

175 functions turn a spreadsheet path into a dataframe-style toolkit. Each opens the file, applies the operation, and (when an $output is given) writes the result; the target format is taken from the output extension. A few representative groups:

Inspectsheet_info, sheet_names, sheet_dims, sheet_stats, sheet_describe, sheet_profile, sheet_dtypes, sheet_count, sheet_nunique, sheet_mode, sheet_duplicates
Statssheet_quantile, sheet_corr, sheet_cov, sheet_regress, sheet_forecast, sheet_ttest, sheet_anova, sheet_chisq, sheet_moments, sheet_means, sheet_mad, sheet_entropy, sheet_gini, sheet_histogram, sheet_outliers
Financesheet_npv, sheet_irr, sheet_cagr, sheet_drawdown, sheet_amortize, sheet_returns, sheet_bollinger, sheet_sumproduct, sheet_autocorr
Reshapesheet_pivot, sheet_unpivot, sheet_join, sheet_union, sheet_merge, sheet_hstack, sheet_cross, sheet_transpose, sheet_explode, sheet_split_column, sheet_concat_columns, sheet_aggregate, sheet_group_concat
Filter / selectsheet_filter, sheet_where, sheet_grep, sheet_select, sheet_drop, sheet_sort, sheet_multisort, sheet_top, sheet_head, sheet_dedupe, sheet_sample, sheet_train_test_split
Clean / transformsheet_cast, sheet_clean, sheet_strip, sheet_fillna, sheet_impute, sheet_interpolate, sheet_dropna, sheet_recode, sheet_map, sheet_normalize, sheet_standardize, sheet_clamp, sheet_winsorize, sheet_round
Time-seriessheet_movavg, sheet_rolling, sheet_ewm, sheet_cumsum, sheet_pct_change, sheet_delta, sheet_shift, sheet_resample, sheet_date_part, sheet_date_diff, sheet_date_add, sheet_networkdays, sheet_weekday
Cells / structuresheet_get_cell, sheet_set_cell, sheet_get_range, sheet_set_range, sheet_insert_rows, sheet_delete_rows, sheet_freeze, sheet_autofilter, sheet_merge_cells, sheet_autosize, sheet_protect, sheet_add, sheet_copy, sheet_remove, sheet_reorder
Excel-stylesheet_lookup (VLOOKUP), sheet_countif, sheet_sumif, sheet_sumifs, sheet_rank, sheet_subtotal, sheet_totals, sheet_pct, sheet_calc, sheet_row_stats
Exportsheet_to_csv, sheet_to_json, sheet_to_ndjson, sheet_to_xml, sheet_to_sql, sheet_to_md, sheet_to_html, sheet_to_latex, sheet_to_text, sheet_to_pdf, sheet_to_doc, sheet_to_slides

Rich formatting

Spreadsheet cells and document runs accept styling, not just scalars. A cell can be a scalar or a rich object; a docx block can carry styled runs.

Office::sheet_write("r.xlsx", [{ name => "S", rows => [
    [{ v => "Header", bold => 1, color => "#FF0000", bg => "#FFFF00", align => "center" }],
    [{ v => 42, num_format => "0.00", italic => 1 }],
    [{ f => "=A2*2" }],                       # formula cell
] }])
# cell keys: v|value, f|formula, bold, italic, underline, font, size,
#            color, bg, align (left/center/right), num_format, border

Office::doc_write("r.docx", [
    { kind => "para", align => "center", runs => [
        { text => "Bold ", bold => 1, color => "#0000FF", size => 18 },
        { text => "and italic", italic => 1 },
    ] },
])

Sheet-level structure (xlsx) also supports merges, frozen panes, autofilter, worksheet tables, conditional formatting, data-validation dropdowns, sparklines, notes, embedded images, outline grouping, page setup, defined names, and workbook properties. ODF (ods/odt) and PDF are written unstyled — the lo_odf/lo_core serializers do not expose per-run styling (a documented crate limitation, not faked).

Documents (doc_*) & presentations (slides_*)

doc_read / doc_paragraphs / doc_linesparagraph + line text (docx/odt; lines also pdf)
doc_blocks / doc_outline / doc_tables / doc_linksordered structural read, heading outline, table grids, hyperlinks
doc_stats / doc_wordfreq / doc_readabilityWord-style counts, word-frequency ranking, Flesch / Flesch–Kincaid
doc_sentences / doc_summary / doc_extract / doc_diffsentence split, extractive summary, regex extraction, LCS paragraph diff
doc_comments / doc_footnotes / doc_add_tocreview comments, footnotes/endnotes, generated Table of Contents
doc_merge / doc_append / doc_splitconcatenate, append blocks, split at headings
doc_to_md / _html / _text / _pdf / _csv / _sheet / _slidesconvert a docx/odt out to any of these (and md/html/pdf back in via md_to_doc / html_to_doc)
slides_read / slides_count / slides_names / slides_outlineread text + notes, count, titles, outline
slides_add_image / slides_add_text / slides_set_notesembed a picture / text box / speaker notes onto a pptx slide
slides_insert / _delete / _reorder / _reverse / _merge / _appendedit a deck in place
slides_to_doc / _pdf / _md / _html / _text / _sheetconvert a deck out; md_to_slides builds one from a Markdown outline

PDF (pdf_*)

pdf_build / pdf_blank / images_to_pdf / sheet_to_pdfgenerate from a content model, blank pages, image-per-page, bordered table
pdf_merge / _split / _extract / _delete / _reorder / _reversepage-level surgery (1-based; pdf_extract takes "1-3,5,8-10" range specs)
pdf_burst / _chunk / _split_ranges / _split_bookmarkssplit into many files (per page, fixed chunks, ranges, chapter bookmarks)
pdf_rotate / _crop / _compress / _remove_blankrotate 90° multiples, set crop box, prune+deflate, drop empty pages
pdf_encrypt / _decryptAES-128 or RC4 standard security handler with per-op permission grants
pdf_form_fields / _fill_formlist + fill AcroForm fields (checkbox takes a bool; sets /NeedAppearances)
pdf_outline / _set_outlineread + write the bookmark navigation tree (nested via children)
pdf_add_link / _links / _highlight / _annotations / _remove_annotationsURI links, highlights, annotation listing + stripping
pdf_attach / _attachmentsembed (EmbeddedFiles name tree) + list/extract attachments
pdf_watermark / _stamp_image / _page_numbers / _add_text / _draw_rect / _draw_lineoverlays + stamps on existing pages
pdf_info / _page_sizes / _stats / _searchgeometry + metadata, per-page sizes, word/char stats, full-text search
pdf_to_doc / _to_slides / _to_sheet / _to_textconvert a PDF's text out (page breaks preserved)
# inspect a form, then fill it (checkbox takes a bool)
val $f = Office::pdf_form_fields("application.pdf")
Office::pdf_fill_form("application.pdf", {
    "applicant_name" => "Jane Doe",
    "agree_terms"    => \1,
}, output => "application-filled.pdf")

# password-protect with AES-128, allow printing only, then strip it back off
Office::pdf_encrypt("report.pdf", "report-locked.pdf",
    owner_password => "admin", user_password => "view",
    aes => \1, permissions => ["print"])
Office::pdf_decrypt("report-locked.pdf", "report-open.pdf", password => "admin")

Images (img_*) — handle-based, like a PIL Image

Image ops return a numeric handle: open once, transform many times, then img_save / img_close. Geometry-changing ops return a new {handle, width, height, mode}; in-place filters mutate the handle.

I/Oimg_open, img_new, img_save, img_info, img_convert, img_close, img_to_base64, img_from_base64, img_data_uri, img_resize_file
Geometryimg_resize, img_thumbnail, img_scale, img_fit, img_crop, img_crop_aspect, img_rotate, img_flip, img_transpose, img_transverse, img_canvas, img_trim, img_warp
Composeimg_paste, img_blend, img_blend_mode, img_composite, img_montage, img_concat, img_border, img_watermark, img_drop_shadow, img_caption
Drawimg_draw_rect, img_draw_rounded_rect, img_draw_line, img_draw_circle, img_draw_ellipse, img_draw_arc, img_draw_polygon, img_draw_polyline, img_draw_text, img_draw_text_multiline, img_flood_fill
Filtersimg_blur, img_box_blur, img_median, img_sharpen, img_edges, img_emboss, img_convolve, img_brighten, img_contrast, img_gamma, img_invert, img_grayscale, img_sepia, img_tint, img_posterize, img_threshold, img_solarize, img_autocontrast, img_equalize, img_pixelate, img_vignette, img_noise, img_dilate, img_erode
Color scienceimg_levels, img_curves, img_hsl, img_huerotate, img_temperature, img_channel_mixer, img_point, img_colorize, img_gradient, img_replace_color, img_swap_channels, img_dither, img_quantize
Distortionsimg_swirl, img_wave, img_fisheye, img_kaleidoscope, img_seam_carve
Analysisimg_histogram, img_extrema, img_entropy, img_count_colors, img_dominant_colors, img_average_color, img_brightness, img_bbox, img_compare, img_phash, img_get_pixel
Animation / batchimg_open_frames, img_save_animated, img_spritesheet, img_split, img_merge, img_reduce, img_favicon, contact_sheet
val $im = Office::img_open("photo.jpg")
Office::img_resize($im->{handle}, 800, 600, filter => "lanczos3")
Office::img_grayscale($im->{handle})
Office::img_save($im->{handle}, "out.png")   # transcode by extension
Office::img_close($im->{handle})

Charting (chart_*)

Render charts natively (imageproc + the vendored font — no plotters, no system fonts). 60+ types render identically in raster and SVG.

Office::chart_render($type, $series, %opts)→ raster image handle (then img_save to any format)
Office::chart_svg($type, $series, %opts)→ vector SVG markup (or write to path =>)
Office::chart_save($type, $path, %opts)write straight to a file, format by extension: .svg, .pdf, or any raster
Office::chart_from_sheet($path, $output, %opts)read a spreadsheet's columns and render in one call
Office::chart_grid($charts, %opts)tile many specs into one dashboard image / pdf

Types include bar/column/stacked, line/area/step/combo, scatter/bubble, pie/donut, histogram, radar, sankey, waterfall, ohlc/candlestick, boxplot, funnel, gauge, heatmap, treemap, sunburst, calendar, plus a ggplot2-style set (density, violin, ecdf, qq, ribbon, jitter, rug, beeswarm, contour, ridgeline, smooth/loess, bin2d, pairs, dendrogram).

for val $spec ([["bar","png"], ["line","jpg"], ["pie","webp"]]) {
    val ($type, $fmt) = @$spec
    val $c = Office::chart_render($type, [{ name => "Sales", data => \@sales }],
                                  title => "Q sales", categories => \@cats)
    Office::img_save($c->{handle}, "out-$type.$fmt")
    Office::img_close($c->{handle})
}

Barcodes & QR codes (barcode_*)

Both produce an image handle, so the result composes with the entire image surface — save, paste onto a label canvas, or embed in a PDF/docx. Generated natively (qrcode + barcoders).

barcode_qr(%opts)QR; data, ec (L/M/Q/H), scale, quiet, fg/bg
barcode_1d(%opts)1D; symbology code128/39/93/11, codabar, ean13/8, upca, itf, std2of5
barcode_save($data, $output, %opts)generate straight to an image file
barcode_sheet($path, $column, $dir, %opts)batch one barcode/QR per column value into a directory

Metadata, media, templates, text & converters

meta_read / meta_write / meta_stripread/set/blank document properties losslessly (xlsx/docx/pptx, ods/odt/odp, pdf)
extract_images($path, %opts)pull every picture out as a live image handle (OOXML/ODF/PDF)
replace_text / mail_merge / text_templatefill {{placeholder}} templates (run-coalescing for OOXML); one document per record
text_* (20)plain-text toolkit: text_grep, text_sort, text_uniq, text_sed, text_cut, text_wrap, text_tr, text_paste, text_comm, text_join, text_shuf, text_base64, text_hash, text_redact, text_tac, text_head, text_stats, …
csv_to_sheet / csv_to_xlsx / xlsx_to_csvCSV ↔ spreadsheet (RFC-4180 quoting)
md_to_sheet / html_to_sheet / json_to_sheet / ndjson_to_sheet / xml_to_sheetimport structured formats into a sheet
color_info / color_contrastfull color breakdown (hex/rgb/hsl/luminance) + WCAG contrast ratio

Cell-reference helpers (no workbook)

Pure A1 / R1C1 / range math — no file is opened, so these run standalone.

parse_a1 / parse_a1_abs / a1_of / a1_abs_ofA1 ↔ 0-based row/col, with $-absolute support
a1_to_r1c1 / r1c1_to_a1Excel R1C1 notation (absolute or anchor-relative)
offset_a1 / cell_deltashift an A1 ref / the offset between two cells
col_to_letter / letter_to_colcolumn letters ↔ 0-based index
parse_range / range_of / expand_range / bounding_rangerange parsing, building, enumeration, bounding box
range_intersection / range_union / range_contains / range_offset / range_to_absolute / range_to_relativerange set-ops and transforms

Troubleshooting

doc_read drops a tableBy design — doc_read returns paragraph text. Use doc_tables for table grids or doc_blocks for ordered structure.
ODF / PDF output is unstyledThe lo_odf / lo_core serializers do not expose per-run styling. Rich formatting applies to xlsx + docx only.
Formulas read but don't evaluatesheet_read(…, formulas => 1) returns formula strings; values are whatever the writing app computed. There is no formula evaluator (Roadmap item).
No docx→pdf "laid out like Word"Generic render-conversion needs a layout engine, which the no-external-binary rule excludes. doc_to_pdf renders from the content model, not a Word layout.
Leaked image handlesEvery img_open / img_new / geometry op returns a handle into an in-process table; call img_close when done.
extract_images skipped a picture$r->{skipped} counts recognized-but-undecodable media (e.g. JPEG2000).

No external binaries

Each format maps to a vendored Rust crate, statically linked: calamine (xlsx/xls read), rust_xlsxwriter (xlsx write), lo_odf (ods/odt/odp write), docx-rs (docx write), zip+quick-xml (OOXML/ODF read + pptx write), and lo_core (PDF read+write, no font files). There is deliberately no soffice call — so there is no generic render-conversion (docx→pdf laid out like Word), which needs a layout engine. You get structured read, structured write, and PDF generation from a content model.

Sibling packages

Part of the stryke package family. Browse the others via the MenkeTechnologiesMeta umbrella repo: