Skip to content

Releases

v0.8.1

v0.8.1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 12 Oct 11:09
5d5b3e4

v0.8.1: simpler font configuration and release workflow

This unstable maintenance release preserves v0.8.0 public APIs, supported
profiles and PDF output. No migration or additional font options are needed.

cargo install --locked caj2pdf-cli --version 0.8.1
npm install caj2pdf-rust@0.8.1
caj2pdf paper.caj -o paper.pdf
  • One authored resource manifest produces the Rust and JavaScript constants;
    CI rejects drift (#551).
  • The CLI reuses core font configuration. CLI/WASM move maps and identities
    into conversion instead of cloning them; JavaScript resolves optional role
    indices once. WASM Session keeps its Send + Sync guarantees (#552).
  • Default CLI/Node/browser usage comes first, advanced font flags are grouped,
    and current publication instructions are separated from linked bootstrap
    history. Coverage status now describes the unchanged 90% floor (#553).

Validation and limits

The retained Wine-reference cohort contains 13 documents / 77 pages. Default
CLI, Node and Chromium PDFs remain byte-identical to v0.8.0. Existing custom,
absent and shared font sources, TTC faces, malformed maps, cancellation and
actual npm package tests remain covered. Seven ignored optional Rust corpus
tests are excluded from compatibility evidence. No fresh Wine pixel comparison
or additional supported profile is claimed.

Font bytes, geometry/glyph tables and embedding choices are unchanged. Native
binaries include the font pack; Node reads the packaged resource and browsers
cache it in OPFS on first use. See bundled fonts and
format support. C8/HN-B
outlines and the recorded raster/unsupported-profile limitations remain.

The tagged workflow requires the complete native/container inventories,
quality and actual-package checks, and verified file/container attestations
before GitHub publication. It then publishes core/CLI to crates.io and the
same tested tarball to npm using OIDC. The tagged run and its SHA256SUMS
identify release bytes; Windows and macOS binaries remain unsigned. See
build provenance for verification commands.

v0.8.0

v0.8.0 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 12 Oct 09:38
8da1486

v0.8.0: automatic native-text fonts

This unstable minor release changes default native-text conversion behavior
since v0.7.0.

CLI and JavaScript native C8/HN-B conversions now use a built-in CAJViewer
7.3 Wine reference preset. Fonts, mode selection, glyph aliases, symbol and
ornament identities, and full-font embedding require no user configuration.

This intentionally changes the default PDF and distribution sizes. Native
binaries contain the 58.6 MiB uncompressed resource pack and work offline.
npm contains the same pack; Node reads it locally, while the browser downloads
it into a verified OPFS cache on first native-text conversion. The core and
raw WASM do not embed font programs. See bundled fonts.

Upgrade and breaking changes

cargo install --locked caj2pdf-cli --version 0.8.0
npm install caj2pdf-rust@0.8.0
caj2pdf paper.caj -o paper.pdf
Surface Previous behavior New behavior and migration
CLI Discover installed fonts unless custom fonts are supplied. Use the bundled mode-specific preset. No flags are needed. Use --no-bundled-fonts to restore installed-font discovery; add --no-system-fonts to disable both.
Node/browser Callers supply native-text fonts and measured parameters. convert(module, source, sink) selects the bundled preset. Explicit custom fonts retain their previous behavior; hnc8: { fonts: false } disables automatic fonts.
Output PDF Default text rendering depends on caller/system fonts. Default native-text PDFs use full original programs and measured mappings. Regenerate PDF hash/size expectations; full-font embedding increases PDF size.
Source builds No bundled resource download is needed. Install curl or set CAJ2PDF_FONT_PACK to the verified local pack for an offline build.
Browser deployment Caller-provided fonts determine storage needs. Serve the packaged font asset and use a secure context with OPFS and Web Locks. The first native-text conversion populates a verified cache; later conversions reuse it.

Use matching JavaScript and WASM builds. Rust core and raw WASM remain
font-data-free; Rust callers can opt into bundled_fonts::configure with
ranged sources for the pinned pack. Existing explicit-font callers need no
new configuration. See bundled fonts for deployment
and override examples.

Validation and limits

No additional document profile is admitted. C8/HN-B outlines remain omitted;
existing codec, image-raster and unsupported-profile limitations remain.
The immutable font-data fonts-v1 release is a build input, separate from
the converter release. No external document corpus is distributed.

Validation: CLI, Node and Chromium each reproduce all 13 retained documents /
77 pages from the explicit Wine-reference configuration byte-for-byte. See
the receipt. This preserves
the prior Wine comparison and its remaining raster differences; it does not
claim universal pixel equivalence. The implementation checkpoint passes
1,470 Rust tests and 194 JavaScript tests, including real Chromium. Seven
ignored optional Rust corpus tests are excluded from compatibility passes.
The actual npm tarball and an extracted native archive were tested with
automatic fonts, and the Rust registry packages passed isolated build checks.

The tag workflow gates publication on the complete native/container inventory,
quality and packaged-artifact checks, and verification of artifact attestations.
Its run and uploaded SHA256SUMS are authoritative for released bytes.
It publishes core/CLI to crates.io and the tested JavaScript tarball to npm
after the GitHub release succeeds. Windows and macOS binaries are unsigned;
see build provenance for verification commands.

v0.7.0

v0.7.0 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 12 Oct 07:13
e8343a6

v0.7.0 — original fonts, Wine rendering and measured format recovery

This unstable minor release includes breaking API and PDF-output changes since
v0.6.1. It includes the classic-Worker bundling fix documented for
v0.6.2, together with all intervening changes on main.

Highlights

  • Explicit original TrueType programs, CJK style roles, symbol/ornament maps
    and glyph aliases bring the measured C8/HN-B cohort into normal-reading
    agreement with Wine CAJViewer 7.3.151 Simple. Font resources remain supplied
    by the caller; the converter does not bundle or download them.
  • Correct page geometry, Latin origins, type-1 JPEG orientation, rule contrast,
    native link appearances and continuous ornament bands. Semantic text remains
    separate from the selected glyph. Full font programs increase the measured
    PDFs to approximately 21–32 MB; subsetting remains the default.
  • Add explicit-response conversion for the measured TTKN PDF profile, more
    bounded CAJ/KDH recovery and PDF footer/outline/object-stream profiles, and
    additional NJU native C8 records. Unmeasured profiles remain refused.
  • Fix Worker cancellation and classic-Worker bundling. A conversion failure
    combined with failed spool cleanup now exposes both errors.

Upgrade overview

cargo install --locked caj2pdf-cli --version 0.7.0
cargo add caj2pdf-core@0.7.0
npm install caj2pdf-rust@0.7.0

Use matching JavaScript and WASM builds. Users coming from v0.5.0 must also
apply the v0.6.0 migration.

Surface Required migration from v0.6.1
Rust font structs Add the optional style roles, maps, identity fields and embedding mode described below; prefer ..Fonts::default() for owned fonts.
Native/CLI/Node/browser PDFs Reconvert and regenerate page-box, coordinate and PDF-hash expectations. Font maps must contain the required glyphs.
Native C8 notes Handle unsupported-format errors for unknown required note appearances; supported links now appear in output.
CLI TEB inspection Match unsupported_reason: "not-implemented" instead of "drm-encrypted".
JavaScript spooling When conversion and cleanup both fail, inspect AggregateError.cause for the original failure and errors[1] for cleanup.

The detailed sections below give previous/new behavior and migration examples.

Validation and remaining limits

The final Wine study covers 13 unchanged documents / 77 pages, reviewed
at reading size, with 113,418 semantic characters retained and 133 link
annotations on 11 pages
. Original controls include independent repeats,
negative controls and multiple zooms. Final CLI, Node and real Chromium outputs
agree byte-for-byte for 16 actual/control documents per runtime; writes
are at most 65,536 bytes. See the final band study
and its linked font, geometry, rule and link reports for reproducible receipts.

The implementation checkpoint passed 1,466 Rust tests and 192 JavaScript
tests
. Seven ignored optional Rust corpus tests are excluded from successful
compatibility evidence. Package/version preparation reruns locked native/WASM
builds and the actual npm tarball's Node/Chromium tests. The tag workflow gates
publication on quality checks, every required native/container target and
verification of artifact attestations. Its run and uploaded SHA256SUMS are
authoritative for the released artifacts.

The format-specific measurements below are attributed historical checkpoints,
not a new full-corpus run for this version. General patterned-ornament cadence,
small image-edge/resampling differences and antialiasing remain. Link marks
approximate a device-fixed Wine pattern; printing and navigation are untested.
No universal Wine/native-Windows pixel equivalence is claimed. C8/HN-B outlines,
other TTKN profiles, TEB conversion and missing-source-data cases retain their
documented limits. External documents, fonts and screenshots are not included.

Windows and macOS binaries are unsigned. GitHub assets include native archives,
WASM/npm, the OCI archive, checksums and provenance bundles. The existing OIDC
workflow publishes caj2pdf-core, caj2pdf-cli and caj2pdf-rust only after the
GitHub release succeeds; the Rust WASM crate remains unpublished. See
build provenance for consumer verification.

Additional features and fixes

  • TTKN PDFs (#504, #505, #506): Rust adds TtknResponse and
    convert_with_ttkn_response; CLI adds --ttkn-response-file FILE;
    Node/browser add { ttknResponse: response }. The matching 32-character
    case-sensitive hexadecimal ASCII response is caller-supplied. Conversion
    contacts no authentication endpoint. Existing convert and options remain
    compatible. The measured original's 180 pages, 234 decrypted streams and
    97 outlines match independent recovery across native/Node/Chromium; this is
    not all-page vendor-viewer fidelity. See profile and bounds.
  • PDF profiles (#494–#496, #507, #510, #511): accept the measured framed
    WebFastLoad metadata, complete block padding, unused object-zero sentinel,
    package XML suffix and bounded acyclic object-stream collection links.
    Existing graph, ambiguity and payload-preservation checks remain in force.
    See input bounds and conformance.
  • NJU C8 records (#513, #514, #516): independently controlled title styles,
    glyph flags, state records and single-segment geometry admit three originals
    with 17 pages. All 29,986 glyphs and 27 vectors were checked; native, Node
    and Chromium outputs agree. See provenance.
  • Classic Workers (#433, #517): remove top-level await from the Worker
    module graph so default Vite/Rolldown IIFE production builds succeed.
  • Dependencies: TTKN adds the documented MIT-compatible RustCrypto and
    base64 dependencies; signal-hook updates to 0.4.5. There is no dependency
    update in the release-version commit itself. Source/license audits remain
    required and no vendor/private HN/JBIG implementation is migrated.

Detailed changes and migration

Breaking CLI inspection value: TEB support reason (#469)

For TEB, inspect --json now reports "unsupported_reason":"not-implemented"
in place of "drm-encrypted". Update callers matching drm-encrypted to
accept not-implemented; format: "TEB", conversion_supported: false and
unknown page/outline metadata are unchanged. CLI text and Node/browser errors
now say conversion is unsupported. Recognizing a TEB prefix does not prove
encryption, corruption or impossibility of recovery. JavaScript retains
UnsupportedFormatError, code: "UNSUPPORTED_FORMAT" and format: "teb";
callers should match these fields instead of diagnostic prose. No supported
conversion/PDF output, I/O limits, dependency or core/WASM API changes.

Breaking Rust API: native symbol glyph maps (#518)

caj2pdf_core::Fonts gains symbol_glyphs: Vec<NativeSymbolGlyph> and now
implements Default; hnc8::C8FontSources gains
symbol_glyphs: &[NativeSymbolGlyph]. Each entry selects the symbols
font character-map entry drawn for one raw HN-B mode-0 symbol code
(hnc8::is_mode_zero_symbol) while extracted text keeps the decoded
character. Codes that decode alike can draw distinct glyphs, and one glyph
can carry different text. Rust callers building these structs with literals
add symbol_glyphs: Vec::new() / symbol_glyphs: &[], or use
..Fonts::default(). An empty map leaves output byte-identical.

A non-empty map must name distinct symbol codes, needs a symbols role
whose font maps every glyph, and applies only to HN-B mode-0 native text.
Native conversion refuses anything else before a PDF is finished, with no
fallback to another glyph or font. Like the fonts themselves, the map is
unread for documents routed to image composition. A symbols source shared
with other roles is embedded as one mapped font for all of them. The core
ships no mappings. Font identity binding and measured source-resource verification are included
in this release, as described below and in the provenance record. No fonts
are bundled, fetched or inferred.

Symbol font identity binding (#518)

A map can be bound to the font it was measured on. Rust Fonts::symbol_font
and C8FontSources::symbol_font, CLI --symbol-font-identity NAME:CHECKSUM,
JavaScript symbolFontIdentity and raw WASM caj2pdf_hnb_set_symbol_font
all take the font's PostScript name and head checkSumAdjustment. A
different symbols font is refused before output is finished, and an
identity without a map is refused. The check uses retained metadata, so no
full-font hash is computed. This guards against using the wrong font by
mistake, not against deliberate tampering: a tool that edits outlines but
leaves the checksum field unchanged would still pass. Rust struct literals
of C8FontSources, and Fonts literals without ..Fonts::default(), add
symbol_font: None.

CLI and JavaScript symbol glyph options (#518)

The CLI accepts repeatable --symbol-glyph CODE=CHAR (four hex digits, then
one BMP character or U+XXXX) with --font-symbols or --fonts DIR.
Node and browser accept hnc8.fonts.symbolGlyphs, an iterable of
{ code, glyph } that requires symbols. The raw WASM ABI adds
`caj2pdf_hnb_add_symbol_glyph(code, glyp...

Read more

Font data v1

Font data v1 Pre-release
Pre-release

Choose a tag to compare

@rwv rwv released this 12 Oct 08:06
e8343a6

Immutable font-data input for automatic native C8/HN-B conversion, tracked in #547.

caj2pdf-fonts-v1.bin concatenates ten original font files without changing their bytes. manifest.json records per-file offsets, sizes and SHA-256 identities; FONT-NOTICES.txt preserves embedded attribution. It includes the nine measured CAJViewer 7.3.151 Simple resource fonts and the measured SimSun collection. No document samples or executable converter code are included.

Pack size: 61,493,200 bytes. SHA-256: 8d828782065b3a405736cb51e47a747d0848a61ca47958550e26915de39d68c0.

This is a versioned data release, not a new converter version. Consumers pin and verify its bytes. Published assets must not be replaced.

v0.6.1

v0.6.1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 08 Oct 08:35
6349d66

v0.6.1 — measured CAJ recovery and npm publication

Measured CAJ tiling-pattern matrices (#414)

  • Two measured CAJ originals (264 pages) now convert by making the observed
    CAJViewer/Poppler identity fallback explicit for four malformed Pattern
    matrices. All pattern streams are retained. Valid matrices and other
    malformed profiles keep their existing behavior.
  • Recovery bounds the header to 512 bytes, proves the exact dictionary and
    stream boundary, and preserves source checks and sequential ranged output.
    Native, CLI and JavaScript APIs and dependencies are unchanged.
  • MuPDF interprets the malformed source differently; this is a measured source
    viewer recovery, not general scientific-notation support. See the
    conformance scope.

Upgrade and publication

There are no new public API or dependency changes since v0.6.0. npm users
upgrading from v0.5.0 must apply the v0.6.0 migration guide:
handle the new CAA format and nullable JavaScript page counts. Use matching
JavaScript and WASM versions.

v0.6.0 was published to GitHub and crates.io through the release workflow,
but npm interpreted its tarball path as a GitHub shorthand and the npm upload
failed before authentication. This release adds the explicit ./ local path
and uses the normal tagged OIDC pipeline for all three packages. The existing
v0.6.0 tag and assets are unchanged; no npm v0.6.0 is published by this release.
The Rust WASM crate remains unpublished.

Validation scope

The conformance checkpoint
records prior validation of both unchanged originals across native, Node and
Chromium, all 264 pages and 207 bookmarks, plus the broader frozen-corpus
receipt. These are attributed historical measurements, not a new full corpus
run for this version bump. Optional external-corpus checks without inputs are
NOT_RUN. Remaining unsupported inputs and fidelity limits still apply.

The tag workflow requires native/WASM quality checks, the complete platform
matrix, Node/Chromium checks of the actual npm tarball and artifact attestation
verification before registry uploads. GitHub assets include native binaries,
WASM/npm, OCI, checksums and provenance bundles. Windows/macOS binaries remain
unsigned. See build provenance.

cargo install --locked caj2pdf-cli --version 0.6.1
cargo add caj2pdf-core@0.6.1
npm install caj2pdf-rust@0.6.1

v0.6.0

v0.6.0 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 08 Oct 07:45
f87de9d

v0.6.0 — CAA descriptor recognition and trusted registry publishing

This unstable release recognizes the independently measured CAA target-descriptor
profile across Rust, the CLI, Node.js and browsers. Inspection reports the format
with unknown counts. A descriptor contains no document pages: conversion returns
the typed unsupported error before writing PDF bytes and asks for the referenced
document. Target values are neither decoded nor fetched.

Breaking changes and migration

  • Rust InputFormat gains Caa. Add InputFormat::Caa to exhaustive matches;
    route it to a request for the referenced document rather than conversion.
    DocumentInfo.page_count remains Option<u32> and is None for CAA.

  • JavaScript Format gains "caa", and DocumentInfo.pageCount changes from
    number to number | null. Handle the new format and guard unknown counts:

    const info = await inspect(module, input);
    if (info.pageCount === null) {
      console.log("Page count is unknown");
    } else {
      console.log(`${info.pageCount} pages`);
    }
  • CLI inspect --json can report "format": "CAA", null counts and
    "unsupported_reason": "target-descriptor". Consumers must handle that
    format; converting a CAA descriptor exits with status 1.

  • Raw WASM adds format code 8, preserving codes 0–7. CAA inspection returns
    raw page count 0 and bookmark count -1; the JavaScript adapter maps unknown
    counts to null. Upgrade JavaScript and WASM together.

Existing document conversion behavior and PDF output are unchanged by CAA
recognition. The bounded probe reads at most 1,024 bytes; the complete measured
field profile is required. Partial or contradictory descriptors are rejected.
No new dependency or external document payload is included.

Format evidence and limits

The NH/CAA checkpoint
records 18 unique external CAA descriptors and an original .nh HN-A document
converted through CLI, Node and Chromium: 433 pages, 365 bookmarks and identical
PDFs. This is the recorded research receipt, not a new release corpus run or a
viewer pixel-parity claim. File extensions do not define input signatures.
Historical CAS remains an unverified sample gap; no CAS decoder is claimed.
Other v0.5.0 limits,
including unverified C8/HN-B outlines and substitute-font fidelity, still apply.
Optional external-corpus tests without inputs are NOT_RUN.

Publication and validation

This is the first release intended to publish caj2pdf-core, caj2pdf-cli and
npm caj2pdf-rust through GitHub OIDC after all release gates. The WASM Rust
crate remains unpublished. The npm upload uses the same tested tarball as the
GitHub asset and requests npm provenance; no long-lived registry token is stored
in CI. Successful publication is established by the tag workflow and registry
records, not by this intention.

The release workflow requires locked native/WASM quality checks, the complete
platform inventory, Node/Chromium tests of the actual npm package, and verified
artifact attestations before publishing. GitHub assets include native binaries,
JS/WASM, OCI, SHA256SUMS and Sigstore bundles. Windows/macOS binaries remain
unsigned. See build provenance for verification.

cargo install --locked caj2pdf-cli --version 0.6.0
cargo add caj2pdf-core@0.6.0
npm install caj2pdf-rust@0.6.0

v0.5.0

v0.5.0 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 08 Oct 06:51
aa11e81

v0.5.0 — synchronous core, Worker APIs and more document profiles

This unstable release replaces the asynchronous Rust core and scratch bitmap
stores with synchronous ranged reads, sequential writes and per-image,
per-dictionary or per-page allocations bounded by Limits. Browser and Node.js
conversion runs in a Worker. The CLI retains its conversion commands and adds
explicit damaged-CAJ conversion. Update native API consumers and JavaScript
call sites together with the matching WASM build.

Breaking changes and migration

This table describes the final v0.5.0 API. The changelog
records individual removals, error-message changes and intermediate refactors.

Surface / old usage v0.5.0 migration
Rust asynchronous source/decoder calls, SequentialSink and scratch workspaces Remove .await; provide RangedSource (or native::SeekableSource) and std::io::Write. Remove scratch resources. Keep inputs unchanged for the entire operation; HN/C8 payload SHA-256 rechecks are removed.
Separate format dispatch Call the root convert, inspect, inspect_pages, read_outline or index_pdf facade. ConversionOptions is borrowed and carries format/font policy. Prefer ..ConversionOptions::default() in literals.
Codec-specific budget structures Use one Limits; former per-codec budget parameters are removed. max_image_pixels and max_symbols cap decoded bitmaps and dictionaries; max_allocation_bytes caps individual retained buffers.
Codec-specific error enums Match Error.kind (ErrorKind), then use offset, context and reason. Removed error payloads are not available. HN/C8 I/O/cancellation now uses JS IO/CANCELLED.
Complete report literals or copying reports ConversionReport gains outline, application_info, images, omitted_pages and substituted_glyphs; use Default where appropriate. Reports containing omissions are no longer Copy; borrow or clone explicitly. DocumentInfo.page_count is Option<u32>.
JS instance/exports and {size, readAt} wrappers Pass the WebAssembly.Module from loadModule() and a browser File/Blob/OPFS handle, or a Node path/URL/descriptor/Blob. Remove blobSource, fileHandleSource and hnc8.scratch. Font sources use the same input types.
Custom raw WASM poll/resume hosts Replace caj2pdf_start/caj2pdf_io_* with synchronous caj2pdf_convert/caj2pdf_inspect and the five host imports in the ABI reference. Rust hosts use engine::Session/Host, not Engine/Request.
TrueTypeFont, whole-font embedding Use OpenTypeFont, supply a face index (0 for a single face), and call embed_font after the last draw before finish. Fonts are subsetted/compressed; CFF and collection faces are supported.
Caller-provided QM/MQ tables Remove CLI --qm-states/--mq-states and JS hnc8.qmStates/mqStates. Built-in standard codec states are used. Removed selected-image helpers are replaced by document conversion; see the changelog for low-level decoder removals.
CLI native-text input without font options Installed fonts are discovered automatically. Use --no-system-fonts for the old no-search behavior, or pass explicit font paths. JS never searches installed fonts.
Output byte identity and early size failures Font/content compression, font subsetting, top-first type-0 image matrices and the outline trailer /ID change PDF bytes. Output limits can fail during sequential writing; stage output if atomic publication is required. Do not compare old/new PDF hashes as a fidelity test.
// Before: convert(instance, blobSource(file), sink, { hnc8: { scratch } })
// v0.5.0: file is a browser File; sink is a supported sequential sink.
const module = await loadModule();
await convert(module, file, sink, { signal });

For prompt browser cancellation and sink backpressure use a cross-origin
isolated page (SharedArrayBuffer). Otherwise cancellation terminates the
Worker. Spooled inputs are now a Node path or OPFS handle. See the
JS examples and native architecture.

Conversion improvements and remaining limits

  • More measured CAJ/PDF/KDH profiles: bounded source-path metadata repair,
    absent optional link appearances, equivalent opacity resources, interrupted
    live prefixes, duplicate identical page boxes, PNG Up xrefs and Flate
    object-stream metadata. Unknown or contradictory profiles still fail.
  • More measured HN-A, C8 and HN-B profiles, including generic-only JBIG2,
    empty symbol content, uncompressed images, full-page JPEG region records,
    native article records and HN-B type-3 images after text.
  • --allow-damaged explicitly permits reported blank substitutions for eligible
    damaged CAJ pages. Exit 3 means partial output was committed. JS callers use
    allowDamaged: true and inspect omittedPages; default conversion stays strict.
  • Native text needs caller/installed fonts; no fonts are bundled. Substitute
    fonts are not original-font fidelity. A measured private-use HN-B character
    may use a reported visual substitute while preserving U+E6C7 in ActualText.
  • C8/HN-B bookmarks remain unverified and omitted with a warning (#303).
    Image pages receive no OCR. TEB remains unsupported. Corpus recovery and
    source-fidelity work (#406, #414, #415, #420) remains open.

Validation and artifacts

The release workflow reruns locked native/WASM quality gates, the complete
platform inventory, actual npm tarball tests on Node and Chromium, and
artifact provenance verification. Windows/macOS binaries remain unsigned.
GitHub assets include native CLI archives, JS/WASM, OCI and SHA256SUMS;
verify them using the provenance guide.

The registry packages are caj2pdf-core, caj2pdf-cli (binary caj2pdf) and
npm caj2pdf-rust. caj2pdf-wasm remains unpublished as a Rust crate.
Initial registry publication uses owner authentication; trusted publishers
are configured after bootstrap. A GitHub release alone is not proof that a
registry upload succeeded. Release policy documents
this transition and the required clean-install checks.

The conformance record separates corpus conversion,
runtime parity, glyph/image checks and selected source-render comparisons.
The 1,232 accepted originals at #408 passed native/Node/Chromium parity;
that is historical source evidence, not a fresh full-corpus run of this tag.
Optional external corpus tests for this release are NOT_RUN unless a separate
receipt records them. Filtered guest rendering tests are not compatibility
passes; their portable conversion checks and host smoke tests are separate.
The #346 source-size target remains unmet (37.9k vs 30k at its recorded
checkpoint); this release does not claim it is complete.

Detailed conversion checkpoints

The entries below preserve the recorded scope and timing of each pre-release
validation checkpoint; later checkpoints supersede earlier failure counts.

Unescaped CAJ source-path metadata (#419)

  • A measured 139-page CAJ original now converts after two malformed QITE
    source-path strings are preserved as hexadecimal strings; all 35 source
    bookmarks remain intact. All incoming
    references must be confined to retained Page metadata; rendering strings
    and unmeasured profiles remain strict.
  • The repair uses bounded reads, source rechecks and existing sequential
    reconstruction. No public API or dependency changes. See the
    scoped conformance evidence.

Absent optional CAJ link appearances (#417)

  • A measured 109-page CAJ original now converts after proving two optional
    Link appearance targets absent. Its live destinations, 574 source streams
    and 70 source bookmarks remain intact. Required references and unmeasured
    appearance/border profiles remain strict errors.
  • Existing bounded metadata reads, retained repair budgets and sequential
    reconstruction apply. No public API or product dependency changes. See the
    scoped source comparison.

Equivalent PDF opacity resources (#412)

  • Two KDH originals now convert after proving duplicate ExtGState references
    carry exactly equal direct CA/ca values. Unknown or conflicting resources
    remain errors; equal-looking rounded numbers are never used as proof.
  • All 14 pages and 151 streams match independent source decoding, and output
    bytes agree across native, Node.js and Chromium. See the
    checkpoint.
    No public API or dependency changes; target reads, metadata and incremental
    repairs remain bounded. Existing v0.4.0 artifacts are unchanged.

Interrupted live PDF prefixes (#410)

  • A measured seven-page KDH file now converts after bounded validation and
    whitespace replacement of inactive object prefixes. Only exact prefixes of
    xref-selected complete non-stream dictionaries/integers qualify; conflicts,
    stream objects and unrelated gap contents remain errors.
  • Native, Node.js and Chromium outputs match; all page renders, text, geometry
    and 22 raw streams match the independent source PDF. See the
    checkpoint.
    No public API or dependencies change; reads, parser metadata and retained
    patches remain bounded under existing limits.

Corpus runtime and order verification (#406)

  • All 1,232 accepted originals at PR #408 pass native/Node/Chromium byte parity
    and browser cleanup. All 26 formerly failing applicable order checks pass
    after correcting bitmap row conventions and adding native glyph checks.
  • The checkpoint
    records the scope and remaining source-fidelity/r...
Read more

v0.4.0

v0.4.0 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 05 Oct 15:32
56bf7cc

v0.4.0 — native C8/HN-B pages, font fallback and tolerant outlines

v0.4.0 is the first release with native-text C8 and HN-B pages. It also
reads more real documents without failing: damaged HN-A outlines are
repaired with warnings, C8/HN-B outlines are omitted with a warning, and a
missing font role falls back to the CJK or Latin font. v0.x is unstable;
breaking changes and their migration are listed below.

Conversion scope

  • HN-A: verified paired raw/compressed framing, per-page dimensions and marked
    image coordinates. The recorded corpus passes 19/19 HN-A inputs; this does
    not establish universal HN-A support or full viewer pixel parity. A
    malformed outline entry is skipped or clamped with a located warning
    instead of failing the document.
  • HN-B: admitted mode-0/mode-2 native text profiles and both verified index
    layouts. Three selected documents have complete 4/4/6-page runtime checks.
    Mode-2 leading images are supported; images after text and mode-0 images
    remain explicit errors.
  • C8: the admitted six-page profile and additional four/five-page profiles
    preserve native text, drawings and descriptor-ordered images. A trailing
    application-info package adds /CNKI_DOI and /CNKI_URL to the PDF
    /Info dictionary.
  • CAJ: bounded interrupted-object and stream recovery admits independently
    validated complete copies. Corrupt or ambiguous content still fails.
  • PDF: a %PDF- header that follows a newline, byte-order mark or junk line
    within the first 1,024 bytes is now recognized.
  • TEB: still rejected, now with a message naming it a DRM-encrypted container
    and "unsupported_reason":"drm-encrypted" in inspect --json.

C8/HN-B outline layouts are unverified. Those PDFs have no outline and the CLI
prints one warning; --no-bookmarks (JS includeBookmarks: false) gives the
same PDF silently, and JS reports outlineOmitted: true. Unknown outline
metadata is not a confirmed empty table of contents (#303).

Native text pages need a caller-supplied CJK and Latin TrueType font, for
example with --fonts DIR. The CLI reference
documents a tested free recipe, Droid Sans Fallback with DejaVu Sans, that
covers all six pinned C8/HN-B corpus inputs. Fonts are not bundled.
Substitute fonts do not reproduce the original typography. Image-only pages
receive no OCR. See current support
and Node/browser usage.

Other changes

  • caj2pdf inspect --pages prints a structure-only per-page report that is
    safe to share in a bug report. It contains no text, titles or pixels.
  • Conversion shows input progress on a terminal; -q/--quiet hides it.
  • Native HN/C8 scratch I/O uses positioned reads and writes, cutting system
    calls by almost two thirds on a 163-page HN-A input.
  • New CLI archives: i586 GNU, FreeBSD RISC-V64 GC and FreeBSD PowerPC64.

Breaking changes and migration

These changes affect direct Rust users and custom WASM hosts; the bundled JS
adapters handle resource routing. CLI scripts keep working; the visible CLI
differences are the C8/HN-B warning, the font fallback and the progress line
on a terminal.

Surface Change and migration
Rust toolchain Minimum Rust version becomes 1.88.0. Update older toolchains before building.
C8PageFonts literals alternate_latin becomes Option<usize>; wrap old values in Some. Add symbols, latin_state3, latin_state28, latin_state31; use None for absent roles. An absent role or unmapped glyph now falls back to the CJK or Latin font instead of failing.
Hnc8Reader::visit_bookmarks Returns an OutlineReport (declared, written, defects, unverified) instead of the declared count. Read report.written for the old count of emitted entries.
ComposeReport Gains outline and application_info. Construct it only through the converter, or add the fields with their defaults.
hnc8::Header literals Include native_origin and native_mode from parsed metadata rather than inventing values. HN-B native_origin and page_size can now be Some even for zero extents; their presence is not a renderability test.
TextCoordinates literals Include page_size. Admitted paired HN-A pages now use verified page dimensions instead of always inheriting the document header; output geometry can change.
NativeRecord::End value becomes Option<u16>; wrap explicit old values in Some and handle None as an absent payload.
Exhaustive native-record matches Handle added ImageReference, ExtendedControl and EncodedString events. Updated C8 drawing framing preserves following controls separately, changing visitor event counts.
Rust WASM engine Request::Read includes resource; route document and font reads to the registered source. Engine::set_c8_fonts adds the symbols argument (u32::MAX when absent) and accepts 0xffffffff as an absent alternate role. Existing raw WASM font-setter exports remain available.
C8/HN-B bookmarks Requesting bookmarks no longer fails; the outline is omitted with a warning. Callers that relied on the error should check outlineOmitted (JS) or OutlineReport::unverified (Rust).
Invalid HN-B input Unknown layout markers and invalid compact-index fields are rejected explicitly; do not rely on permissive parsing.
Damaged CAJ streams Flate Length recovery now validates the compressed stream. The recorded issue-20 input changes from a warning-producing old output to explicit rejection; no unchecked repair fallback is provided.

For exact resource registration and extended font roles, use the
I/O and ABI reference. The
changelog lists every change since v0.3.1.

Evidence and limits

The refreshed pre-tag Linux CI baseline ran all 56 fixed corpus inputs using
the v0.4.0 artifact from main 0153d22 (run 37251767647): 38 default
conversions, 13 unsupported inputs (seven TEB and six font-free HN-B/C8),
and five damaged CAJ failures. This font-free run is separate from explicit-font
HN-B/C8 validation. It does not yet verify the final tagged artifact identity. External documents, fonts,
captures and copied text stay outside Git and release assets.

Unicode evidence separates glyph transport from
independent source checks, extraction order, spacing and visual appearance.
Marker-font or adapter-hash agreement does not establish original-font pixel
parity. Missing optional evidence remains NOT_RUN.

Conformance evidence records representative native RSS,
WASM high-water capacity, bounded requests and scratch peaks. These are
measured cases, not a universal memory bound. Ranged input, sequential output,
forward-only spooling and failure cleanup remain the conversion model.

Artifacts

The release carries 53 native OS/CPU/ABI CLI archives, adding i586 GNU and
FreeBSD RISC-V64/PowerPC64 to v0.3.1's 50. Baselines are documented in
platforms. It also carries the tested JS tarball,
standalone WASM, the OCI container archive and SHA256SUMS. Nothing is
published to npm or crates.io (#293).

The release workflow builds every asset from the tagged commit, runs the full
platform matrix and attests the complete file set and the container digest.
The uploaded SHA256SUMS is authoritative. Verify downloads with the
build provenance guide. Windows and macOS binaries
are unsigned.

v0.3.1

v0.3.1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 01 Oct 04:27
088ecc8

v0.3.1 — verifiable release build provenance

This unstable maintenance release adds GitHub Actions artifact attestations.
There are no conversion, native API, CLI, browser/Node API or PDF behavior
changes from v0.3.0, and no new breaking changes.

Downloads and verification

The same 50 native OS/CPU/ABI archives, browser/Node JS package, standalone
WASM and ten-platform OCI archive are provided. Names use v0.3.1 for native
archives and caj2pdf-rust-0.3.1.tgz for the JS package. GHCR is
ghcr.io/rwv/caj2pdf-rust:v0.3.1; prefer its verified immutable digest.

RELEASE-PROVENANCE.sigstore.json authenticates all release payloads and
SHA256SUMS. CONTAINER-PROVENANCE.sigstore.json authenticates the registry
image digest, and is also published as an OCI attestation. These two signature
bundles are not listed in SHA256SUMS; verify their signatures with gh attestation verify. All other uploaded files are covered by the signed
checksum manifest. GitHub-generated source archives are outside this set.

See the verification guide for commands enforcing
repository, workflow, tag and commit identity. The publisher verifies every
file and the registry attestation before exposing the GitHub release. A
modified-file rejection check is mandatory. This is release-workflow provenance
from the aggregation job, not a claim of SLSA level 3 or platform code signing.
Earlier published releases are unchanged.

Existing limits

The v0.3.0 platform and format limits still apply, including
runtime/libc baselines, caller-supplied experimental HN/C8 tables and deferred
candidate architectures. Browser and Node are both supported. Native archives
include MIT dependency notices; macOS/Windows executables have no platform
code signatures. No npm, crates.io or Docker Hub publication is included.

Release CI reruns required native, WASM, JS, license, coverage and platform
checks. The private CAJSamples corpus is not shipped or run by public CI;
missing optional-corpus checks remain NOT_RUN, not compatibility passes.

v0.3.0

v0.3.0 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 30 Sep 15:01
cc156c8

v0.3.0 — wider native and container platforms

This unstable release expands delivery of the MIT Rust converter. Conversion
formats, bounded input/scratch, sequential output and PDF encoding retain the
v0.2.0 behavior. Browser and Node remain first-class WASM targets.

Downloads

Choose caj2pdf-v0.3.0-<target>.zip on Windows or .tar.gz elsewhere. The exact
required set contains 50 OS/CPU/ABI targets and is recorded in docs/platform-targets.json; docs/platforms.md explains
CPU/ABI, libc and OS baselines. Additions include LoongArch64 GNU/musl, ARMv5TE,
ARMv6, further ARMv7 variants, MIPS32/64 in both byte orders, PowerPC32/64,
SPARC64, i586 musl and additional musl variants, RISC-V32 GNU, NetBSD
x86_64/ARM64, OpenBSD x86_64/ARM64/RISC-V64, illumos x86_64 and Android x86/x86_64 command-line executables. Bootlin musl targets are dynamically linked and need
the matching runtime; other listed musl builds are static. A libc variant is not
counted as a distinct CPU architecture. Unverified candidates are documented
separately and do not appear among release assets.

  • caj2pdf-rust-0.3.0.tgz: browser and Node 22+ JS package, WASM and declarations.
    Install with npm install ./caj2pdf-rust-0.3.0.tgz.
  • caj2pdf_wasm.wasm: standalone module for the ranged-I/O JS adapters.
  • caj2pdf-container.oci.tar: the exact tested multiarch static CLI image.
  • CONTAINER-DIGEST.txt: digest of ghcr.io/rwv/caj2pdf-rust:v0.3.0.
  • SHA256SUMS: hashes for every published asset.

The Docker platforms are linux/amd64, linux/arm64, linux/arm/v5,
linux/arm/v6, linux/arm/v7, linux/386, linux/loong64, linux/riscv64,
linux/ppc64le and linux/ppc64. Images run as non-root on scratch and need
writable output and temporary storage. Large documents should use disk-backed
scratch instead of tmpfs. See docs/docker.md for usage. There is no npm,
crates.io or Docker Hub publication in this release.

Breaking change: browser cleanup errors

OPFS spool removal retries only NoModificationAllowedError, at most three
attempts with 10 ms and 50 ms waits. If removal permanently fails after a spool
error, the promise now rejects with AggregateError; its cause and first
errors entry preserve the original error, and the second entry is the removal
failure. Previously the removal failure was suppressed. Callers matching a
primary error code can migrate with:

const primary = error instanceof AggregateError ? error.cause : error;
if (primary?.code === "LIMIT_EXCEEDED") {
  // Handle the input limit and separately report error.errors when present.
}

A temporary file may
remain after such a reported failure. The exact cause of the single original
Chromium cleanup failure was not reproduced; deterministic error injection and
real-browser tests validate the hardening without claiming a browser root cause.

Limits and evidence

CAJ/PDF/KDH retain their documented profiles. HN/C8 remains experimental with
known viewer-pixel/geometry differences; C8/HN-B requires --no-bookmarks.
No OCR, searchable HN or TEB support is added. Absent optional corpora remain
NOT_RUN. Windows archives are unsigned and macOS archives are not notarized.
User-mode emulation is runtime evidence, not certification of every old kernel,
physical CPU or vendor ABI. Some rare targets build std with a separate pinned
nightly; the normal project compiler remains pinned stable Rust.

Every published target must run its declared tests; build-only success is not
support. Native, WASM/JS, MIT/advisory and exact 100% Linux Rust line-coverage
gates remain mandatory. Other OSes have separate runtime evidence, not a 100%
coverage claim. Release publication checks the complete native inventory and
container manifest, preserves tested binaries and checksums every asset.