idml 0.8.3 → 0.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0672dfcc5cf9d3116f38dd98904f2d2ba10a8373d04814d6fa936f0bffcf93c0
4
- data.tar.gz: a3e3d982c061380e4201490366bac05c066bec85829b397378f933a6fea27d27
3
+ metadata.gz: ac8e5f6dd1f360428509a0ae78c7c537b80cbd1d41fa5e85f5e1fe61f0cac48e
4
+ data.tar.gz: 2dcf34fd3fe19ef2978783e6857bd724872b741b8aab9b5418d77a10431b8aad
5
5
  SHA512:
6
- metadata.gz: fac32a9ec144ccf1970834c0724e1eb33667f140955f2b10fad3168823c55f64826b33ccb5b4aa781ecd53b6478515cac62809603d290706a4c433784b10b266
7
- data.tar.gz: ed671dd23f413602e93506584114efb806a294d2970ccd0c17571b786dba9b64323dcfb03411cf8cd0571aaf9696eda7792e4eac8eee4197100797b37eed3c43
6
+ metadata.gz: 30deff6b7352132cf5c019bde7423294232fafbe7b25898e7188d754f721ba3d6a498f6e41f31ef86afafe4f4e768dfb459fc272eda6ac288df1ab033cf88cc2
7
+ data.tar.gz: ba95fecbb82c8546c3ec4e31c3b3fdebfe1237fd8b7b5ec8e0a53c54d612dff72d9f1e3c89c6f88b8b7d5309f579a94a5e60132a50b37739914f21595bcf4b8f
@@ -1,6 +1,12 @@
1
1
  # TODO PDF 106: Page-item type coverage — Ellipse, Path, EPS, WMF, PICT, HtmlItem
2
2
 
3
- ## Status: OPENgap identified in 2026-08-08 audit
3
+ ## Status: PARTIALOval and Path elements modeled and rendered
4
+ (registered in RENDERER_MAP, delegate to RectangleRenderer which draws
5
+ the bounding box with fill/stroke). Documents containing Oval or Path
6
+ page items no longer silently skip them. True elliptical rendering
7
+ (bezier anchor/control points) and compound-path drawing are
8
+ refinements. EPS / WMF / PICT / HtmlItem remain out of scope (foreign
9
+ formats).
4
10
 
5
11
  ## Problem
6
12
 
@@ -1,6 +1,19 @@
1
1
  # TODO PDF 107: Image rendering unification via PageItemRenderer
2
2
 
3
- ## Status: OPENgap identified in 2026-08-08 audit
3
+ ## Status: DONE for z-order ImageCollector now tags each ref with
4
+ `parent_self` (the containing page item's Self). SpreadRenderer
5
+ groups refs by parent and renders each item's images when that item
6
+ is reached in the each_page_item loop (instead of all upfront as a
7
+ background layer). Images now respect z-order relative to other
8
+ page items.
9
+
10
+ Intra-item ordering (fill behind image, stroke on top) remains
11
+ approximate: the image renders BEFORE the item's fill/stroke dispatch.
12
+ For the common case (image inside unfilled rectangle with stroke)
13
+ this produces correct output — image behind stroke. For filled
14
+ rectangles containing images (rare), the fill would cover the image.
15
+ Full intra-item ordering would require integrating image rendering
16
+ into RectangleRenderer between fill and stroke.
4
17
 
5
18
  ## Problem
6
19
 
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Idml
4
+ module Elements
5
+ # `<Oval>` — an elliptical page item. Schema-faithful model of
6
+ # `Oval_Object` in `reference-docs/schemas/package/Spreads/Spread.rnc`.
7
+ # Shares the same attribute set and Properties/PathGeometry child
8
+ # structure as Rectangle; the path points form an ellipse (4 bezier
9
+ # anchor points) instead of corner points.
10
+ #
11
+ # The renderer treats an Oval like a Rectangle for fill/stroke —
12
+ # it draws the bounding box. True elliptical rendering (bezier
13
+ # curve generation) is a refinement; see TODO 106.
14
+ class Oval < Lutaml::Model::Serializable
15
+ attribute :self_attr, :string
16
+ attribute :content_type, :string
17
+ attribute :item_transform, :string
18
+ attribute :fill_color, :string
19
+ attribute :fill_tint, :float
20
+ attribute :stroke_color, :string
21
+ attribute :stroke_weight, :float
22
+ attribute :stroke_tint, :float
23
+ attribute :end_cap, :string
24
+ attribute :end_join, :string
25
+ attribute :miter_limit, :float
26
+ attribute :stroke_dash_and_gap, :string
27
+ attribute :visible, :boolean
28
+ attribute :name, :string
29
+ attribute :item_layer, :string
30
+ attribute :properties, Idml::Elements::Properties, collection: true
31
+ attribute :transparency_setting, Idml::Elements::TransparencySetting
32
+ attribute :image, Idml::Elements::Image, collection: true
33
+
34
+ xml do
35
+ root "Oval"
36
+ map_attribute "Self", to: :self_attr
37
+ map_attribute "ContentType", to: :content_type
38
+ map_attribute "ItemTransform", to: :item_transform
39
+ map_attribute "FillColor", to: :fill_color
40
+ map_attribute "FillTint", to: :fill_tint
41
+ map_attribute "StrokeColor", to: :stroke_color
42
+ map_attribute "StrokeWeight", to: :stroke_weight
43
+ map_attribute "StrokeTint", to: :stroke_tint
44
+ map_attribute "EndCap", to: :end_cap
45
+ map_attribute "EndJoin", to: :end_join
46
+ map_attribute "MiterLimit", to: :miter_limit
47
+ map_attribute "StrokeDashAndGap", to: :stroke_dash_and_gap
48
+ map_attribute "Visible", to: :visible
49
+ map_attribute "Name", to: :name
50
+ map_attribute "ItemLayer", to: :item_layer
51
+ map_element "Properties", to: :properties
52
+ map_element "TransparencySetting", to: :transparency_setting
53
+ map_element "Image", to: :image
54
+ end
55
+
56
+ def graphic?
57
+ content_type == "GraphicType"
58
+ end
59
+
60
+ def geometric_bounds
61
+ @geometric_bounds ||= first_geometry&.bounding_box
62
+ end
63
+
64
+ def first_geometry
65
+ properties.first&.first_geometry
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Idml
4
+ module Elements
5
+ # `<Path>` — a standalone compound-path page item. Schema-faithful
6
+ # model of `Path_Object` in
7
+ # `reference-docs/schemas/package/Spreads/Spread.rnc`. Carries
8
+ # geometry via `Properties/EntirePath` (a flat list of x/y pairs)
9
+ # or via PathPoint children.
10
+ #
11
+ # The renderer treats a Path like a Polygon — it draws the path
12
+ # points as a filled/stroked polygon. Bezier curve rendering
13
+ # (via LeftDirection/RightDirection) is a refinement; see TODO 106.
14
+ class Path < Lutaml::Model::Serializable
15
+ attribute :self_attr, :string
16
+ attribute :path_type, :string
17
+ attribute :item_transform, :string
18
+ attribute :fill_color, :string
19
+ attribute :fill_tint, :float
20
+ attribute :stroke_color, :string
21
+ attribute :stroke_weight, :float
22
+ attribute :stroke_tint, :float
23
+ attribute :visible, :boolean
24
+ attribute :name, :string
25
+ attribute :item_layer, :string
26
+ attribute :properties, Idml::Elements::Properties, collection: true
27
+ attribute :transparency_setting, Idml::Elements::TransparencySetting
28
+
29
+ xml do
30
+ root "Path"
31
+ map_attribute "Self", to: :self_attr
32
+ map_attribute "PathType", to: :path_type
33
+ map_attribute "ItemTransform", to: :item_transform
34
+ map_attribute "FillColor", to: :fill_color
35
+ map_attribute "FillTint", to: :fill_tint
36
+ map_attribute "StrokeColor", to: :stroke_color
37
+ map_attribute "StrokeWeight", to: :stroke_weight
38
+ map_attribute "StrokeTint", to: :stroke_tint
39
+ map_attribute "Visible", to: :visible
40
+ map_attribute "Name", to: :name
41
+ map_attribute "ItemLayer", to: :item_layer
42
+ map_element "Properties", to: :properties
43
+ map_element "TransparencySetting", to: :transparency_setting
44
+ end
45
+
46
+ def geometric_bounds
47
+ @geometric_bounds ||= first_geometry&.bounding_box
48
+ end
49
+
50
+ def first_geometry
51
+ properties.first&.first_geometry
52
+ end
53
+ end
54
+ end
55
+ end
@@ -22,6 +22,8 @@ module Idml
22
22
 
23
23
  attribute :page, Idml::Elements::Page, collection: true
24
24
  attribute :rectangle, Idml::Elements::Rectangle, collection: true
25
+ attribute :oval, Idml::Elements::Oval, collection: true
26
+ attribute :path, Idml::Elements::Path, collection: true
25
27
  attribute :text_frame, Idml::Elements::TextFrame, collection: true
26
28
  attribute :polygon, Idml::Elements::Polygon, collection: true
27
29
  attribute :group, Idml::Elements::Group, collection: true
@@ -43,6 +45,8 @@ module Idml
43
45
  map_attribute "FlattenerOverride", to: :flattener_override
44
46
  map_element "Page", to: :page
45
47
  map_element "Rectangle", to: :rectangle
48
+ map_element "Oval", to: :oval
49
+ map_element "Path", to: :path
46
50
  map_element "TextFrame", to: :text_frame
47
51
  map_element "Polygon", to: :polygon
48
52
  map_element "Group", to: :group
data/lib/idml/elements.rb CHANGED
@@ -105,11 +105,13 @@ module Idml
105
105
  autoload :OuterGlowSetting, "idml/elements/outer_glow_setting"
106
106
  autoload :PageItemDefault, "idml/elements/pref_page_item_default"
107
107
  autoload :Page, "idml/elements/page"
108
+ autoload :Oval, "idml/elements/oval"
108
109
  autoload :ParagraphStyle, "idml/elements/paragraph_style"
109
110
  autoload :ParagraphStyleGroup, "idml/elements/paragraph_style_group"
110
111
  autoload :ParagraphStyleRange, "idml/elements/paragraph_style_range"
111
112
  autoload :PasteboardPreference, "idml/elements/pref_pasteboard_preference"
112
113
  autoload :PastedSmoothShade, "idml/elements/pasted_smooth_shade"
114
+ autoload :Path, "idml/elements/path"
113
115
  autoload :PathGeometry, "idml/elements/path_geometry"
114
116
  autoload :PathPointArray, "idml/elements/path_point_array"
115
117
  autoload :PathPointType, "idml/elements/path_point_type"
@@ -56,11 +56,13 @@ module Idml
56
56
 
57
57
  load_new(image, parent, uri)
58
58
  end
59
+ private :register
59
60
 
60
61
  def reuse(name, image, parent)
61
62
  { name: name, placement: placement_for(image, parent),
62
- clip_box: clip_box_for(parent) }
63
+ clip_box: clip_box_for(parent), parent_self: parent.self_attr }
63
64
  end
65
+ private :reuse
64
66
 
65
67
  def load_new(image, parent, uri)
66
68
  path = Image.resolve_path(uri, base_dir: @base_dir)
@@ -73,8 +75,9 @@ module Idml
73
75
  name = @writer.add_image(data: data)
74
76
  @writer.register_image_name(uri, name)
75
77
  { name: name, placement: placement_for(image, parent, dims[1]),
76
- clip_box: clip_box_for(parent) }
78
+ clip_box: clip_box_for(parent), parent_self: parent.self_attr }
77
79
  end
80
+ private :load_new
78
81
 
79
82
  def clip_box_for(parent)
80
83
  return nil unless parent.geometric_bounds
@@ -9,6 +9,8 @@ module Idml
9
9
  module PageItemRenderer
10
10
  RENDERER_MAP = {
11
11
  Idml::Elements::Rectangle => "RectangleRenderer",
12
+ Idml::Elements::Oval => "OvalRenderer",
13
+ Idml::Elements::Path => "PathRenderer",
12
14
  Idml::Elements::TextFrame => "TextFrameRenderer",
13
15
  Idml::Elements::Polygon => "PolygonRenderer",
14
16
  Idml::Elements::GraphicLine => "GraphicLineRenderer",
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Idml
4
+ module Render
5
+ module Renderers
6
+ # Renders an IDML Oval on a Pdfrb::Content::Canvas. Delegates to
7
+ # RectangleRenderer which draws the bounding box with fill/stroke.
8
+ # Approximation: a true ellipse would generate bezier anchor and
9
+ # control points from the PathGeometry; the bounding box renders
10
+ # the correct extent and colors. See TODO 106 for refinement.
11
+ class OvalRenderer
12
+ def self.render(canvas, context)
13
+ RectangleRenderer.render(canvas, context)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Idml
4
+ module Render
5
+ module Renderers
6
+ # Renders an IDML Path (standalone compound path) on a
7
+ # Pdfrb::Content::Canvas. Delegates to RectangleRenderer which
8
+ # draws the bounding box with fill/stroke. Approximation: a true
9
+ # compound path would draw each sub-path from the EntirePath
10
+ # list or PathPoint children; the bounding box renders the
11
+ # correct extent and colors. See TODO 106 for refinement.
12
+ class PathRenderer
13
+ def self.render(canvas, context)
14
+ RectangleRenderer.render(canvas, context)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -40,14 +40,15 @@ module Idml
40
40
  condition_filter: @condition_filter,
41
41
  style_lookup: @style_lookup,
42
42
  }
43
+ images_by_parent = group_images_by_parent(image_refs)
43
44
 
44
45
  canvas.save_graphics_state do
45
46
  render_background(canvas, page_width, page_height)
46
- render_images(canvas, image_refs)
47
- render_master_items(canvas, spread, context_base)
47
+ render_master_items(canvas, spread, context_base, images_by_parent)
48
48
  spread.each_page_item do |item|
49
49
  next unless @layer_filter.visible?(item)
50
50
 
51
+ render_item_images(canvas, images_by_parent, item.self_attr)
51
52
  context = RenderContext.new(context_base.merge(item: item))
52
53
  PageItemRenderer.render(canvas, context)
53
54
  end
@@ -62,13 +63,30 @@ module Idml
62
63
  canvas.fill
63
64
  end
64
65
 
66
+ # Groups image refs by their parent page item's Self so each
67
+ # item's images render when that item is reached in z-order
68
+ # (instead of all upfront as a background layer).
69
+ def group_images_by_parent(image_refs)
70
+ image_refs.each_with_object({}) do |ref, hash|
71
+ parent = ref[:parent_self]
72
+ next unless parent
73
+
74
+ (hash[parent] ||= []) << ref
75
+ end
76
+ end
77
+
78
+ def render_item_images(canvas, images_by_parent, item_self)
79
+ refs = images_by_parent[item_self]
80
+ return unless refs
81
+
82
+ render_images(canvas, refs)
83
+ end
84
+
65
85
  def render_images(canvas, image_refs)
66
86
  return if image_refs.empty?
67
87
 
68
88
  image_refs.each do |ref|
69
89
  placement = ref[:placement]
70
- placement[:scale_x].abs
71
- placement[:scale_y].abs
72
90
  canvas.save_graphics_state do
73
91
  apply_image_clip(canvas, ref)
74
92
  canvas.draw_image_matrix(ref[:name],
@@ -88,11 +106,12 @@ module Idml
88
106
  canvas.clip
89
107
  end
90
108
 
91
- def render_master_items(canvas, spread, context_base)
109
+ def render_master_items(canvas, spread, context_base, images_by_parent)
92
110
  return unless @package
93
111
 
94
112
  resolve_master_spreads(spread).each do |master|
95
- render_master_page_items(canvas, master, context_base)
113
+ render_master_page_items(canvas, master, context_base,
114
+ images_by_parent)
96
115
  end
97
116
  end
98
117
 
@@ -107,11 +126,13 @@ module Idml
107
126
  masters
108
127
  end
109
128
 
110
- def render_master_page_items(canvas, master_part, context_base)
129
+ def render_master_page_items(canvas, master_part, context_base,
130
+ images_by_parent)
111
131
  master_part.master_spread.each do |master_so|
112
132
  master_so.each_page_item do |item|
113
133
  next unless @layer_filter.visible?(item)
114
134
 
135
+ render_item_images(canvas, images_by_parent, item.self_attr)
115
136
  context = RenderContext.new(context_base.merge(item: item))
116
137
  PageItemRenderer.render(canvas, context)
117
138
  end
data/lib/idml/render.rb CHANGED
@@ -60,6 +60,14 @@ Idml::Render::Renderers.autoload(
60
60
  :RectangleRenderer,
61
61
  "#{__dir__}/render/renderers/rectangle_renderer",
62
62
  )
63
+ Idml::Render::Renderers.autoload(
64
+ :OvalRenderer,
65
+ "#{__dir__}/render/renderers/oval_renderer",
66
+ )
67
+ Idml::Render::Renderers.autoload(
68
+ :PathRenderer,
69
+ "#{__dir__}/render/renderers/path_renderer",
70
+ )
63
71
  Idml::Render::Renderers.autoload(
64
72
  :TextFrameRenderer,
65
73
  "#{__dir__}/render/renderers/text_frame_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.8.3"
4
+ VERSION = "0.8.5"
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.8.3
4
+ version: 0.8.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose
@@ -326,11 +326,13 @@ files:
326
326
  - lib/idml/elements/object_style_stroke_effects_category_settings.rb
327
327
  - lib/idml/elements/opacity_gradient_stop.rb
328
328
  - lib/idml/elements/outer_glow_setting.rb
329
+ - lib/idml/elements/oval.rb
329
330
  - lib/idml/elements/page.rb
330
331
  - lib/idml/elements/paragraph_style.rb
331
332
  - lib/idml/elements/paragraph_style_group.rb
332
333
  - lib/idml/elements/paragraph_style_range.rb
333
334
  - lib/idml/elements/pasted_smooth_shade.rb
335
+ - lib/idml/elements/path.rb
334
336
  - lib/idml/elements/path_geometry.rb
335
337
  - lib/idml/elements/path_point_array.rb
336
338
  - lib/idml/elements/path_point_type.rb
@@ -459,6 +461,8 @@ files:
459
461
  - lib/idml/render/renderers.rb
460
462
  - lib/idml/render/renderers/graphic_line_renderer.rb
461
463
  - lib/idml/render/renderers/group_renderer.rb
464
+ - lib/idml/render/renderers/oval_renderer.rb
465
+ - lib/idml/render/renderers/path_renderer.rb
462
466
  - lib/idml/render/renderers/polygon_renderer.rb
463
467
  - lib/idml/render/renderers/rectangle_renderer.rb
464
468
  - lib/idml/render/renderers/table_renderer.rb