4.6 KiB
4.6 KiB
| name | description |
|---|---|
| html-file-formats | Load, inspect and save files inside a single-file HTML app (browser, no server): images (png/jpg/webp), svg, stl, json, yaml, csv, xls/xlsx, docx, pdf and zip - which pinned CDN library to use, how to read the file the user picks, extract text/tables/pixels/geometry from it, and generate a download of your own data in that format. Use whenever a web app must open or export one of these formats; for .doc or other formats without a browser parser it says what to do instead. |
File formats in a browser app
Everything runs in the page: the user picks a file (<input type=file>), you
parse it in JS, and you save by generating bytes and triggering a download.
Nothing is written to disk by the app itself - "save" always means download.
Verified library versions and calls: formats.md. Copy the
import map / script tags from there; pin versions, never @latest.
| Format | Load (file -> data) | Save (data -> file) | Library | Notes |
|---|---|---|---|---|
| png / jpg / webp | Image + <canvas> -> pixels, size |
canvas.toBlob(cb, 'image/png') |
none | jpg has no alpha; toBlob('image/jpeg', 0.9) |
| svg | DOMParser -> DOM (paths, sizes); rasterize via Image |
serialize DOM / build string | none; three.js SVGLoader for extrusion |
keep viewBox; CSS inside <style> |
| stl | STLLoader.parse(ArrayBuffer) -> geometry |
STLExporter |
three.js addons | details: threejs-csg skill, loaders.md |
| json | JSON.parse(text) |
JSON.stringify(data, null, 2) |
none | full recipe: save-load-json skill |
| yaml | yaml.load(text) |
yaml.dump(obj) |
js-yaml 5.5.0 (ESM) | load is safe (no code execution) |
| csv / tsv | Papa.parse(text, {header, dynamicTyping}) |
Papa.unparse(rows) |
papaparse 5.7.0 | delimiter auto-detected; encoding for Latin-1 |
| xlsx / xls | XLSX.read(ArrayBuffer) -> sheets -> json/csv |
XLSX.write(wb, {bookType}) |
xlsx 0.18.5 (SheetJS) | reads legacy .xls too; formulas come as values + f |
| docx | mammoth.convertToHtml({arrayBuffer}) / extractRawText |
docx 9.13.0 Packer.toBlob |
mammoth 1.13.0, docx 9.13.0 | mammoth: text, headings, tables, images; no layout |
| doc (legacy) | no browser parser | - | - | convert first: soffice --headless --convert-to docx x.doc (run_command), or ask for .docx |
pdf.js getTextContent() per page, render page to canvas |
pdf-lib (precise, merge/modify) or jsPDF (quick text/images) | pdfjs-dist 6.4.299, pdf-lib 1.17.1, jspdf 4.2.1 | scanned PDFs have no text layer: render + OCR (tesseract.js) | |
| zip | JSZip.loadAsync(ArrayBuffer) |
zip.generateAsync({type:'blob'}) |
jszip 3.10.2 | bundle a project: json + assets |
Workflow
- Pick the row, copy its library line from formats.md into the page (import
map entry or
<script>tag) and the load/save snippet. - Read the file as the right type: text for json/yaml/csv/svg,
ArrayBuffer for everything binary (images, stl, xlsx, docx, pdf, zip).
Helpers
pickFile/downloadare in the single-file-webapp skill. - Parse into plain data first (rows, records, geometry, text per page), THEN build app objects from it through the app's normal constructor. Never keep the library's document object as app state.
- Save = build from app state -> library ->
Blob->download(name, blob). The button handler calls oneexportX()function that RETURNS the Blob, so the browser-test skill can test it (h.download('#btn')). - Test with real files: put small fixtures in
fixtures/(a 2-row csv, a 3-cell xlsx, a one-page pdf), drive the real buttons withh.upload, assert on the parsed data; then round-trip your own export through your own importer.
Pitfalls
FileReader.readAsTextguesses UTF-8; pass'windows-1252'for old CSV/TXT exports from Excel, or detect the BOM.- pdf.js transfers the ArrayBuffer you give it (it becomes empty). Pass
new Uint8Array(bytes)orbytes.slice()if you need the bytes afterwards (e.g. to merge with pdf-lib). - pdf.js needs its worker: set
GlobalWorkerOptions.workerSrcto the CDN worker URL of the SAME version, or every call fails with a worker error. - SheetJS dates:
cellDates: trueon read, else dates arrive as serial numbers. - Big files: parse in a
Workeror at leastawaitin chunks (Papa.parsehasstep/chunkcallbacks); the UI freezes above a few MB otherwise. canvas.toBlobon an image from another origin throws (tainted canvas): images must come from the user's file or the same origin.- Binary formats never go through
readAsText; a docx/xlsx/pdf opened as text is garbage and the library will say "corrupt file".