Skip to content

Commit

Permalink
resolves asciidoctor#625 honor pdfwidth attribute for image in runnin…
Browse files Browse the repository at this point in the history
…g content

- honor pdfwidth attribute for image in running content
- position SVG correctly
- only fit image to bounds if fit=contain or fit=scale-down attribute is used
- calculate image width from percentage value based on column width, not content width
  • Loading branch information
mojavelinux committed Oct 16, 2016
1 parent 60017b7 commit 95cff19
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 35 deletions.
97 changes: 64 additions & 33 deletions lib/asciidoctor-pdf/converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -952,7 +952,7 @@ def convert_image node, opts = {}
if !width && (svg_obj.document.root.attributes.key? 'width')
# NOTE scale native width & height by 75% to convert px to pt; restrict width to bounds.width
if (adjusted_w = [bounds.width, rendered_w * 0.75].min) != rendered_w
# FIXME would be nice to have a resize method (available as of prawn-svg 0.25.2); for now, just reconstruct
# FIXME use new resize method (available as of prawn-svg 0.25.2); reconstruct manually for now
svg_obj = ::Prawn::Svg::Interface.new svg_data, self,
position: alignment,
width: (rendered_w = adjusted_w),
Expand Down Expand Up @@ -1019,12 +1019,15 @@ def convert_image node, opts = {}
img_x, img_y = image_position rendered_w, rendered_h, position: alignment
link_box = [img_x, (img_y - rendered_h), (img_x + rendered_w), img_y]
end
image_top = cursor
embed_image image_obj, image_info, width: rendered_w, position: alignment
if link
link_annotation link_box,
Border: [0, 0, 0],
A: { Type: :Action, S: :URI, URI: link.as_pdf }
end
# NOTE Asciidoctor disables automatic advancement of cursor, so handle it manually
move_down rendered_h if cursor == image_top
rescue => e
warn %(asciidoctor: WARNING: could not embed image: #{image_path}; #{e.message})
end
Expand Down Expand Up @@ -2120,34 +2123,7 @@ def layout_running_content periphery, doc, opts = {}
doc.set_attr 'document-title', doctitle.main
doc.set_attr 'document-subtitle', doctitle.subtitle
doc.set_attr 'page-count', num_pages

# TODO move this to a method so it can be reused; cache results
content_dict = PageSides.inject({}) do |acc, side|
side_content = {}
ColumnPositions.each do |position|
if (val = @theme[%(#{periphery}_#{side}_#{position}_content)])
# TODO support image URL (using resolve_image_path)
if (val.include? ':') && val =~ ImageAttributeValueRx &&
::File.readable?(path = (ThemeLoader.resolve_theme_asset $1, (doc.attr 'pdf-stylesdir')))
attrs = (AttributeList.new $2).parse
unless (width = resolve_explicit_width attrs, bounds.width)
# QUESTION should we lookup and scale intrinsic width if explicit width is not given?
width = (intrinsic_image_dimensions path)[:width] * 0.75
end
side_content[position] = { path: path, width: width, fit: (attrs.key? 'contain-option') }
else
side_content[position] = val
end
end
end
# NOTE set fallbacks if not explicitly disabled
if side_content.empty? && periphery == :footer && @theme[%(footer_#{side}_content)] != 'none'
side_content = { side == :recto ? :right : :left => '{page-number}' }
end

acc[side] = side_content
acc
end
allow_uri_read = doc.attr? 'allow-uri-read'

if periphery == :header
trim_line_metrics = calc_line_metrics(@theme.header_line_height || @theme.base_line_height)
Expand Down Expand Up @@ -2243,6 +2219,40 @@ def layout_running_content periphery, doc, opts = {}
acc
end

# TODO move this to a method so it can be reused; cache results
content_dict = PageSides.inject({}) do |acc, side|
side_content = {}
ColumnPositions.each do |position|
if (val = @theme[%(#{periphery}_#{side}_#{position}_content)])
# TODO support image URL (using resolve_image_path)
if (val.include? ':') && val =~ ImageAttributeValueRx &&
::File.readable?(path = (ThemeLoader.resolve_theme_asset $1, (doc.attr 'pdf-stylesdir')))
attrs = (AttributeList.new $2).parse
col_width = colspec_dict[side][position][:width]
if (fit = attrs['fit']) == 'contain'
width = col_width
else
unless (width = resolve_explicit_width attrs, col_width)
# QUESTION should we lookup and scale intrinsic width if explicit width is not given?
width = (intrinsic_image_dimensions path)[:width] * 0.75
end
width = col_width if fit == 'scale-down' && width > col_width
end
side_content[position] = { path: path, width: width, fit: !!fit }
else
side_content[position] = val
end
end
end
# NOTE set fallbacks if not explicitly disabled
if side_content.empty? && periphery == :footer && @theme[%(footer_#{side}_content)] != 'none'
side_content = { side == :recto ? :right : :left => '{page-number}' }
end

acc[side] = side_content
acc
end

stamps = {}
if trim_bg_color || trim_border_color
PageSides.each do |side|
Expand Down Expand Up @@ -2306,11 +2316,32 @@ def layout_running_content periphery, doc, opts = {}
float do
# NOTE bounding_box is redundant if trim_v_padding is 0
bounding_box [colspec[:x], cursor - trim_padding[0]], width: colspec[:width], height: (bounds.height - trim_v_padding) do
if content[:fit]
# NOTE use :fit to prevent image from overflowing page (at the cost of scaling it)
image content[:path], vposition: trim_img_valign, position: colspec[:align], fit: [content[:width], bounds.height]
if (image_path = content[:path]).downcase.end_with? '.svg'
svg_data = ::IO.read image_path
svg_obj = ::Prawn::Svg::Interface.new svg_data, self,
position: (image_alignment = colspec[:align]),
width: (image_width = content[:width]),
fallback_font_name: (fallback_font_name = default_svg_font),
enable_web_requests: allow_uri_read,
# TODO enforce jail in safe mode
enable_file_requests_with_root: (file_request_root = ::File.dirname image_path)
# FIXME use new resize method (available as of prawn-svg 0.25.2); reconstruct manually for now
if content[:fit] && (rendered_h = svg_obj.document.sizing.output_height) > bounds.height
svg_obj = ::Prawn::Svg::Interface.new svg_data, self,
position: image_alignment,
width: image_width * (bounds.height / rendered_h),
fallback_font_name: fallback_font_name,
enable_web_requests: allow_uri_read,
# TODO enforce jail in safe mode
enable_file_requests_with_root: file_request_root
end
svg_obj.draw
else
image content[:path], vposition: trim_img_valign, position: colspec[:align], width: content[:width]
if content[:fit]
image image_path, vposition: trim_img_valign, position: colspec[:align], fit: [content[:width], bounds.height]
else
image image_path, vposition: trim_img_valign, position: colspec[:align], width: content[:width]
end
end
end
end
Expand Down
7 changes: 7 additions & 0 deletions lib/asciidoctor-pdf/prawn_ext/extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,13 @@ def move_up n
super unless n == 0
end

# Override built-in move_text_position method to prevent Prawn from advancing
# to next page if image doesn't fit before rendering image.
#--
# NOTE could use :at option when calling image/embed_image instead
def move_text_position h
end

# Short-circuits the call to the built-in move_down operation
# when n is 0.
#
Expand Down
2 changes: 0 additions & 2 deletions lib/asciidoctor-pdf/prawn_ext/images.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ def extended base
def image file, opts = {}
# FIXME handle case when SVG is a File or IO object
if ::String === file && (file.downcase.end_with? '.svg')
opts[:position] ||= :left
opts[:vposition] ||= cursor
opts[:fallback_font_name] ||= default_svg_font if respond_to? :default_svg_font
svg (::IO.read file), opts
else
Expand Down

0 comments on commit 95cff19

Please sign in to comment.