idml 0.9.2 → 0.9.3

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: eb1bde51604723b865996a34842c6a5216b3c0ce4f55947902aa9dd92358ed25
4
- data.tar.gz: a1e6ed580c3d0fee769287d3619c33fa6e18ed79ee332d1aa0a7976b1352b760
3
+ metadata.gz: b5306c44be037a52666aa508b9cdb76978561403d72bc43896ea8575b3f61340
4
+ data.tar.gz: 1d46f1c6de5f53f564f69ccfc41349d48d12b5f3522b7dfae1d01dc79f92ae00
5
5
  SHA512:
6
- metadata.gz: 989af27c2ad974dac8d370e335e923b70727a0c32991fe67011c2231cd5b526fdf59e73d571df8423ae69e9e27a5fa03dd69cf94a732ec76138cb34188af0792
7
- data.tar.gz: d3daaccd0d51e4a78b825f5ea2f7baf6a3c23c11df1c33eb793b649c23b18bac2255de8e3fc3e3e7d62addac871b77f20879931dac73d6f14fec6fe54c10caea
6
+ metadata.gz: 4d6830d86be109139a52ee6c2d780f31c33488eee4090b6a64ca938c871fd78429d9da7dbd9b7911d2a814e6908c1a05d53b6083abbb6b74c9d04fec141fcf18
7
+ data.tar.gz: '0886ff7d2aea4389f5bd0779151be35e6dd40473c2bec635ca4ff25f10321b196c09b171d104f405c4133ab699cfc008773a11533ad43fd870e755cd29b2e168'
@@ -0,0 +1,33 @@
1
+ # TODO PDF 118: Table alternating row/column band fills
2
+
3
+ ## Status: COMPLETE — implemented 2026-08-18
4
+
5
+ ## Problem
6
+
7
+ IDML tables declare table-level alternating fills —
8
+ StartRowFillColor/Count + EndRowFillColor/Count (row banding),
9
+ StartColumnFillColor/Count + EndColumnFillColor/Count (column
10
+ banding), ColumnFillsPriority (true = column banding wins),
11
+ SkipFirst/LastAlternatingFillRows/Columns (edge suppression), and
12
+ per-band tints. All attributes are modeled (TODO 104) but the
13
+ renderer only honored per-Cell FillColor, so banded tables (zebra
14
+ stripes, ledger shading) rendered without their backgrounds.
15
+
16
+ ## What was done
17
+
18
+ - `SchemaLayout#band_fill(col, row)` computes the effective band
19
+ color + tint for a cell position: row banding by default; column
20
+ banding when ColumnFillsPriority is true or row banding is
21
+ unconfigured; SkipFirst/Last offsets suppress banding at the
22
+ table edges; "Color/None" band colors render nothing.
23
+ - `TableRenderer` paints the band rect behind each cell BEFORE the
24
+ cell's own background — an explicit Cell FillColor overrides the
25
+ band, matching InDesign.
26
+ - `each_cell` now also yields the cell's column/row indices.
27
+
28
+ ## Acceptance criteria
29
+
30
+ - [x] Rows alternate Start/End colors in the declared counts.
31
+ - [x] Cell-level fill overrides the band.
32
+ - [x] Column banding wins when ColumnFillsPriority is true.
33
+ - [x] SkipFirstAlternatingFillRows suppresses leading bands.
@@ -70,7 +70,10 @@ module Idml
70
70
  # derived from `column_count` attribute or max col + 1.
71
71
  def self.render_schema_faithful(canvas, table, box, context)
72
72
  layout = SchemaLayout.new(table: table, box: box)
73
- layout.each_cell do |cell_x, cell_y, cell_w, cell_h, cell|
73
+ layout.each_cell do |cell_x, cell_y, cell_w, cell_h, cell,
74
+ col_idx, row_idx|
75
+ render_band_background(canvas, cell, layout, col_idx, row_idx,
76
+ cell_x, cell_y, cell_w, cell_h, context)
74
77
  render_cell_background(canvas, cell, cell_x, cell_y, cell_w, cell_h,
75
78
  context)
76
79
  render_cell_border(canvas, cell_x, cell_y, cell_w, cell_h)
@@ -79,6 +82,27 @@ module Idml
79
82
  end
80
83
  private_class_method :render_schema_faithful
81
84
 
85
+ # Table-level alternating band fill behind a cell. An
86
+ # explicit Cell FillColor wins; Color/None bands and zero
87
+ # tints render nothing.
88
+ def self.render_band_background(canvas, cell, layout, col_idx,
89
+ row_idx, x, y, w, h, context)
90
+ return if cell_fill_color(cell, context)
91
+
92
+ name, tint = layout.band_fill(col_idx, row_idx)
93
+ return unless name
94
+ return if name == "Color/None"
95
+
96
+ color = context.color_resolver&.resolve(name)
97
+ return unless color
98
+
99
+ color = ColorHelper.apply_tint(color, tint)
100
+ canvas.fill_color(ColorHelper.to_canvas(color))
101
+ canvas.rectangle(x, y, w, h)
102
+ canvas.fill
103
+ end
104
+ private_class_method :render_band_background
105
+
82
106
  def self.render_cell_background(canvas, cell, x, y, w, h, context)
83
107
  color = cell_fill_color(cell, context)
84
108
  return unless color
@@ -244,7 +268,7 @@ module Idml
244
268
 
245
269
  yield cell_x(col_idx), cell_y(row_idx, col_span, row_span),
246
270
  cell_w(col_idx, col_span), cell_h(row_idx, row_span),
247
- cell
271
+ cell, col_idx, row_idx
248
272
  end
249
273
  end
250
274
  end
@@ -269,6 +293,79 @@ module Idml
269
293
  table.row
270
294
  end
271
295
 
296
+ # Table-level alternating band fill for a cell position:
297
+ # [color_name, tint] or nil. Row banding by default; column
298
+ # banding when ColumnFillsPriority is true or rows are
299
+ # unconfigured.
300
+ def band_fill(col, row)
301
+ column_band = column_band_fill(col)
302
+ return column_band if column_band &&
303
+ (table.column_fills_priority || row_band_fill(row).nil?)
304
+
305
+ row_band_fill(row)
306
+ end
307
+
308
+ def row_band_fill(row)
309
+ band_pair(table.start_row_fill_color, table.start_row_fill_count,
310
+ table.end_row_fill_color, table.end_row_fill_count,
311
+ table.start_row_fill_tint, table.end_row_fill_tint,
312
+ row, row_count,
313
+ table.skip_first_alternating_fill_rows,
314
+ table.skip_last_alternating_fill_rows)
315
+ end
316
+ private :row_band_fill
317
+
318
+ def column_band_fill(col)
319
+ band_pair(table.start_column_fill_color,
320
+ table.start_column_fill_count,
321
+ table.end_column_fill_color,
322
+ table.end_column_fill_count,
323
+ table.start_column_fill_tint,
324
+ table.end_column_fill_tint,
325
+ col, col_count,
326
+ table.skip_first_alternating_fill_columns,
327
+ table.skip_last_alternating_fill_columns)
328
+ end
329
+ private :column_band_fill
330
+
331
+ # Alternating band for one axis: the first `start_count`
332
+ # positions take the start color, the next `end_count` the
333
+ # end color, repeating from after the skipped edge rows.
334
+ # Zero-count cycles band nothing.
335
+ def band_pair(start_color, start_count, end_color, end_count,
336
+ start_tint, end_tint, index, total,
337
+ skip_first, skip_last)
338
+ return nil unless start_color
339
+ return nil if suppressed?(index, total, skip_first, skip_last)
340
+
341
+ cycle = band_cycle(start_count, end_count)
342
+ return nil unless cycle.positive?
343
+
344
+ if in_start_band?(index, skip_first, cycle, start_count)
345
+ [start_color, start_tint]
346
+ else
347
+ [end_color, end_tint]
348
+ end
349
+ end
350
+ private :band_pair
351
+
352
+ def band_cycle(start_count, end_count)
353
+ (start_count || 1) + (end_count || 1)
354
+ end
355
+ private :band_cycle
356
+
357
+ def in_start_band?(index, skip_first, cycle, start_count)
358
+ ((index - (skip_first || 0)) % cycle) < (start_count || 1)
359
+ end
360
+ private :in_start_band?
361
+
362
+ # Banding suppressed at the leading/trailing edges.
363
+ def suppressed?(index, total, skip_first, skip_last)
364
+ index < (skip_first || 0) ||
365
+ index >= total - (skip_last || 0)
366
+ end
367
+ private :suppressed?
368
+
272
369
  def cells
273
370
  table.cell
274
371
  end
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.9.2"
4
+ VERSION = "0.9.3"
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.9.2
4
+ version: 0.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose
@@ -175,6 +175,7 @@ files:
175
175
  - TODO.pdf/116-applied-style-resolution.md
176
176
  - TODO.pdf/116-justification-last-line.md
177
177
  - TODO.pdf/117-endnote-support.md
178
+ - TODO.pdf/118-table-band-fills.md
178
179
  - TODO.pdf/12-idml-to-pdf-pipeline.md
179
180
  - TODO.pdf/13-cjk-text-layout.md
180
181
  - TODO.pdf/14-page-item-element-models.md