mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-25 02:29:31 -06:00
* fix(render): convert spot-colour images once per pixel value (vendored hayro-interpret patch 28) An image whose pixels hold at most 16 bits of samples (an 8-bit Separation or DeviceN image, a 1-, 2- or 4-bit gray or indexed one) is now converted to RGB through a table of every possible pixel value instead of pixel by pixel. A Separation or DeviceN tint transform is a PDF function, often a PostScript calculator program, and the image decoder ran it once per pixel. Fillable character sheets draw their background art as an 8-bit DeviceN image: one with a 3304 x 4105 background took 3.8 s and 430 MB to draw each page (Poppler: 0.27 s), when opening it and again after every field was filled. It now draws in 0.11 s and 100 MB, pixel for pixel the same. The table decodes each sample through the same `decode_sample` as the per-pixel path, keeps `fix_image_length`'s rules for short and overlong data (the pixels past the data are converted as before), and is used only when the image has more pixels than the table has entries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KnNgjPEDfKJM1wj17Q8Za8 * fix(render): place widgets without /P in one pass over the pages Opening a document, the inspector finds the page of a form field whose widget has no /P by searching every page's /Annots for it, once per field: O(fields x annotations). A form of 8,000 such fields took 1.17 s to open instead of 0.27 s. The pages' /Annots are now read once, on the first such field, into a map from annotation to page. A widget that several pages list is now placed on the first of them, as pdfcraft-forms places it; the search took whichever page a HashMap visited first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KnNgjPEDfKJM1wj17Q8Za8 * fix(ui): the Fields panel keeps up with large forms Every frame the Fields panel searched the form for each row by name, once to sort the rows into tab order and again to find what a click selects: O(fields²) a frame. It also laid out, drew and built the tooltip of every row, scrolled into view or not. With 8,000 fields the app used 13.4 s of CPU for 20 pointer moves with the panel open (0.2 s with it closed). The rows are now worked out by `field_rows`, which pairs each row with the first form field of its name through one map a frame, as the engine pairs them, and a row out of view is allocated and keeps its clicks, keyboard focus and accessibility label but isn't drawn and builds no tooltip. The same 20 moves now take 0.86 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KnNgjPEDfKJM1wj17Q8Za8 * docs: roadmap entries for faster form-heavy documents Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KnNgjPEDfKJM1wj17Q8Za8 * fix(render): convert each lookup-table entry on its own (vendored hayro-interpret patch 28) Patch 28 converted the whole table of possible pixel values in one batch. Separation and DeviceN `convert_f32` concatenate each tint result, and a Type 4 program that returns the wrong number of components is only warned about, so a malformed result for a value the image never uses shifted every later entry. A 32 x 32 image whose only sample (255) is red drew black because tint 0 returned one component (PR #1691 review). `convert_each` now converts the table one entry at a time, so a malformed entry changes only itself. The largest table (65,536 entries, a two-ink DeviceN image over DeviceCMYK) takes about 2 ms longer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com>