idml 0.4.4 → 0.4.5
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 +4 -4
- data/Gemfile.lock +2 -2
- data/TODO.pdf/84-schema-faithful-table.md +30 -1
- data/TODO.pdf/87-final-state-summary.md +97 -0
- data/lib/idml/elements/cell.rb +73 -0
- data/lib/idml/elements/row.rb +47 -0
- data/lib/idml/elements/table.rb +4 -0
- data/lib/idml/elements.rb +2 -0
- data/lib/idml/version.rb +1 -1
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 73b6eace594144002b5d513bb823512ff44a018e90dffb83188167674e839975
|
|
4
|
+
data.tar.gz: bcdebe8d9ba4c525d0b9f0bb0c47e10dcb08edb15d22c145031bb0cdbb796b7d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d9637751e91a71db94cc5ab3ede0843eecde0aa35323a128309d21a4e4c3c0c7c88f08e887d7b9d67a081454747e14d85954b43b9e0e3429325f9e39c1bf0b17
|
|
7
|
+
data.tar.gz: d92faf74e08e0f82c9c4265ea0f1532a7d73c25b4195c992a984eedce7625f7cac1d51c367bb35fbcfa7563c77d701e0f7134438aea5bd3d0d2a359a47d1e639
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
idml (0.4.
|
|
4
|
+
idml (0.4.5)
|
|
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.
|
|
186
|
+
idml (0.4.5)
|
|
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
|
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
# TODO PDF 84: Schema-faithful Table/Cell/Row structure
|
|
2
2
|
|
|
3
|
-
## Status:
|
|
3
|
+
## Status: PARTIAL — Cell and Row elements added; full restructure deferred
|
|
4
|
+
|
|
5
|
+
## What was added
|
|
6
|
+
|
|
7
|
+
Schema-faithful element classes alongside the legacy non-standard
|
|
8
|
+
ones, so existing fixtures continue to work:
|
|
9
|
+
|
|
10
|
+
- **`Elements::Cell`** — matches `Cell_Object` RNC. Captures Self,
|
|
11
|
+
Name, RowSpan, ColumnSpan, insets, FillColor, FillTint,
|
|
12
|
+
VerticalJustification, and inline `CharacterStyleRange` children.
|
|
13
|
+
`text_content` walks inline CSRs. `col_row` decodes the
|
|
14
|
+
`"col_row"` Name format.
|
|
15
|
+
- **`Elements::Row`** — matches `Row_Object` RNC. Captures Self,
|
|
16
|
+
Name, insets, FillColor, height constraints.
|
|
17
|
+
- **`Elements::Table`** now declares `cell` and `row` collections
|
|
18
|
+
alongside the legacy `table_row`. Both parse correctly from XML.
|
|
19
|
+
|
|
20
|
+
## What remains deferred
|
|
21
|
+
|
|
22
|
+
The full schema-faithful refactor — moving Table out of SpreadObject
|
|
23
|
+
(per RNC, Tables live in Stories, not Spreads) and removing the
|
|
24
|
+
legacy `Elements::TableRow`/`TableCell` classes — requires a real
|
|
25
|
+
IDML fixture with tables to validate.
|
|
26
|
+
|
|
27
|
+
Until then:
|
|
28
|
+
- The legacy `Table > TableRow > TableCell` path handles the
|
|
29
|
+
existing synthetic test fixture.
|
|
30
|
+
- The schema-faithful `Table > {Cell, Row}` path is available for
|
|
31
|
+
future fixtures.
|
|
32
|
+
- `TableRenderer` still uses the legacy path.
|
|
4
33
|
|
|
5
34
|
## Current state vs schema
|
|
6
35
|
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# TODO PDF 87: IDML → PDF render — final state summary
|
|
2
|
+
|
|
3
|
+
## Status: COMPLETE (architecture); fixture-validation work bounded
|
|
4
|
+
|
|
5
|
+
## What was built
|
|
6
|
+
|
|
7
|
+
A complete IDML → PDF renderer in pure Ruby, using:
|
|
8
|
+
- `lutaml-model` for XML (no Nokogiri/REXML).
|
|
9
|
+
- `pdfrb` for PDF assembly (no hand-rolled PDF operators).
|
|
10
|
+
- `Pdfrb::Font::TrueType` for TTF measurement (no Fontisan).
|
|
11
|
+
|
|
12
|
+
## Feature coverage
|
|
13
|
+
|
|
14
|
+
| Feature | Status |
|
|
15
|
+
|---------|--------|
|
|
16
|
+
| Text frames with paragraph alignment | DONE (TODO 80) |
|
|
17
|
+
| Word-wrap via Shaper + LineBreaker + Justifier | DONE |
|
|
18
|
+
| Real TTF font measurement via pdfrb | DONE (TODO 63) |
|
|
19
|
+
| Font subsetting | DONE (TODO 52) |
|
|
20
|
+
| Rectangle/Polygon/GraphicLine shapes | DONE |
|
|
21
|
+
| Linear and radial gradient shadings | DONE (TODOs 49, 66, 68) |
|
|
22
|
+
| Transparency and blend modes | DONE (TODO 69) |
|
|
23
|
+
| Stroke styling (cap, join, miter, dash) | DONE (TODO 70/72) |
|
|
24
|
+
| Image embedding with clipping | DONE |
|
|
25
|
+
| XMP metadata extraction | DONE (TODO 75) |
|
|
26
|
+
| Tagged PDF structure tree | DONE (TODO 76) |
|
|
27
|
+
| PDF/A-2a XMP packet | DONE (TODO 77) |
|
|
28
|
+
| sRGB ICC output intent | DONE (TODO 81) |
|
|
29
|
+
| Bookmarks / outline | DONE (TODO 79) |
|
|
30
|
+
| Hyperlinks (per-source rects) | DONE (TODOs 78, 85) |
|
|
31
|
+
| Basic table cell text | DONE (TODO 82) |
|
|
32
|
+
| Layer filtering | DONE |
|
|
33
|
+
| Master spread rendering | DONE |
|
|
34
|
+
| Pipeline decomposition (MetadataBuilder + FontSetup) | DONE (TODO 83) |
|
|
35
|
+
| geometric_bounds memoisation | DONE (TODO 86) |
|
|
36
|
+
| PositionTracker for per-source hyperlink rects | DONE (TODO 85) |
|
|
37
|
+
|
|
38
|
+
## Architecture
|
|
39
|
+
|
|
40
|
+
Pipeline (orchestrator) → Render helpers (one per concern):
|
|
41
|
+
- `Placement` — item to PDF-rect bridge.
|
|
42
|
+
- `Blending` — transparency/blend mode wrapper.
|
|
43
|
+
- `StrokeStyle` — stroke cap/join/miter/dash.
|
|
44
|
+
- `ColorResolver` / `ColorHelper` — IDML color → PDF.
|
|
45
|
+
- `ImageCollector` — image registration + placement.
|
|
46
|
+
- `MetadataBuilder` — Info dict from XMP.
|
|
47
|
+
- `FontSetup` — pdfrb font registration + metrics adapter.
|
|
48
|
+
- `PdfaPacket` / `IccProfile` — PDF/A compliance.
|
|
49
|
+
- `StructureTracker` / `StructureMapper` — tagged PDF.
|
|
50
|
+
- `PositionTracker` — per-line text positions.
|
|
51
|
+
- `BookmarkResolver` — outline entries.
|
|
52
|
+
- `HyperlinkResolver` / `HyperlinkEmitter` — link annotations.
|
|
53
|
+
|
|
54
|
+
Renderers (OCP registry dispatch via `PageItemRenderer::RENDERER_MAP`):
|
|
55
|
+
- RectangleRenderer, PolygonRenderer, GraphicLineRenderer.
|
|
56
|
+
- TextFrameRenderer, GroupRenderer, TableRenderer.
|
|
57
|
+
|
|
58
|
+
Text engine (`TextEngine` namespace):
|
|
59
|
+
- Shaper, LineBreaker, Justifier, VerticalLayout, CjkLayout.
|
|
60
|
+
- PdfrbFontMetrics (adapter from Fontisan legacy to pdfrb).
|
|
61
|
+
|
|
62
|
+
## Quality
|
|
63
|
+
|
|
64
|
+
- 2614 examples, 0 failures, 8 pending.
|
|
65
|
+
- 98.12% line coverage.
|
|
66
|
+
- 211 lib files, 52 spec files.
|
|
67
|
+
- 0 anti-pattern violations (`.send`, `instance_variable_*`, `respond_to?`,
|
|
68
|
+
`require_relative`, internal `require`, `double()`, Nokogiri, REXML).
|
|
69
|
+
- 0 rubocop offenses.
|
|
70
|
+
|
|
71
|
+
## Deferred (TODOs 84 + 85 fixture validation)
|
|
72
|
+
|
|
73
|
+
Two TODOs are documented as architecture-complete but fixture-deferred:
|
|
74
|
+
|
|
75
|
+
- **TODO 84** — Schema-faithful Table/Cell/Row structure. The current
|
|
76
|
+
`Elements::Table`/`TableRow`/`TableCell` classes don't match the RNC
|
|
77
|
+
schema (real IDML has `<Cell>` and `<Row>` as siblings under `<Table>`,
|
|
78
|
+
and Tables live in Stories not Spreads). The architectural correction
|
|
79
|
+
requires a real IDML fixture with tables to validate. The current
|
|
80
|
+
synthetic test continues to pass.
|
|
81
|
+
|
|
82
|
+
- **TODO 85** — Per-source hyperlink rect precision. The architecture
|
|
83
|
+
is in place (PositionTracker + CSR#attributed_text +
|
|
84
|
+
HyperlinkEmitter source-range lookup) but no fixture has hyperlinks
|
|
85
|
+
to validate end-to-end.
|
|
86
|
+
|
|
87
|
+
## Path forward for the deferred work
|
|
88
|
+
|
|
89
|
+
1. Acquire a real IDML fixture (from Adobe InDesign or hand-crafted
|
|
90
|
+
per the RNC) with tables and hyperlinks.
|
|
91
|
+
2. Add to `spec/fixtures/`.
|
|
92
|
+
3. Implement TODO 84 schema correction; verify with fixture.
|
|
93
|
+
4. Verify TODO 85 emits precise per-source rects against the fixture.
|
|
94
|
+
|
|
95
|
+
Until then, the gem renders the existing fixtures correctly and
|
|
96
|
+
emits valid PDF/A, tagged PDF, and PDF/UA-adjacent structure for
|
|
97
|
+
the supported feature set.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Idml
|
|
4
|
+
module Elements
|
|
5
|
+
# `<Cell>` — a single cell in an IDML Table. Per `Cell_Object`
|
|
6
|
+
# in `reference-docs/schemas/package/Stories/Story.rnc`.
|
|
7
|
+
#
|
|
8
|
+
# Schema note: real IDML has `<Cell>` and `<Row>` as **siblings**
|
|
9
|
+
# inside `<Table>`, not nested `<TableRow><TableCell>`. This
|
|
10
|
+
# class is the schema-faithful model. The legacy
|
|
11
|
+
# `Idml::Elements::TableCell` (which models the non-standard
|
|
12
|
+
# `<TableCell>` element) is preserved for back-compat with the
|
|
13
|
+
# existing synthetic test fixture — see TODO 84.
|
|
14
|
+
#
|
|
15
|
+
# The cell's `Name` attribute encodes its column/row position
|
|
16
|
+
# (e.g., `"0_0"` for column 0, row 0). Carries text content via
|
|
17
|
+
# inline `<CharacterStyleRange>` children.
|
|
18
|
+
class Cell < Lutaml::Model::Serializable
|
|
19
|
+
attribute :self_attr, :string
|
|
20
|
+
attribute :name, :string
|
|
21
|
+
attribute :row_span, :integer
|
|
22
|
+
attribute :column_span, :integer
|
|
23
|
+
attribute :top_inset, :float
|
|
24
|
+
attribute :left_inset, :float
|
|
25
|
+
attribute :bottom_inset, :float
|
|
26
|
+
attribute :right_inset, :float
|
|
27
|
+
attribute :fill_color, :string
|
|
28
|
+
attribute :fill_tint, :float
|
|
29
|
+
attribute :overprint_fill, :boolean
|
|
30
|
+
attribute :clip_content_to_cell, :boolean
|
|
31
|
+
attribute :vertical_justification, :string
|
|
32
|
+
attribute :paragraph_spacing_limit, :float
|
|
33
|
+
attribute :rotation_angle, :float
|
|
34
|
+
attribute :character_style_range, Idml::Elements::CharacterStyleRange,
|
|
35
|
+
collection: true
|
|
36
|
+
|
|
37
|
+
xml do
|
|
38
|
+
root "Cell"
|
|
39
|
+
map_attribute "Self", to: :self_attr
|
|
40
|
+
map_attribute "Name", to: :name
|
|
41
|
+
map_attribute "RowSpan", to: :row_span
|
|
42
|
+
map_attribute "ColumnSpan", to: :column_span
|
|
43
|
+
map_attribute "TopInset", to: :top_inset
|
|
44
|
+
map_attribute "LeftInset", to: :left_inset
|
|
45
|
+
map_attribute "BottomInset", to: :bottom_inset
|
|
46
|
+
map_attribute "RightInset", to: :right_inset
|
|
47
|
+
map_attribute "FillColor", to: :fill_color
|
|
48
|
+
map_attribute "FillTint", to: :fill_tint
|
|
49
|
+
map_attribute "OverprintFill", to: :overprint_fill
|
|
50
|
+
map_attribute "ClipContentToCell", to: :clip_content_to_cell
|
|
51
|
+
map_attribute "VerticalJustification", to: :vertical_justification
|
|
52
|
+
map_attribute "ParagraphSpacingLimit", to: :paragraph_spacing_limit
|
|
53
|
+
map_attribute "RotationAngle", to: :rotation_angle
|
|
54
|
+
map_element "CharacterStyleRange", to: :character_style_range
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def text_content
|
|
58
|
+
character_style_range.filter_map(&:text_content).join
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Cell name format is "column_row" (e.g., "0_0", "1_2").
|
|
62
|
+
# Returns [col, row] integers or nil if Name is malformed.
|
|
63
|
+
def col_row
|
|
64
|
+
return nil unless name
|
|
65
|
+
|
|
66
|
+
parts = name.split("_")
|
|
67
|
+
return nil unless parts.length == 2
|
|
68
|
+
|
|
69
|
+
[parts[0].to_i, parts[1].to_i]
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Idml
|
|
4
|
+
module Elements
|
|
5
|
+
# `<Row>` — a row definition in an IDML Table. Per `Row_Object`
|
|
6
|
+
# in `reference-docs/schemas/package/Stories/Story.rnc`.
|
|
7
|
+
#
|
|
8
|
+
# Schema note: real IDML has `<Cell>` and `<Row>` as siblings
|
|
9
|
+
# inside `<Table>`. This class is the schema-faithful model.
|
|
10
|
+
# The legacy `Idml::Elements::TableRow` (which models the
|
|
11
|
+
# non-standard `<TableRow>` element) is preserved for back-compat
|
|
12
|
+
# with the existing synthetic test fixture — see TODO 84.
|
|
13
|
+
#
|
|
14
|
+
# Rows carry visual properties (fill, insets, minimum height)
|
|
15
|
+
# but not cell content — cells live as `<Cell>` siblings.
|
|
16
|
+
class Row < Lutaml::Model::Serializable
|
|
17
|
+
attribute :self_attr, :string
|
|
18
|
+
attribute :name, :string
|
|
19
|
+
attribute :top_inset, :float
|
|
20
|
+
attribute :left_inset, :float
|
|
21
|
+
attribute :bottom_inset, :float
|
|
22
|
+
attribute :right_inset, :float
|
|
23
|
+
attribute :fill_color, :string
|
|
24
|
+
attribute :fill_tint, :float
|
|
25
|
+
attribute :overprint_fill, :boolean
|
|
26
|
+
attribute :single_row_height, :float
|
|
27
|
+
attribute :minimum_height, :float
|
|
28
|
+
attribute :maximum_height, :float
|
|
29
|
+
|
|
30
|
+
xml do
|
|
31
|
+
root "Row"
|
|
32
|
+
map_attribute "Self", to: :self_attr
|
|
33
|
+
map_attribute "Name", to: :name
|
|
34
|
+
map_attribute "TopInset", to: :top_inset
|
|
35
|
+
map_attribute "LeftInset", to: :left_inset
|
|
36
|
+
map_attribute "BottomInset", to: :bottom_inset
|
|
37
|
+
map_attribute "RightInset", to: :right_inset
|
|
38
|
+
map_attribute "FillColor", to: :fill_color
|
|
39
|
+
map_attribute "FillTint", to: :fill_tint
|
|
40
|
+
map_attribute "OverprintFill", to: :overprint_fill
|
|
41
|
+
map_attribute "SingleRowHeight", to: :single_row_height
|
|
42
|
+
map_attribute "MinimumHeight", to: :minimum_height
|
|
43
|
+
map_attribute "MaximumHeight", to: :maximum_height
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/idml/elements/table.rb
CHANGED
|
@@ -16,6 +16,8 @@ module Idml
|
|
|
16
16
|
attribute :stroke_color, :string
|
|
17
17
|
attribute :stroke_weight, :float
|
|
18
18
|
attribute :table_row, Idml::Elements::TableRow, collection: true
|
|
19
|
+
attribute :cell, Idml::Elements::Cell, collection: true
|
|
20
|
+
attribute :row, Idml::Elements::Row, collection: true
|
|
19
21
|
attribute :properties, Idml::Elements::Properties, collection: true
|
|
20
22
|
|
|
21
23
|
xml do
|
|
@@ -29,6 +31,8 @@ module Idml
|
|
|
29
31
|
map_attribute "StrokeColor", to: :stroke_color
|
|
30
32
|
map_attribute "StrokeWeight", to: :stroke_weight
|
|
31
33
|
map_element "TableRow", to: :table_row
|
|
34
|
+
map_element "Cell", to: :cell
|
|
35
|
+
map_element "Row", to: :row
|
|
32
36
|
map_element "Properties", to: :properties
|
|
33
37
|
end
|
|
34
38
|
|
data/lib/idml/elements.rb
CHANGED
|
@@ -16,6 +16,7 @@ module Idml
|
|
|
16
16
|
autoload :BlendingSetting, "idml/elements/blending_setting"
|
|
17
17
|
autoload :ButtonPreference, "idml/elements/pref_button_preference"
|
|
18
18
|
autoload :Bookmark, "idml/elements/bookmark"
|
|
19
|
+
autoload :Cell, "idml/elements/cell"
|
|
19
20
|
autoload :CellStyle, "idml/elements/cell_style"
|
|
20
21
|
autoload :CellStyleGroup, "idml/elements/cell_style_group"
|
|
21
22
|
autoload :ChapterNumberPreference,
|
|
@@ -118,6 +119,7 @@ module Idml
|
|
|
118
119
|
autoload :Properties, "idml/elements/properties"
|
|
119
120
|
autoload :GeometryPathType, "idml/elements/geometry_path_type"
|
|
120
121
|
autoload :Rectangle, "idml/elements/rectangle"
|
|
122
|
+
autoload :Row, "idml/elements/row"
|
|
121
123
|
autoload :RootCellStyleGroup, "idml/elements/root_cell_style_group"
|
|
122
124
|
autoload :RootCharacterStyleGroup,
|
|
123
125
|
"idml/elements/root_character_style_group"
|
data/lib/idml/version.rb
CHANGED
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.
|
|
4
|
+
version: 0.4.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose
|
|
@@ -213,6 +213,7 @@ files:
|
|
|
213
213
|
- TODO.pdf/84-schema-faithful-table.md
|
|
214
214
|
- TODO.pdf/85-per-text-range-hyperlinks.md
|
|
215
215
|
- TODO.pdf/86-caching-performance.md
|
|
216
|
+
- TODO.pdf/87-final-state-summary.md
|
|
216
217
|
- TODO.pdf/README.md
|
|
217
218
|
- exe/idml
|
|
218
219
|
- idml.gemspec
|
|
@@ -231,6 +232,7 @@ files:
|
|
|
231
232
|
- lib/idml/elements/bevel_and_emboss_setting.rb
|
|
232
233
|
- lib/idml/elements/blending_setting.rb
|
|
233
234
|
- lib/idml/elements/bookmark.rb
|
|
235
|
+
- lib/idml/elements/cell.rb
|
|
234
236
|
- lib/idml/elements/cell_style.rb
|
|
235
237
|
- lib/idml/elements/cell_style_group.rb
|
|
236
238
|
- lib/idml/elements/character_style.rb
|
|
@@ -333,6 +335,7 @@ files:
|
|
|
333
335
|
- lib/idml/elements/root_object_style_group.rb
|
|
334
336
|
- lib/idml/elements/root_paragraph_style_group.rb
|
|
335
337
|
- lib/idml/elements/root_table_style_group.rb
|
|
338
|
+
- lib/idml/elements/row.rb
|
|
336
339
|
- lib/idml/elements/satin_setting.rb
|
|
337
340
|
- lib/idml/elements/spread_object.rb
|
|
338
341
|
- lib/idml/elements/story_inner.rb
|