Skip to content

Commit

Permalink
resolves #221 apply point conversion to image widths
Browse files Browse the repository at this point in the history
- apply point conversion to width of images on title page
- apply point conversion to width of images in running header/footer
- don't allow image in running header/footer to overrun page (shrink to fit)
- only hide title page if notitle is set (not noheader)
- use ThemeLoader.resolve_theme_asset to resolve path of title-logo-image
- add method to calculate intrinsic dimensions of image
- document fallback running footer content in theming guide
- document the effect the notitle, noheader & nofooter attributes have in theming guide
- minor cleanups
  • Loading branch information
mojavelinux committed Jul 30, 2015
1 parent 504a7d8 commit 05cf254
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 49 deletions.
6 changes: 6 additions & 0 deletions docs/theming-guide.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,8 @@ The literal key is used for inline monospaced text in prose and table cells.
|revision_margin_top: 13.125
|===

TIP: The title page can be disabled from the document by setting the `notitle` attribute in the document header.

=== Block

[cols="3,3,5m"]
Expand Down Expand Up @@ -1531,6 +1533,10 @@ Block styles are applied to the following block types:

IMPORTANT: You must define a height for the running header or footer, respectively, or it will not be shown.

TIP: The running header and footer can be disabled from the document by setting the `noheader` and the `nofooter` attributes, respectively, in the document header.

NOTE: If content is not specified for the running footer, the page number (i.e., `+{page-number}+`) will be shown on the left side on verso pages and the right side on recto pages.

NOTE: The background color spans the width of the page.
When a background color is specified, the border also spans the width of the page.

Expand Down
2 changes: 1 addition & 1 deletion examples/chronicles-example.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ power.
:toc:
:toclevels: 3
ifdef::backend-pdf[]
:title-logo-image: image:sample-title-logo.jpg[scaledwidth=50%,align=center]
:title-logo-image: image:sample-title-logo.jpg[pdfwidth=4.25in,align=center]
:pygments-style: tango
//:source-highlighter: pygments
:source-highlighter: coderay
Expand Down
Binary file modified examples/chronicles-example.pdf
Binary file not shown.
111 changes: 63 additions & 48 deletions lib/asciidoctor-pdf/converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -793,22 +793,9 @@ def convert_image node

theme_margin :block, :top

# NOTE image is scaled proportionally based on width (height is ignored)
# TODO support cover (aka canvas) image layout using "canvas" (or "cover") role
# NOTE height values are basically ignored (image is scaled proportionally based on width)
# QUESTION should we enforce positive numbers?
width = if node.attr? 'pdfwidth'
if (pdfwidth = node.attr 'pdfwidth').end_with? '%'
(pdfwidth.to_f / 100) * bounds.width
else
str_to_pt pdfwidth
end
elsif node.attr? 'scaledwidth'
((node.attr 'scaledwidth').to_f / 100) * bounds.width
elsif node.attr? 'width'
# QUESTION should we honor percentage width value?
# NOTE scale width by 75% to convert px to pt; restrict width to bounds.width
[bounds.width, (node.attr 'width').to_f * 0.75].min
end
width = resolve_explicit_width node.attributes, bounds.width

case image_type
when 'svg'
Expand Down Expand Up @@ -843,9 +830,9 @@ def convert_image node
end
else
begin
# FIXME temporary workaround to group caption & image
# Prawn doesn't provide access to rendered width & height before placing image on page
# FIXME this code really needs to be better organized!
# FIXME temporary workaround to group caption & image
# NOTE use low-level API to access intrinsic dimensions; build_image_object caches image data previously loaded
image_obj, image_info = build_image_object image_path
if width
rendered_w, rendered_h = image_info.calc_image_dimensions width: width
Expand Down Expand Up @@ -1489,15 +1476,15 @@ def convert_inline_quoted node

# FIXME only create title page if doctype=book!
def layout_title_page doc
return unless doc.header? && !doc.noheader && !doc.notitle
return unless doc.header? && !doc.notitle

prev_bg_image = @page_bg_image
prev_bg_color = @page_bg_color
if (bg_image = (doc.attr 'title-background-image', @theme.title_page_background_image))
if bg_image == 'none'
@page_bg_image = nil
else
if bg_image =~ ImageAttributeValueRx
if (bg_image.include? ':') && bg_image =~ ImageAttributeValueRx
bg_image = $1
# QUESTION should we support width and height?
end
Expand Down Expand Up @@ -1533,18 +1520,17 @@ def layout_title_page doc
# QUESTION allow aligment per element on title page?
title_align = (@theme.title_page_align || :center).to_sym

# FIXME rework image handling once fix for #134 is merged
# TODO disallow .pdf as image type
if (logo_image_path = (doc.attr 'title-logo-image', @theme.title_page_logo_image))
if logo_image_path =~ ImageAttributeValueRx
if (logo_image_path.include? ':') && logo_image_path =~ ImageAttributeValueRx
logo_image_path = $1
logo_image_attrs = AttributeList.new($2).parse(['alt', 'width', 'height'])
logo_image_attrs = (AttributeList.new $2).parse ['alt', 'width', 'height']
else
logo_image_attrs = {}
end
# HACK quick fix to resolve image path relative to theme
unless doc.attr? 'title-logo-image'
# FIXME use ThemeLoader.resolve_theme_asset once fix for #134 is merged
logo_image_path = ::File.expand_path logo_image_path, (doc.attr 'pdf-stylesdir', ThemeLoader::ThemesDir)
logo_image_path = ThemeLoader.resolve_theme_asset logo_image_path, (doc.attr 'pdf-stylesdir')
end
logo_image_attrs['target'] = logo_image_path
logo_image_attrs['align'] ||= (@theme.title_page_logo_align || title_align.to_s)
Expand All @@ -1556,6 +1542,7 @@ def layout_title_page doc
# FIXME add API to Asciidoctor for creating blocks like this (extract from extensions module?)
image_block = ::Asciidoctor::Block.new doc, :image, content_model: :empty, attributes: logo_image_attrs
# FIXME prevent image from spilling to next page
# QUESTION should we shave off margin top/bottom?
convert_image image_block
end
end
Expand Down Expand Up @@ -1615,7 +1602,7 @@ def layout_cover_page position, doc
# TODO turn processing of attribute with inline image a utility function in Asciidoctor
# FIXME verify cover_image exists!
if (cover_image = (doc.attr %(#{position}-cover-image)))
if cover_image =~ ImageAttributeValueRx
if (cover_image.include? ':') && cover_image =~ ImageAttributeValueRx
cover_image = resolve_image_path doc, $1
end
# QUESTION should we go to page 1 when position == :front?
Expand Down Expand Up @@ -1836,30 +1823,36 @@ def layout_running_content position, doc, opts = {}
doc.set_attr 'document-subtitle', doctitle.subtitle
doc.set_attr 'page-count', num_pages

fallback_footer_content = {
recto: { right: '{page-number}' },
verso: { left: '{page-number}' }
}
# TODO move this to a method so it can be reused; cache results
content_dict = [:recto, :verso].inject({}) do |acc, side|
side_content = {}
Alignments.each do |align|
if (val = @theme[%(#{position}_#{side}_content_#{align})])
if ImageAttributeValueRx =~ val &&
# 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
attrs['width'] = attrs['width'].to_f if attrs['width']
side_content[align] = { path: path, width: attrs['width'] }
attrs = (AttributeList.new $2).parse
width = resolve_explicit_width attrs, bounds.width
# QUESTION should we lookup and scale intrinsic width if explicit width is not given?
unless width
width = [bounds.width, (intrinsic_image_dimensions path)[:width] * 0.75].min
end
side_content[align] = { path: path, width: width }
else
side_content[align] ||= val
side_content[align] = val
end
end
end
# NOTE set fallbacks if not explicitly disabled
if (acc[side] = side_content).empty? && @theme[%(footer_#{side}_content)] != 'none'
case side
when :recto
acc[side] = { right: '{page-number}' }
when :verso
acc[side] = { left: '{page-number}' }
end
if side_content.empty? && position == :footer && @theme[%(footer_#{side}_content)] != 'none'
side_content = fallback_footer_content[side]
end

acc[side] = side_content
acc
end

Expand Down Expand Up @@ -1962,17 +1955,14 @@ def layout_running_content position, doc, opts = {}
case (content = content_by_alignment[align])
when ::Hash
# NOTE image placement respects padding; use negative image_vertical_align value to revert
if (trim_v_padding = trim_padding[0] + trim_padding[2]) > 0
bounding_box [0, cursor - trim_padding[0]], width: bounds.width, height: (bounds.height - trim_v_padding) do
# FIXME prevent image from overflowing the page
float do
image content[:path], vposition: trim_img_valign, position: align, width: content[:width]
end
end
else
# FIXME prevent image from overflowing the page
trim_v_padding = trim_padding[0] + trim_padding[2]
# NOTE bounding_box is redundant if trim_v_padding is 0
bounding_box [0, cursor - trim_padding[0]], width: bounds.width, height: (bounds.height - trim_v_padding) do
# NOTE float ensures cursor position is restored and returns us to current page if we overrun
float do
image content[:path], vposition: trim_img_valign, position: align, width: content[:width]
#image content[:path], vposition: trim_img_valign, position: align, width: content[:width]
# NOTE use :fit to prevent image from overflowing page (at the cost of scaling it)
image content[:path], vposition: trim_img_valign, position: align, fit: [content[:width], bounds.height]
end
end
when ::String
Expand Down Expand Up @@ -2010,7 +2000,7 @@ def add_outline doc, num_levels = 2, toc_page_nums = (0..-1), num_front_matter_p

# title page (i)
# TODO same conditional logic as in layout_title_page; consolidate
if doc.header? && !doc.noheader && !doc.notitle
if doc.header? && !doc.notitle
page_num_labels[0] = { P: ::PDF::Core::LiteralString.new(front_matter_counter.next!.to_s) }
end

Expand Down Expand Up @@ -2394,6 +2384,31 @@ def resolve_image_path node, image_path = nil, image_type = nil
end
end

# Resolves the explicit width as a PDF pt value, if specified.
#
# Resolves the explicit width, first considering the pdfwidth attribute, then
# the scaledwidth attribute and finally the width attribute. If the specified
# value is in pixels, the value is scaled by 75% to perform approximate
# CSS px to PDF pt conversion. If the resolved width is larger than the
# max_width, the max_width value is returned.
#--
# QUESTION should we enforce positive result?
def resolve_explicit_width attrs, max_width = bounds.width
if attrs.key? 'pdfwidth'
if (pdfwidth = attrs['pdfwidth']).end_with? '%'
(pdfwidth.to_f / 100) * max_width
else
str_to_pt pdfwidth
end
elsif attrs.key? 'scaledwidth'
(attrs['scaledwidth'].to_f / 100) * max_width
elsif attrs.key? 'width'
# QUESTION should we honor percentage width value?
# NOTE scale width down 75% to convert px to pt; restrict width to bounds.width
[max_width, attrs['width'].to_f * 0.75].min
end
end

# QUESTION is there a better way to do this?
# I suppose we could have @tmp_files as an instance variable on converter instead
# It might be sufficient to delete temporary files once per conversion
Expand Down
16 changes: 16 additions & 0 deletions lib/asciidoctor-pdf/prawn_ext/images.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,22 @@ def image file, opts = {}
_initial_image file, opts
end
end

# Retrieve the intrinsic image dimensions for the specified path.
#
# Returns a Hash containing :width and :height keys that map to the image's
# intrinsic width and height values (in pixels)
def intrinsic_image_dimensions path
if path.end_with? '.svg'
img_obj = ::Prawn::Svg::Interface.new ::IO.read(path), self, {}
img_size = img_obj.document.sizing
{ width: img_size.output_width, height: img_size.output_height }
else
# NOTE build_image_object caches image data previously loaded
_, img_size = build_image_object path
{ width: img_size.width, height: img_size.height }
end
end
end

::Prawn::Document.extensions << Images
Expand Down

0 comments on commit 05cf254

Please sign in to comment.