From 4770ea70ba66ccdfa7ebd15b32ec7792d7deec90 Mon Sep 17 00:00:00 2001
From: Andrej Sandorf <77627197+as-op@users.noreply.github.com>
Date: Mon, 10 Jun 2024 16:34:30 +0200
Subject: [PATCH] fix(tables): better image handling in table autosizing (#8)
* fix(tables): better image handling in table autosizing
---
lib/md_to_pdf/elements/blockquote.rb | 4 +-
lib/md_to_pdf/elements/html.rb | 26 +-
lib/md_to_pdf/elements/image.rb | 4 +-
lib/md_to_pdf/elements/table.rb | 12 +-
.../ext/prawn-table/table/cell/cell/image.rb | 14 +-
lib/md_to_pdf/ext/prawn-table/table/table.rb | 16 +-
lib/md_to_pdf/utils/common.rb | 8 +
spec/fixtures/image/html.md | 3 +
spec/fixtures/image/image.md | 2 +-
spec/fixtures/image/in_table.md | 8 +-
spec/fixtures/image/large_in_table.md | 8 +
spec/markdown_to_pdf/image_spec.rb | 271 ++++++++++++++----
spec/pdf_helpers.rb | 23 +-
13 files changed, 311 insertions(+), 88 deletions(-)
create mode 100644 spec/fixtures/image/large_in_table.md
diff --git a/lib/md_to_pdf/elements/blockquote.rb b/lib/md_to_pdf/elements/blockquote.rb
index 6628163..666f9d2 100644
--- a/lib/md_to_pdf/elements/blockquote.rb
+++ b/lib/md_to_pdf/elements/blockquote.rb
@@ -31,7 +31,7 @@ def draw_blockquote(node, opts)
def data_blockquote_paragraph(node, opts)
cell_data = data_node_children(node, opts)
- [make_table_cell_or_subtable(cell_data, opts, :left)]
+ [make_table_cell_or_subtable(cell_data, opts, :left, 1)]
end
def data_blockquote_list(node, opts)
@@ -40,7 +40,7 @@ def data_blockquote_list(node, opts)
sub.to_a.each do |paragraph|
cell_data = data_node_children(paragraph, opts)
unless cell_data.empty?
- cell = make_table_cell_or_subtable(cell_data, opts, :left)
+ cell = make_table_cell_or_subtable(cell_data, opts, :left, 1)
result.push(cell)
end
end
diff --git a/lib/md_to_pdf/elements/html.rb b/lib/md_to_pdf/elements/html.rb
index d0e02f7..925ce05 100644
--- a/lib/md_to_pdf/elements/html.rb
+++ b/lib/md_to_pdf/elements/html.rb
@@ -105,7 +105,7 @@ def data_inlinehtml_tag(tag, node, opts)
when 'comment'
# ignore html comments
when 'img'
- result.push({ image: sub.attr('src') })
+ result.push(data_inline_image_tag(sub, node, opts))
when 'ul', 'ol'
result.concat(data_inlinehtml_list_tag(sub, node, opts))
when 'label', 'p', 'li'
@@ -126,6 +126,27 @@ def data_inlinehtml_tag(tag, node, opts)
result
end
+ def data_image_style_opts(tag, _node, _opts)
+ result = {}
+ if tag.attr("style")
+ image_styles = tag.attr("style").split(';').to_h do |pair|
+ k, v = pair.split(':', 2)
+ [k, v]
+ end
+ if image_styles['width']
+ custom_max_width = parse_pt(image_styles['width'])
+ result[:custom_max_width] = custom_max_width unless custom_max_width.nil? || custom_max_width <= 0
+ end
+ end
+ result[:image_classes] = tag.attr('class')
+ result[:image_caption] = find_img_caption(tag)
+ result
+ end
+
+ def data_inline_image_tag(tag, node, opts)
+ { image: tag.attr('src') }.merge(data_image_style_opts(tag, node, opts))
+ end
+
def data_inlinehtml_list_tag(tag, node, opts)
result = []
points, level, _list_style, content_opts = data_html_list(tag, node, opts)
@@ -188,7 +209,8 @@ def draw_html_tag(tag, node, opts)
tag.children.each do |sub|
case sub.name
when 'img'
- embed_image(sub.attr('src'), node, current_opts.merge({ image_classes: sub.attr('class'), image_caption: find_img_caption(sub) }))
+ embed_image(sub.attr('src'), node, current_opts
+ .merge(data_image_style_opts(sub, node, current_opts)))
when 'text'
@pdf.formatted_text([text_hash(sub.text, current_opts)])
when 'a'
diff --git a/lib/md_to_pdf/elements/image.rb b/lib/md_to_pdf/elements/image.rb
index 143da46..1b7aabe 100644
--- a/lib/md_to_pdf/elements/image.rb
+++ b/lib/md_to_pdf/elements/image.rb
@@ -55,11 +55,9 @@ def build_image_settings(style, image_info, opts)
end
def build_image_opts(style, image_info, image_margin_opts, opts)
- max_width = opt_image_max_width(style)
options = opts_image(style)
width = @pdf.bounds.width - (image_margin_opts[:left_margin] || 0) - (image_margin_opts[:right_margin] || 0)
- width = [max_width, width].min unless max_width.nil?
- width = [image_info.width, width].min
+ width = [image_info.width, opt_image_max_width(style), opts[:custom_max_width], width].compact.min
options[:scale] = [width / image_info.width.to_f, 1].min
options[:position] = :right if (opts[:image_classes] || '') =~ /\bright\b/
options
diff --git a/lib/md_to_pdf/elements/table.rb b/lib/md_to_pdf/elements/table.rb
index a1e619a..36aa429 100644
--- a/lib/md_to_pdf/elements/table.rb
+++ b/lib/md_to_pdf/elements/table.rb
@@ -147,7 +147,7 @@ def build_pdf_table(table, cell_style, data, column_alignments)
end
end
- def make_subtable(cell_data, opts, alignment)
+ def make_subtable(cell_data, opts, alignment, column_count)
rows = []
row = []
cell_data.each do |elem|
@@ -155,7 +155,7 @@ def make_subtable(cell_data, opts, alignment)
rows.push([make_subtable_cell(row, opts)]) unless row.empty?
image_file = image_url_to_local_file(elem[:image])
unless image_file.nil? || image_file.empty?
- rows.push([image_in_table_column(image_file, alignment).merge({ borders: [] })])
+ rows.push([image_in_table_column(image_file, alignment).merge({ borders: [], custom_max_width: elem[:custom_max_width] })])
end
row = []
else
@@ -165,7 +165,7 @@ def make_subtable(cell_data, opts, alignment)
rows.push([make_subtable_cell(row, opts)]) unless row.empty?
return make_table_cell([{ text: '' }], opts) if rows.empty?
- @pdf.make_table(rows, {}) do
+ @pdf.make_table(rows, column_widths: [@pdf.bounds.width / column_count]) do
columns(0).align = alignment unless alignment == nil
end
end
@@ -180,20 +180,20 @@ def build_table_data(data_rows, column_alignments, opts)
data_rows.each do |data_row|
cells_row = []
data_row.each_with_index do |cell_data, index|
- cells_row.push(make_table_cell_or_subtable(cell_data, opts, column_alignments[index]))
+ cells_row.push(make_table_cell_or_subtable(cell_data, opts, column_alignments[index], data_row.length))
end
data.push(cells_row)
end
data
end
- def make_table_cell_or_subtable(cell_data, opts, alignment)
+ def make_table_cell_or_subtable(cell_data, opts, alignment, column_count)
image_data = cell_data.find { |elem| elem.key?(:image) }
if image_data
image_file = image_url_to_local_file(image_data[:image])
return image_in_table_column(image_file, alignment) if !(image_file.nil? || image_file.empty?) && cell_data.length === 1
- return make_subtable(cell_data, opts, alignment)
+ return make_subtable(cell_data, opts, alignment, column_count)
end
make_table_cell(cell_data, opts)
end
diff --git a/lib/md_to_pdf/ext/prawn-table/table/cell/cell/image.rb b/lib/md_to_pdf/ext/prawn-table/table/cell/cell/image.rb
index f26a2ea..5329589 100644
--- a/lib/md_to_pdf/ext/prawn-table/table/cell/cell/image.rb
+++ b/lib/md_to_pdf/ext/prawn-table/table/cell/cell/image.rb
@@ -1,15 +1,21 @@
Prawn::Table::Cell::Image.prepend(Module.new do
def initialize(pdf, point, options = {})
@image_options = {}
+ custom_max_width = options.delete(:custom_max_width)
super
- @pdf_object, @image_info = @pdf.build_image_object(@file)
- @natural_width, @natural_height = @image_info.calc_image_dimensions(@image_options)
+ natural_width(custom_max_width) if custom_max_width && custom_max_width > 0 && custom_max_width < @natural_width
+ natural_width(@pdf.bounds.width) if @natural_width > @pdf.bounds.width
+ end
+
+ def natural_width(new_width)
+ @natural_height = @natural_height * (new_width / @natural_width)
+ @natural_width = new_width
end
def width=(new_width)
- @width = new_width
- @height = (@natural_height * (new_width / @natural_width))
+ @width = [new_width, @natural_width].min
+ @height = (@natural_height * (@width / @natural_width))
end
def natural_content_width
diff --git a/lib/md_to_pdf/ext/prawn-table/table/table.rb b/lib/md_to_pdf/ext/prawn-table/table/table.rb
index a950f3e..005ef65 100644
--- a/lib/md_to_pdf/ext/prawn-table/table/table.rb
+++ b/lib/md_to_pdf/ext/prawn-table/table/table.rb
@@ -49,21 +49,23 @@ def distribute_to_available_space(needed)
end
def reduce_to_available_space(needed)
- cols = natural_split_column_widths.each_with_index
- .map { |w, index| { min: w, max: natural_column_widths[index], index: index } }
- .sort_by { |e| -e[:max] }
- steps = needed / natural_split_column_widths.length
+ split_widths = natural_split_column_widths
+ return [[20, split_widths[0] - needed].max] if split_widths.length == 1
- col = cols.first
+ cols = split_widths.each_with_index
+ .map { |w, index| { min: w, max: natural_column_widths[index], index: index } }
+ steps = needed / (split_widths.length * 2)
+
+ col = cols.max_by { |e| e[:max] }
while needed > Prawn::FLOAT_PRECISION
reduce = [steps, needed].min
col[:min] -= reduce
col[:max] -= reduce
needed -= reduce
- col = cols.max_by { |e| e[:max] }
+ col = cols.max_by { |e| e[:min] }
end
- cols.sort_by { |e| e[:index] }.map { |e| e[:min] }
+ cols.map { |e| e[:min] }
end
def recalculate_positions
diff --git a/lib/md_to_pdf/utils/common.rb b/lib/md_to_pdf/utils/common.rb
index f8a5caf..86407fe 100644
--- a/lib/md_to_pdf/utils/common.rb
+++ b/lib/md_to_pdf/utils/common.rb
@@ -58,11 +58,19 @@ def parse_pt(something)
ft2pt(value)
when 'in'
in2pt(value)
+ when 'px'
+ csspx2pt(value)
else
value
end
end
+ def csspx2pt(css_px)
+ # only css pixels are supported, not device pixels
+ # https://github.com/prawnpdf/prawn/pull/879
+ css_px * 0.75
+ end
+
def number_unit(string)
value = string.to_f # => -123.45
unit = string[/[a-zA-Z]+/] # => "min"
diff --git a/spec/fixtures/image/html.md b/spec/fixtures/image/html.md
index 82d3b43..fd23c92 100644
--- a/spec/fixtures/image/html.md
+++ b/spec/fixtures/image/html.md
@@ -1,3 +1,6 @@
+
+
+
# An image in the middle of a headline
diff --git a/spec/fixtures/image/image.md b/spec/fixtures/image/image.md
index 8981fff..75db693 100644
--- a/spec/fixtures/image/image.md
+++ b/spec/fixtures/image/image.md
@@ -1 +1 @@
-Floating text above ![Dummy image](demo.jpg) and below image
+Floating text above ![Dummy image](demo.jpg) and below image ![Dummy image](logo.png)
diff --git a/spec/fixtures/image/in_table.md b/spec/fixtures/image/in_table.md
index 72782d5..08e5c45 100644
--- a/spec/fixtures/image/in_table.md
+++ b/spec/fixtures/image/in_table.md
@@ -3,7 +3,7 @@
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor
-
+
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor
@@ -22,10 +22,10 @@
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor
-
+
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor
-
+
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor
@@ -40,7 +40,7 @@
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
-
+
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor
diff --git a/spec/fixtures/image/large_in_table.md b/spec/fixtures/image/large_in_table.md
new file mode 100644
index 0000000..44ee06b
--- /dev/null
+++ b/spec/fixtures/image/large_in_table.md
@@ -0,0 +1,8 @@
+With image style.width:
+
+Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est L
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est L
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est L
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est L
+
+
+Without image style.width:
+
+Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est L
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est L
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est L
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est L
diff --git a/spec/markdown_to_pdf/image_spec.rb b/spec/markdown_to_pdf/image_spec.rb
index 4da0ca0..0b5c783 100644
--- a/spec/markdown_to_pdf/image_spec.rb
+++ b/spec/markdown_to_pdf/image_spec.rb
@@ -10,93 +10,252 @@
expect_pdf([
{ x: 36.0, y: 747.384, text: "Floating text above" },
{ x: 36.0, y: 306.507, text: "and below image" }])
- expect_images_in_pdf(1)
+ expect_pdf_images([
+ { x: 36.0, y: 315.123, width: 540.0, height: 427.005 },
+ { x: 164.0, y: 215.251, width: 284.0, height: 86.0 }])
end
it 'creates image with classes' do
- generator.parse_file('image/classes.md')
+ generator.parse_file('image/classes.md',
+ {
+ image_classes: {
+ small: { max_width: 100 },
+ left: { margin: 0, align: "left" },
+ center: { margin: 0, align: "center" },
+ right: { margin: 0, align: "right" }
+ }
+ })
expect_pdf([])
- expect_images_in_pdf(3)
+ expect_pdf_images([
+ { x: 36.0, y: 676.925, width: 100.0, height: 79.075 },
+ { x: 256.0, y: 597.85, width: 100.0, height: 79.075 },
+ { x: 476.0, y: 518.775, width: 100.0, height: 79.075 }])
end
it 'creates image by html' do
- generator.parse_file('image/html.md')
+ generator.parse_file('image/html.md', { image: { max_width: 300 } })
expect_pdf([
- { x: 36.0, y: 320.379, text: "An image in the middle of" },
- { x: 36.0, y: 320.379, text: "a headline" },
- { x: 36.0, y: 306.507, text: "•" },
- { x: 43.536, y: 306.507, text: "List 1" },
- { x: 36.0, y: 292.635, text: "•" },
- { x: 43.536, y: 292.635, text: "An image in the middle of" },
- { x: 43.536, y: 326.33809, text: "a list" },
- { x: 36.0, y: 312.46609, text: "•" },
- { x: 43.536, y: 312.46609, text: "List 3" },
+ { x: 36.0, y: 450.85275, text: "An image in the middle of" },
+ { x: 36.0, y: 199.75575, text: "a headline" },
+ { x: 36.0, y: 185.88375, text: "•" },
+ { x: 43.536, y: 185.88375, text: "List 1" },
+ { x: 36.0, y: 172.01175, text: "•" },
+ { x: 43.536, y: 172.01175, text: "An image in the middle of" },
+ { x: 43.536, y: 510.159, text: "a list" },
+ { x: 36.0, y: 496.287, text: "•" },
+ { x: 43.536, y: 496.287, text: "List 3" },
{ x: 41.0, y: 739.756, text: "Quote 1 An image in the middle of" },
{ x: 41.0, y: 288.879, text: "a quote Quote 2" }])
- expect_images_in_pdf(4)
+ expect_pdf_images([
+ { x: 268.5, y: 696.69375, width: 75.0, height: 59.30625 },
+ { x: 156.0, y: 459.46875, width: 300.0, height: 237.225 },
+ { x: 156.0, y: 208.37175, width: 300.0, height: 237.225 },
+ { x: 159.768, y: 518.775, width: 300.0, height: 237.225 },
+ { x: 41.0, y: 309.623, width: 527.35378, height: 417.005 }])
end
it 'creates image by footnote' do
- generator.parse_file('image/footnote.md')
- expect_pdf([{ x: 36.0, y: 320.379, text: "The demo image" }])
- expect_images_in_pdf(1)
+ generator.parse_file('image/footnote.md', { image: { max_width: 100 } })
+ expect_pdf([{ x: 36.0, y: 668.309, text: "The demo image" }])
+ expect_pdf_images([{ x: 256.0, y: 676.925, width: 100.0, height: 79.075 }])
end
it 'creates image with caption' do
- generator.parse_file('image/caption.md', { image: { caption: { align: :center, size: 10 } } })
- expect_pdf([{ x: 264.315, y: 321.815, text: "Image with caption" }])
- expect_images_in_pdf(1)
+ generator.parse_file('image/caption.md', { image: { max_width: 100, caption: { align: :center, size: 10 } } })
+ expect_pdf([{ x: 264.315, y: 669.745, text: "Image with caption" }])
+ expect_pdf_images([{ x: 256.0, y: 676.925, width: 100.0, height: 79.075 }])
end
it 'creates image with figure and caption' do
- generator.parse_file('image/figure.md', { image: { margin_bottom: 100, caption: { align: :center, size: 10 } } })
- expect_pdf([{ x: 273.85, y: 321.815, text: "Dummy image" }])
- expect_images_in_pdf(1)
+ generator.parse_file('image/figure.md', { image: { max_width: 100, margin_bottom: 100, caption: { align: :center, size: 10 } } })
+ expect_pdf([{ x: 273.85, y: 669.745, text: "Dummy image" }])
+ expect_pdf_images([{ x: 256.0, y: 676.925, width: 100.0, height: 79.075 }])
end
it 'creates image in table' do
- generator.parse_file('image/in_table.md', { image: { margin_bottom: 100, caption: { align: :center, size: 10 } } })
+ generator.parse_file('image/in_table.md', { headless_table: { auto_width: true } })
expect_pdf([
{ x: 41.0, y: 739.756, text: "Lorem ipsum dolor sit amet, consetetur" },
{ x: 41.0, y: 725.884, text: "sadipscing elitr, sed diam nonumy eirmod tempor" },
{ x: 41.0, y: 712.012, text: "" },
- { x: 41.0, y: 474.6375, text: "Lorem ipsum dolor sit amet, consetetur" },
- { x: 41.0, y: 460.7655, text: "sadipscing elitr, sed diam nonumy eirmod" },
- { x: 41.0, y: 446.8935, text: "tempor " },
+ { x: 41.0, y: 606.37944, text: "Lorem ipsum dolor sit amet, consetetur" },
+ { x: 41.0, y: 592.50744, text: "sadipscing elitr, sed diam nonumy eirmod" },
+ { x: 41.0, y: 578.63544, text: "tempor " },
{ x: 306.0, y: 744.756, text: "Lorem ipsum dolor sit amet, consetetur sadipscing" },
{ x: 306.0, y: 730.884, text: "elitr, sed diam nonumy eirmod tempor invidunt ut" },
{ x: 306.0, y: 717.012, text: "labore et dolore magna aliquyam erat, sed diam" },
{ x: 306.0, y: 703.14, text: "voluptua. At vero eos et accusam et justo duo" },
{ x: 306.0, y: 689.268, text: "dolores et ea rebum. Stet clita kasd gubergren, no" },
{ x: 306.0, y: 675.396, text: "sea takimata sanctus est L" },
- { x: 36.0, y: 744.756, text: "Lorem ipsum dolor sit amet, consetetur sadipscing" },
- { x: 36.0, y: 730.884, text: "elitr, sed diam nonumy" },
- { x: 311.0, y: 739.756, text: "Lorem ipsum dolor sit amet, consetetur" },
- { x: 311.0, y: 725.884, text: "sadipscing elitr, sed diam nonumy eirmod tempor" },
- { x: 311.0, y: 712.012, text: "" },
- { x: 311.0, y: 474.6375, text: "Lorem ipsum dolor sit amet, consetetur" },
- { x: 311.0, y: 460.7655, text: "sadipscing elitr, sed diam nonumy eirmod" },
- { x: 311.0, y: 446.8935, text: "tempor " },
- { x: 311.0, y: 209.519, text: "Lorem ipsum dolor sit amet, consetetur" },
- { x: 311.0, y: 195.647, text: "sadipscing elitr, sed diam nonumy eirmod tempor" },
- { x: 311.0, y: 181.775, text: "" },
- { x: 36.0, y: 744.756, text: "Lorem ipsum dolor sit amet," },
- { x: 36.0, y: 730.884, text: "consetetur sadipscing elitr, sed" },
- { x: 36.0, y: 717.012, text: "diam nonumy" },
- { x: 216.0, y: 744.756, text: "Lorem ipsum dolor sit amet," },
- { x: 216.0, y: 730.884, text: "consetetur sadipscing elitr, sed" },
- { x: 216.0, y: 717.012, text: "diam nonumy" },
- { x: 401.0, y: 739.756, text: "Lorem ipsum dolor sit amet," },
- { x: 401.0, y: 725.884, text: "consetetur sadipscing elitr, sed" },
- { x: 401.0, y: 712.012, text: "diam nonumy eirmod tempor" },
- { x: 401.0, y: 698.14, text: "invidunt ut labore et dolore" },
- { x: 401.0, y: 684.268, text: "magna aliquyam erat, " },
- { x: 401.0, y: 670.396, text: "" },
- { x: 401.0, y: 504.189, text: "Lorem ipsum dolor sit amet," },
- { x: 401.0, y: 490.317, text: "consetetur sadipscing elitr, sed" },
- { x: 401.0, y: 476.445, text: "diam nonumy eirmod tempor " },
- { x: 41.0, y: 452.573, text: "" },
- { x: 41.0, y: 265.17987, text: "" }])
- expect_images_in_pdf(5)
+ { x: 36.0, y: 559.76344, text: "Lorem ipsum dolor sit amet, consetetur sadipscing" },
+ { x: 36.0, y: 545.89144, text: "elitr, sed diam nonumy" },
+ { x: 311.0, y: 554.76344, text: "Lorem ipsum dolor sit amet, consetetur" },
+ { x: 311.0, y: 540.89144, text: "sadipscing elitr, sed diam nonumy eirmod tempor" },
+ { x: 311.0, y: 527.01944, text: "" },
+ { x: 311.0, y: 421.38687, text: "Lorem ipsum dolor sit amet, consetetur" },
+ { x: 311.0, y: 407.51487, text: "sadipscing elitr, sed diam nonumy eirmod" },
+ { x: 311.0, y: 393.64287, text: "tempor " },
+ { x: 311.0, y: 288.01031, text: "Lorem ipsum dolor sit amet, consetetur" },
+ { x: 311.0, y: 274.13831, text: "sadipscing elitr, sed diam nonumy eirmod tempor" },
+ { x: 311.0, y: 260.26631, text: "" },
+ { x: 36.0, y: 241.39431, text: "Lorem ipsum dolor sit amet, consetetur" },
+ { x: 36.0, y: 227.52231, text: "sadipscing elitr, sed diam nonumy" },
+ { x: 257.324, y: 241.39431, text: "Lorem ipsum dolor sit" },
+ { x: 257.324, y: 227.52231, text: "amet, consetetur" },
+ { x: 257.324, y: 213.65031, text: "sadipscing elitr, sed diam" },
+ { x: 257.324, y: 199.77831, text: "nonumy" },
+ { x: 401.0, y: 236.39431, text: "Lorem ipsum dolor sit amet," },
+ { x: 401.0, y: 222.52231, text: "consetetur sadipscing elitr, sed" },
+ { x: 401.0, y: 208.65031, text: "diam nonumy eirmod tempor" },
+ { x: 401.0, y: 194.77831, text: "invidunt ut labore et dolore" },
+ { x: 401.0, y: 180.90631, text: "magna aliquyam erat, " },
+ { x: 401.0, y: 167.03431, text: "" },
+ { x: 401.0, y: 88.65527, text: "Lorem ipsum dolor sit amet," },
+ { x: 401.0, y: 74.78327, text: "consetetur sadipscing elitr, sed" },
+ { x: 401.0, y: 60.91127, text: "diam nonumy eirmod tempor " },
+ { x: 41.0, y: 739.756, text: "" },
+ { x: 41.0, y: 629.884, text: "" }])
+ expect_pdf_images([
+ { x: 41.0, y: 627.12344, width: 236.97674, height: 71.76056 },
+ { x: 311.0, y: 442.13087, width: 236.97674, height: 71.76056 },
+ { x: 311.0, y: 308.75431, width: 236.97674, height: 71.76056 },
+ { x: 401.0, y: 109.39927, width: 146.97674, height: 44.50704 },
+ { x: 41.0, y: 650.628, width: 250.97674, height: 76.0 }])
+ end
+
+ it 'creates large image in table' do
+ generator.parse_file('image/large_in_table.md', { headless_table: { auto_width: true } })
+ expect_pdf([
+ { x: 36.0, y: 747.384, text: "With image style.width:" },
+ { x: 41.0, y: 725.884, text: "Lorem ipsum dolor sit amet, consetetur" },
+ { x: 41.0, y: 712.012, text: "sadipscing elitr, sed diam nonumy eirmod" },
+ { x: 41.0, y: 698.14, text: "tempor invidunt ut labore et dolore magna" },
+ { x: 41.0, y: 684.268, text: "aliquyam erat, " },
+ { x: 41.0, y: 505.01362, text: "sed diam voluptua. At vero eos et accusam et" },
+ { x: 41.0, y: 491.14162, text: "justo duo dolores et ea rebum. " },
+ { x: 298.648, y: 730.884, text: "Lorem ipsum dolor sit" },
+ { x: 298.648, y: 717.012, text: "amet, consetetur" },
+ { x: 298.648, y: 703.14, text: "sadipscing elitr, sed diam" },
+ { x: 298.648, y: 689.268, text: "nonumy eirmod tempor" },
+ { x: 298.648, y: 675.396, text: "invidunt ut labore et" },
+ { x: 298.648, y: 661.524, text: "dolore magna aliquyam" },
+ { x: 298.648, y: 647.652, text: "erat, sed diam voluptua." },
+ { x: 298.648, y: 633.78, text: "At vero eos et accusam et" },
+ { x: 298.648, y: 619.908, text: "justo duo dolores et ea" },
+ { x: 298.648, y: 606.036, text: "rebum. Stet clita kasd" },
+ { x: 298.648, y: 592.164, text: "gubergren, no sea" },
+ { x: 298.648, y: 578.292, text: "takimata sanctus est L" },
+ { x: 437.324, y: 730.884, text: "Lorem ipsum dolor sit" },
+ { x: 437.324, y: 717.012, text: "amet, consetetur" },
+ { x: 437.324, y: 703.14, text: "sadipscing elitr, sed diam" },
+ { x: 437.324, y: 689.268, text: "nonumy eirmod tempor" },
+ { x: 437.324, y: 675.396, text: "invidunt ut labore et" },
+ { x: 437.324, y: 661.524, text: "dolore magna aliquyam" },
+ { x: 437.324, y: 647.652, text: "erat, sed diam voluptua." },
+ { x: 437.324, y: 633.78, text: "At vero eos et accusam et" },
+ { x: 437.324, y: 619.908, text: "justo duo dolores et ea" },
+ { x: 437.324, y: 606.036, text: "rebum. Stet clita kasd" },
+ { x: 437.324, y: 592.164, text: "gubergren, no sea" },
+ { x: 437.324, y: 578.292, text: "takimata sanctus est L" },
+ { x: 36.0, y: 472.26962, text: "Stet clita kasd gubergren, no sea takimata" },
+ { x: 36.0, y: 458.39762, text: "sanctus est Lorem ipsum dolor sit amet. Lorem" },
+ { x: 36.0, y: 444.52562, text: "ipsum dolor sit amet, consetetur sadipscing elitr," },
+ { x: 36.0, y: 430.65362, text: "sed diam nonumy eirmod tempor invidunt ut" },
+ { x: 36.0, y: 416.78162, text: "labore et dolore magna aliquyam erat, sed diam" },
+ { x: 36.0, y: 402.90962, text: "voluptua. At vero eos et accusam et justo duo" },
+ { x: 36.0, y: 389.03762, text: "dolores et ea rebum. Stet clita kasd gubergren," },
+ { x: 36.0, y: 375.16562, text: "no sea takimata sanctus est Lorem ipsum dolor" },
+ { x: 36.0, y: 361.29362, text: "sit amet." },
+ { x: 298.648, y: 472.26962, text: "Lorem ipsum dolor sit" },
+ { x: 298.648, y: 458.39762, text: "amet, consetetur" },
+ { x: 298.648, y: 444.52562, text: "sadipscing elitr, sed diam" },
+ { x: 298.648, y: 430.65362, text: "nonumy eirmod tempor" },
+ { x: 298.648, y: 416.78162, text: "invidunt ut labore et" },
+ { x: 298.648, y: 402.90962, text: "dolore magna aliquyam" },
+ { x: 298.648, y: 389.03762, text: "erat, sed diam voluptua." },
+ { x: 298.648, y: 375.16562, text: "At vero eos et accusam et" },
+ { x: 298.648, y: 361.29362, text: "justo duo dolores et ea" },
+ { x: 298.648, y: 347.42162, text: "rebum. Stet clita kasd" },
+ { x: 298.648, y: 333.54962, text: "gubergren, no sea" },
+ { x: 298.648, y: 319.67762, text: "takimata sanctus est L" },
+ { x: 437.324, y: 472.26962, text: "Lorem ipsum dolor sit" },
+ { x: 437.324, y: 458.39762, text: "amet, consetetur" },
+ { x: 437.324, y: 444.52562, text: "sadipscing elitr, sed diam" },
+ { x: 437.324, y: 430.65362, text: "nonumy eirmod tempor" },
+ { x: 437.324, y: 416.78162, text: "invidunt ut labore et" },
+ { x: 437.324, y: 402.90962, text: "dolore magna aliquyam" },
+ { x: 437.324, y: 389.03762, text: "erat, sed diam voluptua." },
+ { x: 437.324, y: 375.16562, text: "At vero eos et accusam et" },
+ { x: 437.324, y: 361.29362, text: "justo duo dolores et ea" },
+ { x: 437.324, y: 347.42162, text: "rebum. Stet clita kasd" },
+ { x: 437.324, y: 333.54962, text: "gubergren, no sea" },
+ { x: 437.324, y: 319.67762, text: "takimata sanctus est L" },
+ { x: 36.0, y: 308.43362, text: "Without image style.width:" },
+ { x: 41.0, y: 739.756, text: "Lorem ipsum dolor sit amet, consetetur" },
+ { x: 41.0, y: 725.884, text: "sadipscing elitr, sed diam nonumy eirmod" },
+ { x: 41.0, y: 712.012, text: "tempor invidunt ut labore et dolore magna" },
+ { x: 41.0, y: 698.14, text: "aliquyam erat, " },
+ { x: 41.0, y: 466.57909, text: "sed diam voluptua. At vero eos et accusam et" },
+ { x: 41.0, y: 452.70709, text: "justo duo dolores et ea rebum. " },
+ { x: 298.648, y: 744.756, text: "Lorem ipsum dolor sit" },
+ { x: 298.648, y: 730.884, text: "amet, consetetur" },
+ { x: 298.648, y: 717.012, text: "sadipscing elitr, sed diam" },
+ { x: 298.648, y: 703.14, text: "nonumy eirmod tempor" },
+ { x: 298.648, y: 689.268, text: "invidunt ut labore et" },
+ { x: 298.648, y: 675.396, text: "dolore magna aliquyam" },
+ { x: 298.648, y: 661.524, text: "erat, sed diam voluptua." },
+ { x: 298.648, y: 647.652, text: "At vero eos et accusam et" },
+ { x: 298.648, y: 633.78, text: "justo duo dolores et ea" },
+ { x: 298.648, y: 619.908, text: "rebum. Stet clita kasd" },
+ { x: 298.648, y: 606.036, text: "gubergren, no sea" },
+ { x: 298.648, y: 592.164, text: "takimata sanctus est L" },
+ { x: 437.324, y: 744.756, text: "Lorem ipsum dolor sit" },
+ { x: 437.324, y: 730.884, text: "amet, consetetur" },
+ { x: 437.324, y: 717.012, text: "sadipscing elitr, sed diam" },
+ { x: 437.324, y: 703.14, text: "nonumy eirmod tempor" },
+ { x: 437.324, y: 689.268, text: "invidunt ut labore et" },
+ { x: 437.324, y: 675.396, text: "dolore magna aliquyam" },
+ { x: 437.324, y: 661.524, text: "erat, sed diam voluptua." },
+ { x: 437.324, y: 647.652, text: "At vero eos et accusam et" },
+ { x: 437.324, y: 633.78, text: "justo duo dolores et ea" },
+ { x: 437.324, y: 619.908, text: "rebum. Stet clita kasd" },
+ { x: 437.324, y: 606.036, text: "gubergren, no sea" },
+ { x: 437.324, y: 592.164, text: "takimata sanctus est L" },
+ { x: 36.0, y: 433.83509, text: "Stet clita kasd gubergren, no sea takimata" },
+ { x: 36.0, y: 419.96309, text: "sanctus est Lorem ipsum dolor sit amet. Lorem" },
+ { x: 36.0, y: 406.09109, text: "ipsum dolor sit amet, consetetur sadipscing elitr," },
+ { x: 36.0, y: 392.21909, text: "sed diam nonumy eirmod tempor invidunt ut" },
+ { x: 36.0, y: 378.34709, text: "labore et dolore magna aliquyam erat, sed diam" },
+ { x: 36.0, y: 364.47509, text: "voluptua. At vero eos et accusam et justo duo" },
+ { x: 36.0, y: 350.60309, text: "dolores et ea rebum. Stet clita kasd gubergren," },
+ { x: 36.0, y: 336.73109, text: "no sea takimata sanctus est Lorem ipsum dolor" },
+ { x: 36.0, y: 322.85909, text: "sit amet." },
+ { x: 298.648, y: 433.83509, text: "Lorem ipsum dolor sit" },
+ { x: 298.648, y: 419.96309, text: "amet, consetetur" },
+ { x: 298.648, y: 406.09109, text: "sadipscing elitr, sed diam" },
+ { x: 298.648, y: 392.21909, text: "nonumy eirmod tempor" },
+ { x: 298.648, y: 378.34709, text: "invidunt ut labore et" },
+ { x: 298.648, y: 364.47509, text: "dolore magna aliquyam" },
+ { x: 298.648, y: 350.60309, text: "erat, sed diam voluptua." },
+ { x: 298.648, y: 336.73109, text: "At vero eos et accusam et" },
+ { x: 298.648, y: 322.85909, text: "justo duo dolores et ea" },
+ { x: 298.648, y: 308.98709, text: "rebum. Stet clita kasd" },
+ { x: 298.648, y: 295.11509, text: "gubergren, no sea" },
+ { x: 298.648, y: 281.24309, text: "takimata sanctus est L" },
+ { x: 437.324, y: 433.83509, text: "Lorem ipsum dolor sit" },
+ { x: 437.324, y: 419.96309, text: "amet, consetetur" },
+ { x: 437.324, y: 406.09109, text: "sadipscing elitr, sed diam" },
+ { x: 437.324, y: 392.21909, text: "nonumy eirmod tempor" },
+ { x: 437.324, y: 378.34709, text: "invidunt ut labore et" },
+ { x: 437.324, y: 364.47509, text: "dolore magna aliquyam" },
+ { x: 437.324, y: 350.60309, text: "erat, sed diam voluptua." },
+ { x: 437.324, y: 336.73109, text: "At vero eos et accusam et" },
+ { x: 437.324, y: 322.85909, text: "justo duo dolores et ea" },
+ { x: 437.324, y: 308.98709, text: "rebum. Stet clita kasd" },
+ { x: 437.324, y: 295.11509, text: "gubergren, no sea" },
+ { x: 437.324, y: 281.24309, text: "takimata sanctus est L" }])
+ expect_pdf_images([
+ { x: 41.0, y: 525.75762, width: 183.85378, height: 145.38238 },
+ { x: 41.0, y: 487.32309, width: 250.00178, height: 197.68891 }])
end
end
diff --git a/spec/pdf_helpers.rb b/spec/pdf_helpers.rb
index ece0e38..74dcc59 100644
--- a/spec/pdf_helpers.rb
+++ b/spec/pdf_helpers.rb
@@ -65,7 +65,7 @@ def page
result
end
- def images
+ def xobjects
PDF::Inspector::XObject.analyze(pdf)
end
@@ -84,6 +84,23 @@ def out
.gsub(':text=>', 'text:')})"
end
+ def images
+ all_calls = calls
+ image_calls = calls.each_index.select { |i| all_calls[i][0] == :invoke_xobject } # .find_index { |call| call[0] == :invoke_xobject }
+ image_calls.map do |call_index|
+ call = all_calls[call_index - 1]
+ { x: call[5], y: call[6], width: call[1], height: call[4] }
+ end
+ end
+
+ def out_images
+ puts "expect_pdf_images(#{images.to_s
+ .gsub('{:x=>', "\n{x:")
+ .gsub(':width=>', 'width:')
+ .gsub(':height=>', 'height:')
+ .gsub(':y=>', 'y:')})"
+ end
+
def rectangles
rects = []
calls.each_with_index do |call, i|
@@ -110,8 +127,8 @@ def expect_pdf(data)
expect(page).to eq(data)
end
- def expect_images_in_pdf(amount)
- expect(images.xobject_streams.size).to eq(amount)
+ def expect_pdf_images(data)
+ expect(images).to eq(data)
end
def pdf_raw_color(color)