idml 0.4.1 → 0.4.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7defde95ef6dc98c93c16a27f09b93c17aaea161a6878b1b130b58b3d8ba9cd
4
- data.tar.gz: 603a52445ffcb85e2e384e097d74810a302b045aecfaf4937af10d763c076c2d
3
+ metadata.gz: 79791db7118dac992a6dbfc780f143bc545cc1d6b7c408fac91fe9eb75de8d32
4
+ data.tar.gz: f98eb3f41100e1b7f62c51511f33aa774a5272e14fb4bcc7012dff50c88336d3
5
5
  SHA512:
6
- metadata.gz: da8441f49894dcce6656d429357421ee101c59061738e73527b9dc574d8905adf68b8a2fb78a5cc6bd5a4b67d2f4774893d96c9608ea7e6b91d945a1189b8e20
7
- data.tar.gz: 5251dd9d4c5bbb4003dc2f159a87a8d6ba1a9c1e78beacdbce37df366edf7cdd89a339b27edb470b91641db9ba387a2964e9857d39900476b57507d87470b873
6
+ metadata.gz: 34b95aeea5bf217fec6a88f8ae7a8a03c399001c0f4735bc11b0485afe27dbf9012fd481c8e6005f68f17fcc2bf850a63d03a3d23249bd570a57739ab92af1ed
7
+ data.tar.gz: 1f462441786c0a807f3bb0ddb01ff0c1c4a2e9a8e736fbd9e18b7666c2fe1c57c917dae3770b051ec716a25f4202cba5eef86a96bdca9630263ff5f385527367
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- idml (0.4.1)
4
+ idml (0.4.2)
5
5
  bigdecimal
6
6
  lutaml-model (~> 0.8.18)
7
7
  pdfrb
@@ -183,7 +183,7 @@ CHECKSUMS
183
183
  ffi (1.17.4-x86_64-darwin) sha256=aa70390523cf3235096cf64962b709b4cfbd5c082a2cb2ae714eb0fe2ccda496
184
184
  ffi (1.17.4-x86_64-linux-gnu) sha256=9d3db14c2eae074b382fa9c083fe95aec6e0a1451da249eab096c34002bc752d
185
185
  ffi (1.17.4-x86_64-linux-musl) sha256=3fdf9888483de005f8ef8d1cf2d3b20d86626af206cbf780f6a6a12439a9c49e
186
- idml (0.4.1)
186
+ idml (0.4.2)
187
187
  json (2.21.2) sha256=1f1d3b7cf2b3ba1a69beca0bb6db13d5438b80bff3cd54cdaaa620b9b07c1c6a
188
188
  language_server-protocol (3.17.0.6) sha256=5ef2c0c138f8267e1bc631d3328347d354f96724b0af22f2c79516120443b7f0
189
189
  lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
@@ -4,35 +4,51 @@
4
4
 
5
5
  ## What was done
6
6
 
7
- Extracted metadata assembly from `Pipeline` into a dedicated
8
- `Render::MetadataBuilder` class. Pipeline now calls
9
- `MetadataBuilder.new(@package).build` instead of inlining the XMP
10
- parsing, date conversion, and defaults logic.
7
+ Two extractions from `Pipeline` into dedicated classes:
8
+
9
+ 1. **`Render::MetadataBuilder`** metadata assembly (combined
10
+ defaults + XMP-extracted fields, ISO 8601 → PDF date conversion).
11
+ 2. **`Render::FontSetup`** — document font resolution via
12
+ `Pdfrb::FontResolver`, registration with pdfrb, and
13
+ `PdfrbFontMetrics` adapter construction.
14
+
15
+ Pipeline now does pure orchestration: build writer → set metadata →
16
+ apply compliance → set up structure → resolve font → render spreads
17
+ → flush structure → emit bookmarks → subset → write. No parsing,
18
+ no date math, no font-path lookup.
11
19
 
12
20
  ## Why
13
21
 
14
- Pipeline had five private methods dedicated to metadata
15
- (`combined_metadata`, `xmp_metadata`, `default_metadata`,
16
- `pdf_date_string`, `pdf_date`). Each was a single responsibility
17
- unrelated to the pipeline's core orchestration role. Moving them
18
- into a focused class:
22
+ Pipeline had 9 private methods across metadata, font setup, and
23
+ rendering concerns. Each concern is now its own class:
19
24
 
20
- - Shrinks Pipeline by ~55 lines.
21
- - Makes MetadataBuilder independently testable.
22
- - Makes Pipeline's intent clearer: orchestrate, not parse.
23
- - Lets future metadata sources (e.g., IDML document properties,
24
- custom user metadata) plug in without touching Pipeline.
25
+ - `MetadataBuilder` Info dict assembly.
26
+ - `FontSetup` font file lookup + registration + metrics adapter.
27
+ - `PdfaPacket` XMP packet + Catalog /Metadata attachment.
28
+ - `IccProfile` locate sRGB ICC bytes.
29
+ - `BookmarkResolver` destination chain + page index.
30
+ - `HyperlinkResolver` — source → URL lookup.
31
+ - `HyperlinkEmitter` — Link annotation emission.
32
+ - `StructureTracker` — MCID allocation + element registration.
33
+ - `StructureMapper` — item → PDF structure type.
34
+ - `ImageCollector` — image registration + placement.
35
+
36
+ Pipeline shrunk from ~225 lines (v0.3.0) to ~135 lines (v0.4.2).
25
37
 
26
38
  ## Verification
27
39
 
28
- - `lib/idml/render/metadata_builder.rb` — extracted class.
29
- - `lib/idml/render/pipeline.rb:25` — single-call usage.
30
- - `spec/idml/render/metadata_builder_spec.rb` — 5 specs covering
31
- defaults, XMP extraction, and the no-XMP fallback.
40
+ - `lib/idml/render/metadata_builder.rb` — extracted.
41
+ - `lib/idml/render/font_setup.rb` — extracted.
42
+ - `lib/idml/render/pipeline.rb` — orchestration only.
43
+ - `spec/idml/render/metadata_builder_spec.rb` 5 specs.
44
+ - `spec/idml/render/font_setup_spec.rb` — 4 specs.
45
+ - `spec/idml/render/placement_spec.rb` — added for completeness.
32
46
 
33
47
  ## Acceptance criteria
34
48
 
35
- - [x] MetadataBuilder extracted as a separate class.
36
- - [x] Pipeline no longer contains XMP/date helpers.
37
- - [x] Existing pipeline specs still pass.
38
- - [x] MetadataBuilder has dedicated specs.
49
+ - [x] MetadataBuilder extracted.
50
+ - [x] FontSetup extracted.
51
+ - [x] Pipeline no longer contains metadata/font helpers.
52
+ - [x] Each extracted class has dedicated specs.
53
+ - [x] All existing pipeline specs still pass.
54
+
@@ -0,0 +1,80 @@
1
+ # TODO PDF 84: Schema-faithful Table/Cell/Row structure
2
+
3
+ ## Status: DEFERRED (architectural correction; no fixtures to validate)
4
+
5
+ ## Current state vs schema
6
+
7
+ The existing `Idml::Elements::Table`, `TableRow`, `TableCell` classes
8
+ do not match the IDML RNC schema. Three structural divergences:
9
+
10
+ ### 1. Table lives in Stories, not Spreads
11
+
12
+ Per `reference-docs/schemas/package/Stories/Story.rnc`, `Table_Object`
13
+ appears inside `Story_Object` (as a child of `ParagraphStyleRange` or
14
+ `CharacterStyleRange`). The current `Idml::Elements::SpreadObject`
15
+ incorrectly declares `attribute :table, ... collection: true`, and
16
+ `PageItemRenderer` dispatches spread-level Tables to `TableRenderer`.
17
+
18
+ In real IDML, Tables appear inside Stories. A TextFrame's story
19
+ contains the table; the renderer should walk the story to find
20
+ tables, not the spread.
21
+
22
+ ### 2. Element names: `Cell` and `Row`, not `TableCell` and `TableRow`
23
+
24
+ Per RNC, the element names are:
25
+ - `element Cell` (`Cell_Object`)
26
+ - `element Row` (`Row_Object`)
27
+
28
+ The current model uses `TableCell` and `TableRow` as both class names
29
+ and XML element roots — neither matches the schema.
30
+
31
+ ### 3. Cell and Row are siblings under Table, not nested
32
+
33
+ Per RNC, `Table_Object` contains `Cell_Object* & Row_Object*` as
34
+ **siblings**, not nested `<Row><Cell>` structure:
35
+
36
+ ```
37
+ Table_Object = element Table {
38
+ ...
39
+ Cell_Object*,
40
+ Row_Object*
41
+ }
42
+ ```
43
+
44
+ The current model uses `Table > TableRow > TableCell` nesting, which
45
+ won't parse real IDML.
46
+
47
+ ## Plan
48
+
49
+ 1. Add new `Elements::Cell` (matching `Cell_Object` RNC, ~80 attrs).
50
+ 2. Add new `Elements::Row` (matching `Row_Object` RNC).
51
+ 3. Restructure `Elements::Table` to declare both `cell` and `row`
52
+ sibling collections.
53
+ 4. Remove `Elements::TableCell` and `Elements::TableRow` (broken).
54
+ 5. Remove `:table` from `Elements::SpreadObject`; Tables come via
55
+ Stories only.
56
+ 6. Update `TableRenderer` to:
57
+ - Dispatch from `TextFrameRenderer` when a story contains a Table.
58
+ - Render via `cell` and `row` siblings, using cell `Name` attr
59
+ (e.g., `"0_0"`) to determine column/row position.
60
+ 7. Update `PageItemRenderer::RENDERER_MAP` to remove Table (no
61
+ longer a page item).
62
+ 8. Update specs.
63
+
64
+ ## Why deferred
65
+
66
+ - No fixture in `spec/fixtures/` contains a Table, so the current
67
+ broken model has never been validated against real IDML.
68
+ - The correction touches multiple subsystems (elements, parts,
69
+ renderers, dispatch) and is best done as a focused refactor with
70
+ real-fixture regression tests.
71
+ - Adding fixtures requires either Adobe InDesign (commercial) or a
72
+ hand-crafted IDML ZIP matching the schema.
73
+
74
+ ## Acceptance criteria
75
+
76
+ - [ ] `Elements::Cell` matches `Cell_Object` RNC.
77
+ - [ ] `Elements::Row` matches `Row_Object` RNC.
78
+ - [ ] `Elements::Table` has sibling `cell` and `row` collections.
79
+ - [ ] Tables dispatch from `TextFrameRenderer`, not spread iteration.
80
+ - [ ] Real-fixture regression test with a known Table IDML.
@@ -0,0 +1,93 @@
1
+ # TODO PDF 85: Per-TextRange hyperlink precision
2
+
3
+ ## Status: DEFERRED (requires text-engine position tracking)
4
+
5
+ ## Current state
6
+
7
+ `HyperlinkEmitter` (TODO 78) emits one Link annotation per text
8
+ frame whose story contains a hyperlink source. The annotation
9
+ covers the entire frame's bounding box, not just the linked
10
+ characters.
11
+
12
+ ## What per-TextRange precision requires
13
+
14
+ For each hyperlink source, compute the rect that covers exactly
15
+ the source's characters on the page.
16
+
17
+ ### Position tracking
18
+
19
+ The text engine (`Shaper`, `LineBreaker`, `Justifier`) already
20
+ produces positioned lines via `VerticalLayout`, but
21
+ `TextFrameRenderer` does not surface per-character positions
22
+ outside its own scope. To compute per-source rects we need:
23
+
24
+ 1. **Absolute character index per CSR** — track cumulative char
25
+ position as CSRs are processed within a story.
26
+ 2. **Per-glyph (x, y) after layout** — Shaper gives widths,
27
+ LineBreaker gives line assignments, Justifier gives x_offset,
28
+ but no structured "positioned glyph" output is exposed today.
29
+ 3. **Source range lookup** — map `HyperlinkTextSource#Self` to a
30
+ `[start_char, end_char]` range. Today HyperlinkTextSource is
31
+ modelled as a sibling element of `Content` inside CSR; the
32
+ range is implicit (the source wraps its own content).
33
+
34
+ ### Emitter change
35
+
36
+ `HyperlinkEmitter` currently does:
37
+ ```ruby
38
+ box = Placement.box(frame, @page_height)
39
+ @writer.add_uri_link_annotation(page_index:, rect: rect_for(box), url:)
40
+ ```
41
+
42
+ Per-range version needs the positioned glyph data:
43
+ ```ruby
44
+ positions = context.positioned_glyphs_for_frame(frame.self_attr)
45
+ range = source_range_for(hyperlink_source)
46
+ rect = bounding_rect_for_range(positions, range)
47
+ @writer.add_uri_link_annotation(page_index:, rect:, url:)
48
+ ```
49
+
50
+ ### Threading
51
+
52
+ Positioned glyph data must travel from `TextFrameRenderer` (which
53
+ runs the layout engine) to `HyperlinkEmitter` (which runs after
54
+ the page renders). Options:
55
+
56
+ - **A. Side channel via RenderContext**: add `positioned_glyphs`
57
+ hash to RenderContext, keyed by frame Self. Renderers populate
58
+ it; emitter reads it.
59
+ - **B. Two-pass render**: re-run layout in the emitter to compute
60
+ positions. Wasteful but keeps emitter self-contained.
61
+ - **C. Position tracker object**: similar to StructureTracker —
62
+ Pipeline constructs it, threads through RenderContext, queries
63
+ after rendering.
64
+
65
+ Option C is the cleanest (matches StructureTracker pattern from
66
+ TODO 76).
67
+
68
+ ## Plan
69
+
70
+ 1. Add `Render::PositionTracker` — accumulates per-frame positioned
71
+ ranges: `[{ frame_self:, start_char:, end_char:, x:, y:, width:,
72
+ height: }, ...]`.
73
+ 2. Add `position_tracker` to `RenderContext`.
74
+ 3. In `TextFrameRenderer#render_run_lines`, after layout, push each
75
+ line's positioned range to the tracker.
76
+ 4. In `HyperlinkEmitter#emit_for_frame`, query the tracker for
77
+ ranges that overlap each hyperlink source's `[start_char,
78
+ end_char]`. Compute the bounding rect from those ranges.
79
+ 5. Emit one Link annotation per source.
80
+
81
+ ## Why deferred
82
+
83
+ - No fixture has hyperlinks → can't validate per-range precision.
84
+ - Position tracker adds another stateful object to the render path.
85
+ - Frame-level precision is "good enough" for visible link presence;
86
+ per-range is a polish improvement.
87
+
88
+ ## Acceptance criteria
89
+
90
+ - [ ] PositionTracker accumulates per-frame positioned ranges.
91
+ - [ ] HyperlinkEmitter queries tracker for source ranges.
92
+ - [ ] Each hyperlink source gets its own Link annotation rect.
93
+ - [ ] Spec covers multi-source story with overlapping ranges.
@@ -0,0 +1,71 @@
1
+ # TODO PDF 86: Caching and performance
2
+
3
+ ## Status: PARTIAL — most hot paths cached; one risk noted
4
+
5
+ ## What is cached today
6
+
7
+ - `ColorResolver#resolve` — per-color-name cache (`@cache`).
8
+ - `PdfrbFontMetrics#metrics_data` — read-through to pdfrb's
9
+ `Fonts#metrics_for` which has its own cache.
10
+ - `Pipeline#font_resolver` — lazily memoised via `||=`.
11
+ - `MetadataBuilder#xmp_packet` — memoised via `@xmp_packet ||=`.
12
+ - `PdfrbWriter#@image_cache` — URI → name cache for images.
13
+ - `Pdfrb::Document` internals — fonts, pages, structure all have
14
+ their own caches.
15
+
16
+ ## What is not cached
17
+
18
+ ### `geometric_bounds` on element instances
19
+
20
+ Each call to `Placement.box(item, page_height)` calls
21
+ `item.geometric_bounds`, which walks `Properties → PathGeometry →
22
+ bounding_box`. For each rendered item, this is called:
23
+
24
+ - 1× in the renderer (via `Placement.box`).
25
+ - 1× in `ImageCollector#clip_box_for` (for items that have images).
26
+ - 1× in `HyperlinkEmitter#emit_for_frame` (for text frames).
27
+
28
+ So 2–3 walks per item. Memoising at the element level would save
29
+ the duplicate walks.
30
+
31
+ ### Risk: Lutaml model instance variables
32
+
33
+ Lutaml::Model::Serializable instances are populated via the
34
+ framework's own `instance_variable_set` during deserialization.
35
+ Adding `@geometric_bounds ||= ...` could conflict if Lutaml ever
36
+ adds an attribute of the same name, or if the framework resets
37
+ instance state during round-trip.
38
+
39
+ The safer pattern is to memoise at the helper layer (Placement)
40
+ using `Object#object_id` as the cache key, but that introduces
41
+ memory pressure (unbounded hash growth).
42
+
43
+ ### Decision
44
+
45
+ Defer until profiling shows it matters. Current render of the
46
+ sample-with-image fixture (~60KB PDF, multiple shapes/text frames)
47
+ completes in ~250ms, which is fast enough for typical use.
48
+
49
+ ## Other performance notes
50
+
51
+ - **SpreadRenderer iterates spread items 3×**: once for
52
+ `ImageCollector`, once for rendering, once for `HyperlinkEmitter`.
53
+ Could be combined but couples concerns.
54
+ - **No lazy part loading**: opening a Package reads all parts
55
+ eagerly. For large IDML files this could be slow; not yet a
56
+ measured problem.
57
+
58
+ ## Plan (if profiling shows it matters)
59
+
60
+ 1. Memoise `geometric_bounds` on `Elements::Rectangle`, `Polygon`,
61
+ `GraphicLine`, `TextFrame`, `Table` via `||=` with a
62
+ non-conflicting ivar name (e.g., `@_bounds_cache`).
63
+ 2. Add a spec that asserts the cache is populated after first
64
+ access.
65
+ 3. Re-run render benchmarks.
66
+
67
+ ## Acceptance criteria
68
+
69
+ - [ ] Profile render of a large fixture and identify hot paths.
70
+ - [ ] If `geometric_bounds` shows up, memoise safely.
71
+ - [ ] Spec asserts memoisation doesn't break round-trip.
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Idml
4
+ module Render
5
+ # Resolves the document font and wraps it in a
6
+ # `TextEngine::PdfrbFontMetrics` adapter. Encapsulates:
7
+ #
8
+ # 1. Finding the IDML document's first non-missing font file
9
+ # via `Pdfrb::FontResolver#find_by_ps_name`.
10
+ # 2. Registering that file with pdfrb's Fonts collection.
11
+ # 3. Wrapping the resulting Symbol resource in
12
+ # `PdfrbFontMetrics` for the text engine.
13
+ #
14
+ # Extracted from `Pipeline` for SRP — Pipeline orchestrates,
15
+ # this object owns the font-setup dance.
16
+ class FontSetup
17
+ DEFAULT_FONT = Render::DEFAULT_FONT
18
+
19
+ def initialize(package:, font_search_paths: nil)
20
+ @package = package
21
+ @font_search_paths = font_search_paths
22
+ end
23
+
24
+ # Registers the resolved font with `writer` and returns the
25
+ # Symbol resource. Falls back to `Render::DEFAULT_FONT`
26
+ # (`"Helvetica"`) when the document has no resolvable font.
27
+ def register(writer)
28
+ path = resolve_document_font_path
29
+ return DEFAULT_FONT unless path
30
+
31
+ writer.register_font(path)
32
+ rescue StandardError
33
+ DEFAULT_FONT
34
+ end
35
+
36
+ # Wraps a registered font resource in a PdfrbFontMetrics
37
+ # adapter. Returns nil when the resource is the default
38
+ # fallback (no real metrics available).
39
+ def metrics_for(writer, font_resource)
40
+ return nil if font_resource == DEFAULT_FONT
41
+
42
+ TextEngine::PdfrbFontMetrics.new(writer.document.fonts, font_resource)
43
+ rescue StandardError
44
+ nil
45
+ end
46
+
47
+ private
48
+
49
+ def resolve_document_font_path
50
+ return nil unless @package&.fonts
51
+
52
+ @package.fonts.font_family.each do |family|
53
+ path = find_font_file(family)
54
+ return path if path
55
+ end
56
+ nil
57
+ end
58
+
59
+ def find_font_file(family)
60
+ family.font.each do |font|
61
+ next unless font.post_script_name
62
+ next if font.status == "Missing"
63
+
64
+ path = resolver.find_by_ps_name(font.post_script_name)
65
+ return path if path
66
+ end
67
+ nil
68
+ end
69
+
70
+ def resolver
71
+ @resolver ||= Pdfrb::FontResolver.new(
72
+ search_paths: @font_search_paths || Pdfrb::FontResolver::DEFAULT_SEARCH_PATHS,
73
+ )
74
+ end
75
+ end
76
+ end
77
+ end
@@ -3,8 +3,15 @@
3
3
  module Idml
4
4
  module Render
5
5
  # Top-level pipeline: IDML Package → PDF file using pdfrb.
6
- # All PDF assembly is delegated to Pdfrb::Document. Renderers
7
- # receive a Pdfrb::Content::Canvas and call drawing methods.
6
+ # All PDF assembly is delegated to pdfrb; this class orchestrates
7
+ # the high-level flow:
8
+ #
9
+ # 1. Build writer + set metadata.
10
+ # 2. Apply compliance (PDF/A XMP + ICC) if requested.
11
+ # 3. Set up structure tracker for tagged PDF.
12
+ # 4. Resolve document font.
13
+ # 5. For each spread: collect images, render pages, emit hyperlinks.
14
+ # 6. Flush structure, emit bookmarks, subset fonts, write.
8
15
  class Pipeline
9
16
  DEFAULT_WIDTH = 612
10
17
  DEFAULT_HEIGHT = 792
@@ -24,23 +31,21 @@ module Idml
24
31
  metadata = MetadataBuilder.new(@package).build
25
32
  writer.set_info(metadata)
26
33
  writer.enable_tagged if @tagged
27
- if pdfa_requested?
28
- PdfaPacket.attach(writer.document, metadata)
29
- embed_pdfa_output_intent(writer)
30
- end
34
+ apply_compliance(writer, metadata) if pdfa_requested?
35
+
31
36
  structure = StructureTracker.new(enabled: @tagged)
32
37
  layer_filter = LayerFilter.from_designmap(@package.designmap)
33
38
  font_ref_resolver = FontReferenceResolver.build(@package)
34
- base_dir = File.dirname(@package.path)
35
- font_resource = register_font(writer)
36
- font_metrics = build_font_metrics(writer, font_resource)
37
- page_index = -1
39
+ font_setup = FontSetup.new(package: @package,
40
+ font_search_paths: @font_search_paths)
41
+ font_resource = font_setup.register(writer)
42
+ font_metrics = font_setup.metrics_for(writer, font_resource)
38
43
 
44
+ page_index = -1
39
45
  @package.spreads.each do |spread|
40
- page_index = render_spread_pages(writer, spread, base_dir,
41
- layer_filter, font_ref_resolver,
42
- font_resource, font_metrics,
43
- structure, page_index)
46
+ page_index = render_spread(writer, spread, layer_filter,
47
+ font_ref_resolver, font_resource,
48
+ font_metrics, structure, page_index)
44
49
  end
45
50
 
46
51
  structure.flush(writer)
@@ -53,7 +58,8 @@ module Idml
53
58
 
54
59
  private
55
60
 
56
- def embed_pdfa_output_intent(writer)
61
+ def apply_compliance(writer, metadata)
62
+ PdfaPacket.attach(writer.document, metadata)
57
63
  bytes = IccProfile.srgb_bytes
58
64
  return unless bytes
59
65
 
@@ -67,24 +73,24 @@ module Idml
67
73
  nil
68
74
  end
69
75
 
76
+ def pdfa_requested?
77
+ @compliance&.to_s&.start_with?("pdfa")
78
+ end
79
+
70
80
  def emit_bookmarks(writer)
71
81
  BookmarkResolver.new(@package).each do |title, page_index|
72
82
  writer.add_bookmark(title, page_index)
73
83
  end
74
84
  end
75
85
 
76
- def pdfa_requested?
77
- @compliance&.to_s&.start_with?("pdfa")
78
- end
79
-
80
- def render_spread_pages(writer, spread, base_dir, layer_filter,
81
- font_ref_resolver, font_resource, font_metrics,
82
- structure, page_offset)
86
+ def render_spread(writer, spread, layer_filter, font_ref_resolver,
87
+ font_resource, font_metrics, structure, page_offset)
83
88
  pages = spread.spread.flat_map(&:page)
84
- image_refs = ImageCollector.new(writer: writer, base_dir: base_dir,
89
+ image_refs = ImageCollector.new(writer: writer,
90
+ base_dir: File.dirname(@package.path),
85
91
  page_height: DEFAULT_HEIGHT).collect(spread)
86
92
  renderer = build_renderer(layer_filter, font_ref_resolver,
87
- font_resource, font_metrics, structure: structure)
93
+ font_resource, font_metrics, structure)
88
94
  current = page_offset
89
95
 
90
96
  pages.each do |page|
@@ -110,7 +116,7 @@ module Idml
110
116
  end
111
117
 
112
118
  def build_renderer(layer_filter, font_ref_resolver, font_resource,
113
- font_metrics, structure:)
119
+ font_metrics, structure)
114
120
  SpreadRenderer.new(
115
121
  font_metrics: font_metrics,
116
122
  font_ps_name: font_resource,
@@ -125,50 +131,6 @@ module Idml
125
131
  { width: page.width || DEFAULT_WIDTH,
126
132
  height: page.height || DEFAULT_HEIGHT }
127
133
  end
128
-
129
- def build_font_metrics(writer, font_resource)
130
- return nil if font_resource == Render::DEFAULT_FONT
131
-
132
- TextEngine::PdfrbFontMetrics.new(writer.document.fonts, font_resource)
133
- rescue StandardError
134
- nil
135
- end
136
-
137
- def register_font(writer)
138
- path = resolve_document_font_path
139
- return Render::DEFAULT_FONT unless path
140
-
141
- writer.register_font(path)
142
- rescue StandardError
143
- Render::DEFAULT_FONT
144
- end
145
-
146
- def font_resolver
147
- @font_resolver ||= Pdfrb::FontResolver.new(
148
- search_paths: @font_search_paths || Pdfrb::FontResolver::DEFAULT_SEARCH_PATHS,
149
- )
150
- end
151
-
152
- def resolve_document_font_path
153
- return nil unless @package&.fonts
154
-
155
- @package.fonts.font_family.each do |family|
156
- path = find_font_file(family)
157
- return path if path
158
- end
159
- nil
160
- end
161
-
162
- def find_font_file(family)
163
- family.font.each do |font|
164
- next unless font.post_script_name
165
- next if font.status == "Missing"
166
-
167
- path = font_resolver.find_by_ps_name(font.post_script_name)
168
- return path if path
169
- end
170
- nil
171
- end
172
134
  end
173
135
  end
174
136
  end
data/lib/idml/render.rb CHANGED
@@ -24,6 +24,7 @@ module Idml
24
24
  autoload :HyperlinkResolver, "#{__dir__}/render/hyperlink_resolver"
25
25
  autoload :HyperlinkEmitter, "#{__dir__}/render/hyperlink_emitter"
26
26
  autoload :MetadataBuilder, "#{__dir__}/render/metadata_builder"
27
+ autoload :FontSetup, "#{__dir__}/render/font_setup"
27
28
  autoload :StoryThreader, "#{__dir__}/render/story_threader"
28
29
  autoload :PdfrbWriter, "#{__dir__}/render/pdfrb_writer"
29
30
  autoload :SpreadRenderer, "#{__dir__}/render/spread_renderer"
data/lib/idml/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Idml
4
- VERSION = "0.4.1"
4
+ VERSION = "0.4.2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: idml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose
@@ -210,6 +210,9 @@ files:
210
210
  - TODO.pdf/81-pdfa-icc-output-intent.md
211
211
  - TODO.pdf/82-table-cell-text.md
212
212
  - TODO.pdf/83-pipeline-decomposition.md
213
+ - TODO.pdf/84-schema-faithful-table.md
214
+ - TODO.pdf/85-per-text-range-hyperlinks.md
215
+ - TODO.pdf/86-caching-performance.md
213
216
  - TODO.pdf/README.md
214
217
  - exe/idml
215
218
  - idml.gemspec
@@ -385,6 +388,7 @@ files:
385
388
  - lib/idml/render/color_helper.rb
386
389
  - lib/idml/render/color_resolver.rb
387
390
  - lib/idml/render/font_reference_resolver.rb
391
+ - lib/idml/render/font_setup.rb
388
392
  - lib/idml/render/gradient_resolver.rb
389
393
  - lib/idml/render/hyperlink_emitter.rb
390
394
  - lib/idml/render/hyperlink_resolver.rb