diff options
| author | Dan Allen <dan.j.allen@gmail.com> | 2015-07-29 01:59:44 -0600 |
|---|---|---|
| committer | Dan Allen <dan.j.allen@gmail.com> | 2015-07-29 22:26:53 -0600 |
| commit | 05cf2544aabc181ce7cde82e138e888baa9739a2 (patch) | |
| tree | b7fea973fd07091ade44f00122fd1f2cb4cc5e83 | |
| parent | 504a7d81d769ec6016d728e33d3b36235c8638d4 (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.adoc | 6 | ||||
| -rw-r--r-- | examples/chronicles-example.adoc | 2 | ||||
| -rw-r--r-- | examples/chronicles-example.pdf | bin | 193922 -> 179677 bytes | |||
| -rw-r--r-- | lib/asciidoctor-pdf/converter.rb | 111 | ||||
| -rw-r--r-- | lib/asciidoctor-pdf/prawn_ext/images.rb | 16 |
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 Binary files differindex 156df945..366c3f71 100644 --- a/examples/chronicles-example.pdf +++ b/examples/chronicles-example.pdf 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 |
