summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Allen <dan.j.allen@gmail.com>2015-07-29 01:59:44 -0600
committerDan Allen <dan.j.allen@gmail.com>2015-07-29 22:26:53 -0600
commit05cf2544aabc181ce7cde82e138e888baa9739a2 (patch)
treeb7fea973fd07091ade44f00122fd1f2cb4cc5e83
parent504a7d81d769ec6016d728e33d3b36235c8638d4 (diff)
resolves #221 apply point conversion to image widths
- 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
-rw-r--r--docs/theming-guide.adoc6
-rw-r--r--examples/chronicles-example.adoc2
-rw-r--r--examples/chronicles-example.pdfbin193922 -> 179677 bytes
-rw-r--r--lib/asciidoctor-pdf/converter.rb111
-rw-r--r--lib/asciidoctor-pdf/prawn_ext/images.rb16
5 files changed, 86 insertions, 49 deletions
diff --git a/docs/theming-guide.adoc b/docs/theming-guide.adoc
index 7d44603d..77e162a4 100644
--- a/docs/theming-guide.adoc
+++ b/docs/theming-guide.adoc
@@ -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"]
@@ -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.
diff --git a/examples/chronicles-example.adoc b/examples/chronicles-example.adoc
index 9d137e4e..503f3fe5 100644
--- a/examples/chronicles-example.adoc
+++ b/examples/chronicles-example.adoc
@@ -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
diff --git a/examples/chronicles-example.pdf b/examples/chronicles-example.pdf
index 156df945..366c3f71 100644
--- a/examples/chronicles-example.pdf
+++ b/examples/chronicles-example.pdf
Binary files differ
diff --git a/lib/asciidoctor-pdf/converter.rb b/lib/asciidoctor-pdf/converter.rb
index b0b0fb35..453b92b1 100644
--- a/lib/asciidoctor-pdf/converter.rb
+++ b/lib/asciidoctor-pdf/converter.rb
@@ -793,22 +793,9 @@ class Converter < ::Prawn::Document
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'
@@ -843,9 +830,9 @@ class Converter < ::Prawn::Document
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
@@ -1489,7 +1476,7 @@ class Converter < ::Prawn::Document
# 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
@@ -1497,7 +1484,7 @@ class Converter < ::Prawn::Document
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
@@ -1533,18 +1520,17 @@ class Converter < ::Prawn::Document
# 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)
@@ -1556,6 +1542,7 @@ class Converter < ::Prawn::Document
# 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
@@ -1615,7 +1602,7 @@ class Converter < ::Prawn::Document
# 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?
@@ -1836,30 +1823,36 @@ class Converter < ::Prawn::Document
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
@@ -1962,17 +1955,14 @@ class Converter < ::Prawn::Document
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
@@ -2010,7 +2000,7 @@ class Converter < ::Prawn::Document
# 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
@@ -2394,6 +2384,31 @@ class Converter < ::Prawn::Document
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
diff --git a/lib/asciidoctor-pdf/prawn_ext/images.rb b/lib/asciidoctor-pdf/prawn_ext/images.rb
index 7797ed83..76f351c9 100644
--- a/lib/asciidoctor-pdf/prawn_ext/images.rb
+++ b/lib/asciidoctor-pdf/prawn_ext/images.rb
@@ -17,6 +17,22 @@ module Images
_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