idml 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,33 +0,0 @@
1
- # TODO PDF 56: Text engine full integration with pdfrb Canvas
2
-
3
- ## Goal
4
-
5
- Re-integrate the text engine (Shaper → LineBreaker → Justifier →
6
- VerticalLayout) into TextFrameRenderer using pdfrb Canvas. Each line
7
- of shaped/broken text is emitted as a separate `canvas.text` call
8
- at the computed baseline position.
9
-
10
- ## Status: DONE
11
-
12
- ## What was implemented
13
-
14
- TextFrameRenderer has two rendering paths:
15
- 1. **engine_render** (when FontMetrics available): shapes text via
16
- Shaper, breaks lines via LineBreaker at frame width, positions
17
- each line at decreasing baseline_y, emits `canvas.text` per line.
18
- Lines beyond frame bottom are skipped.
19
- 2. **simple_render** (fallback): one `canvas.text` per styled run at
20
- sequential y positions.
21
-
22
- The FontMetrics comes from `context.font_resolver.resolve(family_name:)`.
23
- On systems where the default font is available as .ttf (not .ttc), the
24
- text engine provides proper word-wrap.
25
-
26
- ## Acceptance criteria
27
-
28
- - [x] TextFrameRenderer tries FontResolver for metrics.
29
- - [x] When metrics available: Shaper → LineBreaker → per-line canvas.text.
30
- - [x] When metrics unavailable: simple one-text-per-run fallback.
31
- - [x] Frame bounds respected (lines beyond frame bottom skipped).
32
- - [x] Chain head check prevents duplicate text in overflow frames.
33
- - [x] Text frame insets subtracted from frame box.
@@ -1,26 +0,0 @@
1
- # TODO PDF 57: Image clipping via pdfrb Canvas
2
-
3
- ## Goal
4
-
5
- Clip placed images to their parent Rectangle's bounds using PDF clip
6
- paths. Prevents image overflow beyond the containing frame.
7
-
8
- ## Status: DONE
9
-
10
- ## What was implemented
11
-
12
- - `PdfrbExt::Clip` (PDF `W` operator) and `PdfrbExt::EndPath` (PDF `n`
13
- operator) registered as pdfrb Content::Operator subclasses.
14
- - `SpreadRenderer#apply_image_clip` emits a clip path from the parent
15
- Rectangle's geometric_bounds before drawing the image.
16
- - `Pipeline#parent_clip_box` computes the clip rectangle from the
17
- parent page item's bounds via Geometry helpers.
18
- - Image refs now carry a `clip_box` field; when present, the SpreadRenderer
19
- clips before drawing.
20
-
21
- ## Acceptance criteria
22
-
23
- - [x] PdfrbExt::Clip and EndPath operators registered.
24
- - [x] SpreadRenderer applies clip path when clip_box is present.
25
- - [x] Pipeline computes clip_box from parent geometric_bounds.
26
- - [x] All tests pass.
@@ -1,23 +0,0 @@
1
- # TODO PDF 58: PDF bookmarks via pdfrb outline API
2
-
3
- ## Goal
4
-
5
- Generate PDF bookmark (outline) entries using pdfrb's outline API.
6
- Each bookmark links to a page destination.
7
-
8
- ## Status: DONE
9
-
10
- ## What was implemented
11
-
12
- - `PdfrbWriter#add_bookmark(title, page_index)` delegates to
13
- `Pdfrb::Document#outline.add(title, dest: page)`.
14
- - Available for Pipeline consumers to add bookmarks for headings or
15
- sections.
16
- - `PdfrbExt::Clip` and `PdfrbExt::EndPath` also added for image clipping
17
- (TODO 57).
18
-
19
- ## Acceptance criteria
20
-
21
- - [x] PdfrbWriter#add_bookmark delegates to pdfrb outline API.
22
- - [x] Anti-pattern spec passes (no new violations).
23
- - [x] All tests pass.
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # DEPRECATED: This module is superseded by ColorHelper + Canvas
4
- # fill_color/stroke_color methods. Kept for backward compatibility.
5
-
6
- module Idml
7
- module Render
8
- # Converts IDML color values to PDF content-stream operators.
9
- module Color
10
- module_function
11
-
12
- # RGB fill: `r g b rg`. Values 0.0–1.0.
13
- def fill_rgb(r, g, b)
14
- format("%<r>.4f %<g>.4f %<b>.4f rg", r: r, g: g, b: b)
15
- end
16
-
17
- # RGB stroke: `r g b RG`.
18
- def stroke_rgb(r, g, b)
19
- format("%<r>.4f %<g>.4f %<b>.4f RG", r: r, g: g, b: b)
20
- end
21
-
22
- # CMYK fill: `c m y k k`.
23
- def fill_cmyk(c, m, y, k)
24
- format("%<c>.4f %<m>.4f %<y>.4f %<k>.4f k", c: c, m: m, y: y, k: k)
25
- end
26
-
27
- # CMYK stroke: `c m y k K`.
28
- def stroke_cmyk(c, m, y, k)
29
- format("%<c>.4f %<m>.4f %<y>.4f %<k>.4f K", c: c, m: m, y: y, k: k)
30
- end
31
-
32
- # Parse IDML color space value (space-separated 0–255 or 0–100
33
- # depending on model) to normalized 0.0–1.0.
34
- def normalize_channel(value, max = 255)
35
- value.to_f / max
36
- end
37
-
38
- # Black fill (common default).
39
- def black_fill
40
- "0 g"
41
- end
42
-
43
- # White fill.
44
- def white_fill
45
- "1 g"
46
- end
47
-
48
- # Dispatch: accepts a color hash ({ model:, r:, g:, b: } or
49
- # { model:, c:, m:, y:, k: }) and returns the appropriate
50
- # fill operator string.
51
- def fill_op(color)
52
- case color[:model]
53
- when :rgb then fill_rgb(color[:r], color[:g], color[:b])
54
- when :cmyk then fill_cmyk(color[:c], color[:m], color[:y], color[:k])
55
- end
56
- end
57
-
58
- # Dispatch: accepts a color hash and returns the appropriate
59
- # stroke operator string.
60
- def stroke_op(color)
61
- case color[:model]
62
- when :rgb then stroke_rgb(color[:r], color[:g], color[:b])
63
- when :cmyk then stroke_cmyk(color[:c], color[:m], color[:y],
64
- color[:k])
65
- end
66
- end
67
- end
68
- end
69
- end
@@ -1,79 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # DEPRECATED: This module is superseded by PdfrbWriter.register_font.
4
- # Font embedding is now handled by pdfrb (Pdfrb::Document#fonts.add).
5
-
6
- module Idml
7
- module Render
8
- # Generates PDF font structures for embedded TrueType fonts.
9
- # Produces the Widths array (WinAnsiEncoding 32–255), FontDescriptor
10
- # metadata, and FontFile2 binary embedding.
11
- module FontEmbedder
12
- FIRST_CHAR = 32
13
- LAST_CHAR = 255
14
-
15
- # PDF WinAnsiEncoding = Code Page 1252. Bytes 0x80-0x9F differ
16
- # from ISO-8859-1 and map to specific Unicode codepoints.
17
- CP1252_SPECIAL = {
18
- 0x80 => 0x20AC, 0x82 => 0x201A, 0x83 => 0x0192, 0x84 => 0x201E,
19
- 0x85 => 0x2026, 0x86 => 0x2020, 0x87 => 0x2021, 0x88 => 0x02C6,
20
- 0x89 => 0x2030, 0x8A => 0x0160, 0x8B => 0x2039, 0x8C => 0x0152,
21
- 0x8E => 0x017D, 0x91 => 0x2018, 0x92 => 0x2019, 0x93 => 0x201C,
22
- 0x94 => 0x201D, 0x95 => 0x2022, 0x96 => 0x2013, 0x97 => 0x2014,
23
- 0x98 => 0x02DC, 0x99 => 0x2122, 0x9A => 0x0161, 0x9B => 0x203A,
24
- 0x9C => 0x0153, 0x9E => 0x017E, 0x9F => 0x0178
25
- }.freeze
26
-
27
- private_constant :CP1252_SPECIAL
28
-
29
- module_function
30
-
31
- # Widths array for WinAnsiEncoding (chars 32–255), in PDF text
32
- # units (1000 units per em).
33
- def widths_array(font_metrics)
34
- (FIRST_CHAR..LAST_CHAR).map do |byte|
35
- cp = winansi_to_unicode(byte)
36
- raw = font_metrics.glyph_width(cp)
37
- scale_to_text_units(raw, font_metrics.units_per_em)
38
- end
39
- end
40
-
41
- # Map a WinAnsi (CP1252) byte value to its Unicode codepoint.
42
- def winansi_to_unicode(byte)
43
- CP1252_SPECIAL.fetch(byte, byte)
44
- end
45
-
46
- def scale_to_text_units(font_units, upem)
47
- (font_units.to_f * 1000 / upem).round
48
- end
49
-
50
- # FontDescriptor metadata hash.
51
- def descriptor(font_metrics)
52
- upem = font_metrics.units_per_em
53
- scale = 1000.0 / upem
54
- ascent = font_metrics.ascent.to_f
55
- descent = font_metrics.descent.to_f
56
- {
57
- font_name: font_metrics.postscript_name,
58
- flags: 32,
59
- font_bbox: [
60
- (descent * scale).round,
61
- 0,
62
- 1000,
63
- (ascent * scale).round,
64
- ],
65
- italic_angle: 0,
66
- ascent: (ascent * scale).round,
67
- descent: (descent * scale).round,
68
- cap_height: (ascent * scale * 0.7).round,
69
- stem_v: 80,
70
- }
71
- end
72
-
73
- # Read raw font binary data from the FontMetrics source path.
74
- def raw_font_data(font_metrics)
75
- File.binread(font_metrics.path)
76
- end
77
- end
78
- end
79
- end
@@ -1,80 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # DEPRECATED: This module is superseded by Pdfrb::Content::Canvas
4
- # drawing methods (rectangle, stroke, fill, etc.).
5
-
6
- module Idml
7
- module Render
8
- # Converts IDML geometric page items to PDF path operators.
9
- module Path
10
- module_function
11
-
12
- # Rectangle → `x y w h re`
13
- def rectangle(x:, y:, width:, height:)
14
- format("%<x>.2f %<y>.2f %<w>.2f %<h>.2f re", x: x, y: y, w: width,
15
- h: height)
16
- end
17
-
18
- # Save graphics state
19
- def save_state
20
- "q"
21
- end
22
-
23
- # Restore graphics state
24
- def restore_state
25
- "Q"
26
- end
27
-
28
- # Transformation matrix: `a b c d e f cm`
29
- def transform(a:, b:, c:, d:, e:, f:)
30
- format("%<a>.4f %<b>.4f %<c>.4f %<d>.4f %<e>.2f %<f>.2f cm",
31
- a: a, b: b, c: c, d: d, e: e, f: f)
32
- end
33
-
34
- # Fill the current path (nonzero winding).
35
- def fill
36
- "f"
37
- end
38
-
39
- # Set clip path (nonzero winding). Must be followed by `n` (no-op).
40
- def clip
41
- "W n"
42
- end
43
-
44
- # Set clip path (even-odd).
45
- def eo_clip
46
- "W* n"
47
- end
48
-
49
- # Stroke the current path.
50
- def stroke
51
- "S"
52
- end
53
-
54
- # Set stroke line width: `w w`
55
- def stroke_width(weight)
56
- format("%<w>.2f w", w: weight)
57
- end
58
-
59
- # Close, fill, and stroke the current path.
60
- def fill_stroke
61
- "B"
62
- end
63
-
64
- # Close the current path.
65
- def close
66
- "h"
67
- end
68
-
69
- # Move to a point: `x y m`
70
- def move_to(x, y)
71
- format("%<x>.2f %<y>.2f m", x: x, y: y)
72
- end
73
-
74
- # Line to a point: `x y l`
75
- def line_to(x, y)
76
- format("%<x>.2f %<y>.2f l", x: x, y: y)
77
- end
78
- end
79
- end
80
- end