Files
pdfcraft/crates/create
Grzegorz MartensandClaude Opus 5.5 8c720e4808 M11: Export reads byte-aligned Group 3 by the codes in its data
"Export ▸ Images reads byte-aligned Group 3 whichever way its fill
falls" read byte-aligned rows unaligned whenever /EndOfLine was set.
That broke byte-aligned Group 4 with /EndOfLine (refused); read Group 3
that says /EndOfLine but has no codes unaligned, and wrongly; and read
codes with the fill before them, but no /EndOfLine, on bytes: every row,
the wrong picture, nothing said. Now:
- Group 4, and rows not on bytes, read as the parameters say;
- Group 3 rows on bytes are read by the data: T.4 sends an end-of-line
  code before the first row when it sends them at all, and no other code
  starts with more than eight zeros. Data that starts with 11 zeros or
  more (fill included) and a 1 has codes, and is read unaligned, where
  the codes mark the rows whether the fill starts each code on a byte or
  ends it on one; other data is read on bytes, whatever /EndOfLine says.
  A reading that comes up short is reported rather than tried the other
  way, where data cut short would read as other rows.

The Group 3 test exports nine pictures, stripes and eight of random
text-like runs (how a misreading comes out depends on the picture),
coded with T.4's terminating codes at /K 0 and 1: no codes, with
/EndOfLine and without; codes each starting on a byte or ending on one,
with /EndOfLine and without. Each exports as its picture, and each a
byte short is reported; at /K 1, codes with none before the first row
(not as T.4 sends them) export as their picture or are reported.
Byte-aligned Group 4 still reads with and without /EndOfLine. The
create.export-all-images parity note says what is still limited: such
codes may export wrong at /K 0, as the create README says. A rule tried
first, reading both ways and refusing an image that gave every row both
ways differently, failed on the stripes without codes (TIFF's Modified
Huffman layout): its unaligned reading gives every row too, wrongly. So
did one that read the other way when the first reading came up short: it
drew data cut short as other rows. cargo-mutants leaves no mutant of the
new lines alive.

From reviews with the pdfcraft-review skill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P6yUtvWGPsJpMLyh6pxSXG
2026-10-29 20:48:02 +01:00
..

pdfcraft-create

Layer L4. Create a PDF (Acrobat's Create a PDF tool), execution plan M10.2:

  • blank(width, height, pages): an empty document;
  • from_images(&[(name, bytes)]): one page per image, sized from the image's resolution (PNG pHYs, JPEG JFIF density; 72 dpi when absent). JPEG data is embedded as is (/DCTDecode, grey, RGB or Adobe-inverted CMYK); PNG is decoded and stored with Flate, with transparency as a soft mask. A picture of only pure black and white (a 1-bit PNG or TIFF, eight-bit grey, a two-colour palette, RGB without a profile) is stored at one bit per pixel, as CCITT Group 4 or Flate, whichever is smaller as stored (pdfcraft_filters::encode_g4). Redaction doesn't decode Group 4 yet: a mark over part of such a picture removes the whole picture (nothing leaks). An ICC profile in the file (JPEG APP2 ICC_PROFILE, PNG iCCP) that matches the image's colour space is kept as an /ICCBased colour space with the device space as /Alternate; images with the same profile share one profile object. JPEG metadata scanning skips marker fill bytes and reads application segments after the frame header, stopping at the first scan or end marker. Broken or mismatched ICC profiles still fall back to the device colour space;
  • from_images_with_resolution(images, ImageResolution::Dpi(dpi)): override the page resolution (1–1200 dpi), without resampling or recompressing image pixels. Use 72 dpi for one point per pixel, or ImageResolution::Embedded for the same behavior as from_images. The largest page side is still capped at 14,400 points;
  • from_text(text, …): plain text set in Helvetica, wrapped and paginated. Text Helvetica can't draw is refused, naming the line and the character, never set as ?.
  • from_text_escaped(text, …): the same for reports PdfCraft generates from documents (comment summaries, compare reports): such characters are written as [U+XXXX] and the first line says so (ESCAPED_NOTE).

Every function returns a pdfcraft_cos::Document; the caller writes it.

Image export and Save Image As apply each lossless image's Decode pair before converting its color components. Indexed Decode values select palette entries after rounding and clipping. Color-key masks compare the original samples. Missing, null or malformed Decode arrays keep the default mapping. Soft-mask Decode intervals map samples to opacity before the mask is resized, including reversed ranges and indirect entries. The existing 16-bit path still uses each sample's high byte. JPEG image Decode handling remains limited. ICC transforms and calibrated color conversion remain outside this export path. CCITT fax images (Group 3 and 4) are decoded for export through hayro-ccitt with their /DecodeParms (/Columns has to be the image's width), behind other filters such as ASCII85Decode too. Byte-aligned Group 3 rows are read by their end-of-line codes, whether the fill starts each code on a byte or ends it on one, when the data starts with one (T.4 sends one before the first row), and on bytes otherwise, whatever /EndOfLine says; data that comes up short is reported. Data with codes but none before the first row is read on bytes, and is reported or, at /K 0, may come out wrong. JPEG 2000 and JBIG2 images are still reported, not exported.