Can a section be aligned to the page bottom? #337

Closed
mraible opened this Issue Oct 18, 2015 · 14 comments

Comments

Projects
None yet
2 participants
@mraible

mraible commented Oct 18, 2015

I'd like to make a number of changes to the PDF version of my project so it looks like an InfoQ Mini-Book.

The first thing I'd like to start with is aligning the colophon to the bottom of the page. Is that possible?

@mraible

This comment has been minimized.

Show comment
Hide comment
@mraible

mraible Oct 18, 2015

Additional questions I've come up with since I started looking into this:

  1. Is it possible to customize section headings? For example, InfoQ's Dedication and Acknowledgements is center-aligned and is underlined by /////////////////////////. The other sections have their own page for the level-2 headings 0 with large fonts and sometimes quotes under them. I've attached a screenshot below.

partone

1. Using `:toc: macro` and `toc::[]` doesn't seem to work. I'd like to put the TOC after the dedication, acknowledgements and preface, but it seems to remain at the beginning no matter what I do. Also, page numbering starts on the 2nd page of the TOC. The InfoQ mini-book standard is to start it on the page after the TOC renders. If I could put it where I wanted, there would be several pages (numbered with Roman numerals) before the TOC. 2. Is it possible to make the page after the 1st page into the colophon? This page has the book title, author name and version, but I'd like to include the copyright, publisher and ISBN number on it too. It'd be great to be able to customize this page or just replace it. I could probably delete and move pages in the rendered PDF, but I'd rather automate it.

mraible commented Oct 18, 2015

Additional questions I've come up with since I started looking into this:

  1. Is it possible to customize section headings? For example, InfoQ's Dedication and Acknowledgements is center-aligned and is underlined by /////////////////////////. The other sections have their own page for the level-2 headings 0 with large fonts and sometimes quotes under them. I've attached a screenshot below.

partone

1. Using `:toc: macro` and `toc::[]` doesn't seem to work. I'd like to put the TOC after the dedication, acknowledgements and preface, but it seems to remain at the beginning no matter what I do. Also, page numbering starts on the 2nd page of the TOC. The InfoQ mini-book standard is to start it on the page after the TOC renders. If I could put it where I wanted, there would be several pages (numbered with Roman numerals) before the TOC. 2. Is it possible to make the page after the 1st page into the colophon? This page has the book title, author name and version, but I'd like to include the copyright, publisher and ISBN number on it too. It'd be great to be able to customize this page or just replace it. I could probably delete and move pages in the rendered PDF, but I'd rather automate it.
@mojavelinux

This comment has been minimized.

Show comment
Hide comment
@mojavelinux

mojavelinux Oct 22, 2015

Member

There are currently two ways to customize Asciidoctor PDF. One way is using the theme (declarative) and the other is by extending the converter (programmatic).

The first and easiest way is to tweak the theme file. The drawback of this approach is that the capabilities of what the theme can control are still (gradually) emerging. We're attempting to define a declarative, CSS-like design “language” without making it overly technical. The target audience for the theme customization strategy are people who want/need to apply brand guidelines but otherwise retain the general structure (i.e., opinionated layout) of the output document. We need to find the right balance.

The second way to customize is to extend the converter using Ruby (or, eventually, other JVM languages). There are no limits to what you can change once you take this approach (aside from the inherent limitations of Prawn and the PDF format). Using this approach, you can dive deep into the internals without having to fork the project.

Since the first method is already well covered by the theming guide, I'll focus here on the second.

To extend Asciidoctor PDF, you create a Ruby file (let's call it asciidoctor-pdf-extensions.rb) and populate it with the following content.

module AsciidoctorPdfExtensions
  def convert_paragraph node
    puts "Custom convert_paragraph called"
    # delegate to default implementation
    super
  end
end

Asciidoctor::Pdf::Converter.prepend AsciidoctorPdfExtensions

You then load this file using the -r flag (which also works in the Gradle build).

asciidoctor-pdf -f ./asciidoctor-pdf-extensions.rb sample.adoc

The prepend method (introduced in Ruby 2) is how you inject a class into the class hierarchy in Ruby (instead of having to extend the base class, though with a bit more work you could do it that way too). Using extend, your module inherits from the built-in converter, which means you can call super to delegate to the built-in method.

You can override any of the methods in the Asciidoctor PDF converter. Several of the methods are split out to make it easy to handle things like the start of a chapter (for example, see https://github.com/asciidoctor/asciidoctor-pdf/blob/master/lib/asciidoctor-pdf/converter.rb#L1630).

I suspect that in order to get the customizations you want for the InfoQ mini-book format, you'll need to take this approach (at least until the theme file matures a bit more).

  1. Is it possible to customize section headings?

At the moment, only by extending the converter (as I described above). However, being able to customize the chapter titles is something that is planned.

  1. Using :toc: macro and toc::[] doesn't seem to work.

Correct. It is not currently possible to move the TOC unless you extend the converter. Even then, moving the TOC is very complicated because Prawn does not support transactional write operations. Being able to move the TOC, however, is planned. See #278.

  1. Is it possible to make the page after the 1st page into the colophon?

This may be something we want to do generally. When Asciidoctor PDF was created, the colophon and dedication were not considered (as Asciidoctor PDF was originally created with magazine articles in mind). We want these pages to be placed in the standard position for books. If that is before the TOC, then yes, we want to support that. It's probably best to file a separate issue for that.

I do want address the title of the issue before a close out. Positioning text to the bottom of the page is surprisingly difficult in Prawn. However, I do know how it can be done using foundation infrastructure in Asciidoctor PDF. So the open question that remains is How do we define this setting in the theme file?

Member

mojavelinux commented Oct 22, 2015

There are currently two ways to customize Asciidoctor PDF. One way is using the theme (declarative) and the other is by extending the converter (programmatic).

The first and easiest way is to tweak the theme file. The drawback of this approach is that the capabilities of what the theme can control are still (gradually) emerging. We're attempting to define a declarative, CSS-like design “language” without making it overly technical. The target audience for the theme customization strategy are people who want/need to apply brand guidelines but otherwise retain the general structure (i.e., opinionated layout) of the output document. We need to find the right balance.

The second way to customize is to extend the converter using Ruby (or, eventually, other JVM languages). There are no limits to what you can change once you take this approach (aside from the inherent limitations of Prawn and the PDF format). Using this approach, you can dive deep into the internals without having to fork the project.

Since the first method is already well covered by the theming guide, I'll focus here on the second.

To extend Asciidoctor PDF, you create a Ruby file (let's call it asciidoctor-pdf-extensions.rb) and populate it with the following content.

module AsciidoctorPdfExtensions
  def convert_paragraph node
    puts "Custom convert_paragraph called"
    # delegate to default implementation
    super
  end
end

Asciidoctor::Pdf::Converter.prepend AsciidoctorPdfExtensions

You then load this file using the -r flag (which also works in the Gradle build).

asciidoctor-pdf -f ./asciidoctor-pdf-extensions.rb sample.adoc

The prepend method (introduced in Ruby 2) is how you inject a class into the class hierarchy in Ruby (instead of having to extend the base class, though with a bit more work you could do it that way too). Using extend, your module inherits from the built-in converter, which means you can call super to delegate to the built-in method.

You can override any of the methods in the Asciidoctor PDF converter. Several of the methods are split out to make it easy to handle things like the start of a chapter (for example, see https://github.com/asciidoctor/asciidoctor-pdf/blob/master/lib/asciidoctor-pdf/converter.rb#L1630).

I suspect that in order to get the customizations you want for the InfoQ mini-book format, you'll need to take this approach (at least until the theme file matures a bit more).

  1. Is it possible to customize section headings?

At the moment, only by extending the converter (as I described above). However, being able to customize the chapter titles is something that is planned.

  1. Using :toc: macro and toc::[] doesn't seem to work.

Correct. It is not currently possible to move the TOC unless you extend the converter. Even then, moving the TOC is very complicated because Prawn does not support transactional write operations. Being able to move the TOC, however, is planned. See #278.

  1. Is it possible to make the page after the 1st page into the colophon?

This may be something we want to do generally. When Asciidoctor PDF was created, the colophon and dedication were not considered (as Asciidoctor PDF was originally created with magazine articles in mind). We want these pages to be placed in the standard position for books. If that is before the TOC, then yes, we want to support that. It's probably best to file a separate issue for that.

I do want address the title of the issue before a close out. Positioning text to the bottom of the page is surprisingly difficult in Prawn. However, I do know how it can be done using foundation infrastructure in Asciidoctor PDF. So the open question that remains is How do we define this setting in the theme file?

@mraible

This comment has been minimized.

Show comment
Hide comment
@mraible

mraible Oct 23, 2015

Thanks for the detailed explanation Dan!

I tried creating sciidoctor-pdf-extensions.rb in src/main/ruby:

module AsciidoctorPdfExtensions
  def convert_paragraph node
    puts "Custom convert_paragraph called"
    # delegate to default implementation
    super
  end

  def layout_chapter_title node, title
    puts "title" + title
    # delegate to default implementation
    super
  end
end

Asciidoctor::Pdf::Converter.prepend AsciidoctorPdfExtensions

Then I added a requires method to point to this file in build.gradle:

asciidoctor {
    backends 'html5', 'pdf', 'epub3'
    attributes 'sourcedir': '../../../main/webapp',
            'endpoint-url': 'http://www.jhipster-book.com/',
            'source-highlighter': 'coderay',
            'imagesdir': './images',
             toc: 'left',
             icons: 'font',
             linkattrs: true,
             encoding: 'utf-8',
            'setanchors': 'true',
            'idprefix': '',
            'idseparator': '-',
            'docinfo1': 'true'
    requires './src/main/ruby/asciidoctor-pdf-extensions.rb'
}

Unfortunately, I get an error when I run ./gradlew asciidoctor:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':asciidoctor'.
> (NameError) uninitialized constant Asciidoctor::Pdf

Am I configuring Gradle properly to include this extension?

mraible commented Oct 23, 2015

Thanks for the detailed explanation Dan!

I tried creating sciidoctor-pdf-extensions.rb in src/main/ruby:

module AsciidoctorPdfExtensions
  def convert_paragraph node
    puts "Custom convert_paragraph called"
    # delegate to default implementation
    super
  end

  def layout_chapter_title node, title
    puts "title" + title
    # delegate to default implementation
    super
  end
end

Asciidoctor::Pdf::Converter.prepend AsciidoctorPdfExtensions

Then I added a requires method to point to this file in build.gradle:

asciidoctor {
    backends 'html5', 'pdf', 'epub3'
    attributes 'sourcedir': '../../../main/webapp',
            'endpoint-url': 'http://www.jhipster-book.com/',
            'source-highlighter': 'coderay',
            'imagesdir': './images',
             toc: 'left',
             icons: 'font',
             linkattrs: true,
             encoding: 'utf-8',
            'setanchors': 'true',
            'idprefix': '',
            'idseparator': '-',
            'docinfo1': 'true'
    requires './src/main/ruby/asciidoctor-pdf-extensions.rb'
}

Unfortunately, I get an error when I run ./gradlew asciidoctor:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':asciidoctor'.
> (NameError) uninitialized constant Asciidoctor::Pdf

Am I configuring Gradle properly to include this extension?

@mraible

This comment has been minimized.

Show comment
Hide comment
@mraible

mraible Oct 23, 2015

It seems I was configuring the extension loading wrong. I changed it to:

asciidoctor {
    backends 'html5', 'pdf', 'epub3'
    ...
    extensions new File('./src/main/ruby/asciidoctor-pdf-extensions.rb')
}

However, when I run ./gradlew asciidoctor it fails to parse the file:

* What went wrong:
Execution failed for task ':asciidoctor'.
> startup failed:
  asciidoctor-pdf-extensions.rb: 2: unexpected token: convert_paragraph @ line 2, column 7.
       def convert_paragraph node
           ^

  1 error

mraible commented Oct 23, 2015

It seems I was configuring the extension loading wrong. I changed it to:

asciidoctor {
    backends 'html5', 'pdf', 'epub3'
    ...
    extensions new File('./src/main/ruby/asciidoctor-pdf-extensions.rb')
}

However, when I run ./gradlew asciidoctor it fails to parse the file:

* What went wrong:
Execution failed for task ':asciidoctor'.
> startup failed:
  asciidoctor-pdf-extensions.rb: 2: unexpected token: convert_paragraph @ line 2, column 7.
       def convert_paragraph node
           ^

  1 error
@mojavelinux

This comment has been minimized.

Show comment
Hide comment
@mojavelinux

mojavelinux Oct 23, 2015

Member

Actually, you had it right the first time. You want to use requires. Extensions are something else.

requires file('src/main/ruby/asciidoctor-pdf-extensions.rb')

The reason for uninitialized constant Asciidoctor::Pdf has to do with the load order when using AsciidoctorJ. You simply need to add an explicit require statement to the top of the Ruby file.

require 'asciidoctor-pdf' unless defined? ::Asciidoctor::Pdf

In order to use the prepend feature in Ruby, you'll need to use JRuby 9000, which I recommend anyway. It's a drop-in replacement and it brings compatibility up to Ruby 2.0.

You add it to the buildscript section of your build.gradle and it will automatically get used:

buildscript {
  ...
  dependencies {
    ...
    classpath 'org.jruby:jruby-complete:9.0.3.0'
  }
}

I tested those three changes together and was able to demonstrate that the custom code is called.

Member

mojavelinux commented Oct 23, 2015

Actually, you had it right the first time. You want to use requires. Extensions are something else.

requires file('src/main/ruby/asciidoctor-pdf-extensions.rb')

The reason for uninitialized constant Asciidoctor::Pdf has to do with the load order when using AsciidoctorJ. You simply need to add an explicit require statement to the top of the Ruby file.

require 'asciidoctor-pdf' unless defined? ::Asciidoctor::Pdf

In order to use the prepend feature in Ruby, you'll need to use JRuby 9000, which I recommend anyway. It's a drop-in replacement and it brings compatibility up to Ruby 2.0.

You add it to the buildscript section of your build.gradle and it will automatically get used:

buildscript {
  ...
  dependencies {
    ...
    classpath 'org.jruby:jruby-complete:9.0.3.0'
  }
}

I tested those three changes together and was able to demonstrate that the custom code is called.

@mraible

This comment has been minimized.

Show comment
Hide comment
@mraible

mraible Oct 23, 2015

I've confirmed this works - thanks Dan!

What's the best way to add #278? Can I do it by overriding methods in asciidoctor-pdf-extensions.rb or would I be better off cloning https://github.com/hmflash/asciidoctor-pdf/tree/toc_placement?

mraible commented Oct 23, 2015

I've confirmed this works - thanks Dan!

What's the best way to add #278? Can I do it by overriding methods in asciidoctor-pdf-extensions.rb or would I be better off cloning https://github.com/hmflash/asciidoctor-pdf/tree/toc_placement?

@mojavelinux

This comment has been minimized.

Show comment
Hide comment
@mojavelinux

mojavelinux Oct 23, 2015

Member

You could go either way on that. You'll quickly learn, though, that the toc has special needs with regard to page counting, so the hard part is actually reasoning about how to calculate all the offsets.

If you did it through extension, what I would recommend is turning off the toc attribute, then intercepting the convert_section block, detect the first chapter and then insert the toc by reusing the logic currently in the document method.

The trickiest part is that the toc has to be converted twice, the first time as a dry run. That's because you don't know the page numbers at the start of the book, but you need to reserve pages to put the toc. Then you need to go back and insert the toc after converting the rest of the book.

In order to make this more flexible for extension, the first thing I'd like to do upstream is to create a method named prepare_toc and a method called insert_toc. That way, these two methods can be easily reused to move the toc around. Naturally, prepare_toc would need to store its result in an instance variable so that insert_toc can access it in any scope. I'll go ahead and file an issue for that change as it will make extension a lot simpler.

Member

mojavelinux commented Oct 23, 2015

You could go either way on that. You'll quickly learn, though, that the toc has special needs with regard to page counting, so the hard part is actually reasoning about how to calculate all the offsets.

If you did it through extension, what I would recommend is turning off the toc attribute, then intercepting the convert_section block, detect the first chapter and then insert the toc by reusing the logic currently in the document method.

The trickiest part is that the toc has to be converted twice, the first time as a dry run. That's because you don't know the page numbers at the start of the book, but you need to reserve pages to put the toc. Then you need to go back and insert the toc after converting the rest of the book.

In order to make this more flexible for extension, the first thing I'd like to do upstream is to create a method named prepare_toc and a method called insert_toc. That way, these two methods can be easily reused to move the toc around. Naturally, prepare_toc would need to store its result in an instance variable so that insert_toc can access it in any scope. I'll go ahead and file an issue for that change as it will make extension a lot simpler.

@mojavelinux

This comment has been minimized.

Show comment
Hide comment
Member

mojavelinux commented Oct 23, 2015

See #340

@mraible

This comment has been minimized.

Show comment
Hide comment
@mraible

mraible Oct 23, 2015

Thanks for creating #340. I'm concentrating on the low-hanging fruit now:

  • Centering the dedication and acknowledgement titles (done)
  • Adding a 2-3 inch margin above the dedication and acknowledgement titles (can't figure out how to set the top margin)
  • Adding section pages and making titles fancy (section pages done, haven't tried font manipulation)

Here's what I have so far:

require 'asciidoctor-pdf' unless defined? ::Asciidoctor::Pdf

module AsciidoctorPdfExtensions
  def layout_title_page doc
      # no title page
  end

  def layout_chapter_title node, title
    if (node.id == "dedication" || node.id == "acknowledgements")
      # todo: Add underline of forward-slashes under title
      # todo: Add margin below title, before text
      layout_heading title, align: :center, margin_top: 3
    elsif node.id.include? "mini-book" # colophon
      # todo: make title font-size same as text, align with bottom of page
      layout_heading title, margin: 5
    elsif node.id.include? "jhipster" #chapters
      puts node.id
      # todo: add 'Part One|Two|Three' to title and make font name, size and colors match InfoQ
      layout_heading title, align: :right, margin_top: 3
      start_new_page
    else
       # delegate to default implementation
       super
    end
  end
end

A few questions:

  1. Is it possible to get the node type? For example, 'colophon', 'dedication', etc. rather than just parsing the ids or titles? If not, is it possible to get the file name (from an include)?
  2. How do I add a margin before/after a title? Related: is it possible to vertically align everything on a page?
  3. Is it possible to manipulate the formatting of the title to change the font size and color?
  4. How do I add a line break if I manipulate the title's text?

mraible commented Oct 23, 2015

Thanks for creating #340. I'm concentrating on the low-hanging fruit now:

  • Centering the dedication and acknowledgement titles (done)
  • Adding a 2-3 inch margin above the dedication and acknowledgement titles (can't figure out how to set the top margin)
  • Adding section pages and making titles fancy (section pages done, haven't tried font manipulation)

Here's what I have so far:

require 'asciidoctor-pdf' unless defined? ::Asciidoctor::Pdf

module AsciidoctorPdfExtensions
  def layout_title_page doc
      # no title page
  end

  def layout_chapter_title node, title
    if (node.id == "dedication" || node.id == "acknowledgements")
      # todo: Add underline of forward-slashes under title
      # todo: Add margin below title, before text
      layout_heading title, align: :center, margin_top: 3
    elsif node.id.include? "mini-book" # colophon
      # todo: make title font-size same as text, align with bottom of page
      layout_heading title, margin: 5
    elsif node.id.include? "jhipster" #chapters
      puts node.id
      # todo: add 'Part One|Two|Three' to title and make font name, size and colors match InfoQ
      layout_heading title, align: :right, margin_top: 3
      start_new_page
    else
       # delegate to default implementation
       super
    end
  end
end

A few questions:

  1. Is it possible to get the node type? For example, 'colophon', 'dedication', etc. rather than just parsing the ids or titles? If not, is it possible to get the file name (from an include)?
  2. How do I add a margin before/after a title? Related: is it possible to vertically align everything on a page?
  3. Is it possible to manipulate the formatting of the title to change the font size and color?
  4. How do I add a line break if I manipulate the title's text?
@mojavelinux

This comment has been minimized.

Show comment
Hide comment
@mojavelinux

mojavelinux Oct 28, 2015

Member

I was really busy over the weekend. I'll reply to your questions asap.

Member

mojavelinux commented Oct 28, 2015

I was really busy over the weekend. I'll reply to your questions asap.

@mraible

This comment has been minimized.

Show comment
Hide comment
@mraible

mraible Oct 28, 2015

I figured out most things. Here's some answers to my own questions:

  • node.sectname should do it
  • move_down is your friend
  • yes
  • call layout_heading for each line

Here's what I've come up with. It does most everything I need.

require 'asciidoctor-pdf' unless defined? ::Asciidoctor::Pdf

module AsciidoctorPdfExtensions

  def layout_title_page doc
      # no title page
  end

  def layout_chapter_title node, title
    if node.id == "dedication" || node.id == "acknowledgements"
      layout_heading_custom title, align: :center
    elsif node.id.include? "mini-book" # colophon
      move_down 470
      layout_heading title, size: @theme.base_font_size
    elsif node.id.include? "jhipster" #chapters
      puts 'Processing ' + node.id + '...'
      move_down 120
      # set Akkurat font for all custom headings
      font 'Akkurat'
      layout_heading 'PART', align: :right, size: 120, color: [91, 54, 8, 13], style: :normal
      move_up 40

      part_number = "ONE"
      if node.id.include? "ui-components"
        part_number = "TWO"
      elsif node.id.include? "api"
        part_number = "THREE"
      end

      layout_heading part_number, align: :right, size: 120, color: [42, 1, 83, 1], style: :bold
      layout_heading title, align: :right, color: [42, 1, 83, 1], style: :normal, size: 30
      move_up 30
      start_new_page
    else
       # delegate to default implementation
       super
    end
  end

  def layout_heading_custom string, opts = {}
      move_down 100
      typeset_text string, calc_line_metrics((opts.delete :line_height) || @theme.heading_line_height), {
          inline_format: true
      }.merge(opts)
      move_up 5
      $i = 0
      underline = ''
      while $i < string.length do
          if string == 'Dedication'
            underline += '/////'
          else
            underline += '//////'
          end
          $i += 1
      end
      if string == 'Dedication'
          underline += '////'
      end
      typeset_text underline, calc_line_metrics((opts.delete :line_height) || @theme.heading_line_height), {
            inline_format: true, color: 'B0B0B0', size: 8, style: :italic
      }.merge(opts)
      move_down 20
  end

end

Asciidoctor::Pdf::Converter.prepend AsciidoctorPdfExtensions

A couple issues I'd still like to solve:

  • Replace title page with colophon. I was able to do this in layout_title_page, but then the page count was off and the colophon still printed.
  • Move the table of contents so it starts on a particular page (after the colophon, dedication and acknowledgements).

mraible commented Oct 28, 2015

I figured out most things. Here's some answers to my own questions:

  • node.sectname should do it
  • move_down is your friend
  • yes
  • call layout_heading for each line

Here's what I've come up with. It does most everything I need.

require 'asciidoctor-pdf' unless defined? ::Asciidoctor::Pdf

module AsciidoctorPdfExtensions

  def layout_title_page doc
      # no title page
  end

  def layout_chapter_title node, title
    if node.id == "dedication" || node.id == "acknowledgements"
      layout_heading_custom title, align: :center
    elsif node.id.include? "mini-book" # colophon
      move_down 470
      layout_heading title, size: @theme.base_font_size
    elsif node.id.include? "jhipster" #chapters
      puts 'Processing ' + node.id + '...'
      move_down 120
      # set Akkurat font for all custom headings
      font 'Akkurat'
      layout_heading 'PART', align: :right, size: 120, color: [91, 54, 8, 13], style: :normal
      move_up 40

      part_number = "ONE"
      if node.id.include? "ui-components"
        part_number = "TWO"
      elsif node.id.include? "api"
        part_number = "THREE"
      end

      layout_heading part_number, align: :right, size: 120, color: [42, 1, 83, 1], style: :bold
      layout_heading title, align: :right, color: [42, 1, 83, 1], style: :normal, size: 30
      move_up 30
      start_new_page
    else
       # delegate to default implementation
       super
    end
  end

  def layout_heading_custom string, opts = {}
      move_down 100
      typeset_text string, calc_line_metrics((opts.delete :line_height) || @theme.heading_line_height), {
          inline_format: true
      }.merge(opts)
      move_up 5
      $i = 0
      underline = ''
      while $i < string.length do
          if string == 'Dedication'
            underline += '/////'
          else
            underline += '//////'
          end
          $i += 1
      end
      if string == 'Dedication'
          underline += '////'
      end
      typeset_text underline, calc_line_metrics((opts.delete :line_height) || @theme.heading_line_height), {
            inline_format: true, color: 'B0B0B0', size: 8, style: :italic
      }.merge(opts)
      move_down 20
  end

end

Asciidoctor::Pdf::Converter.prepend AsciidoctorPdfExtensions

A couple issues I'd still like to solve:

  • Replace title page with colophon. I was able to do this in layout_title_page, but then the page count was off and the colophon still printed.
  • Move the table of contents so it starts on a particular page (after the colophon, dedication and acknowledgements).

@mraible mraible closed this Oct 28, 2015

@mojavelinux

This comment has been minimized.

Show comment
Hide comment
@mojavelinux

mojavelinux Oct 28, 2015

Member

I'm glad to hear it!

  1. Correct. sectname is the name of the property that holds the special "block name" of a section. You know that the block name is something other than "section" when the property special returns true. For regular sections, the sectname is "sect" + the level (e.g., sect1). It's not possible to get the file name of an include from the AST as that information is gone by the time the parser runs.
  2. move_down is the low-level primitive in Prawn for moving down (and move_up goes back up). As much as possible we try to abstract over these primitives. In fact, there are lots of useful methods that Asciidoctor PDF adds that you can find here: https://github.com/asciidoctor/asciidoctor-pdf/blob/master/lib/asciidoctor-pdf/prawn_ext/extensions.rb. Vertically aligning on a page is a lot of work because you have to know the height of what you are rendering, then calculate the distance from the top of the page to move down. But it is possible.
  3. Yep, the theme. See https://github.com/asciidoctor/asciidoctor-pdf/blob/master/docs/theming-guide.adoc#heading
  4. Actually, a better way to do this is to add an endline to the text, then pass the normalize: false option to layout_heading. But default, Asciidoctor PDF folds endlines. The normalize: false disables this behavior.

Move the table of contents so it starts on a particular page (after the colophon, dedication and acknowledgements).

As you may have figured out by now, the biggest complexity is counting pages. (I really dread working on anything that touches the page counts). Once we start moving things around, it gets complicated really quick. I can see how it can be solved, but it's going to be a task. Related issues: #340 and #233.

Replace title page with colophon.

In general, I think we just need to start with some special handling for the colophon. That should allow extension points to emerge and get refined. I don't think we have an issue for that yet.

Member

mojavelinux commented Oct 28, 2015

I'm glad to hear it!

  1. Correct. sectname is the name of the property that holds the special "block name" of a section. You know that the block name is something other than "section" when the property special returns true. For regular sections, the sectname is "sect" + the level (e.g., sect1). It's not possible to get the file name of an include from the AST as that information is gone by the time the parser runs.
  2. move_down is the low-level primitive in Prawn for moving down (and move_up goes back up). As much as possible we try to abstract over these primitives. In fact, there are lots of useful methods that Asciidoctor PDF adds that you can find here: https://github.com/asciidoctor/asciidoctor-pdf/blob/master/lib/asciidoctor-pdf/prawn_ext/extensions.rb. Vertically aligning on a page is a lot of work because you have to know the height of what you are rendering, then calculate the distance from the top of the page to move down. But it is possible.
  3. Yep, the theme. See https://github.com/asciidoctor/asciidoctor-pdf/blob/master/docs/theming-guide.adoc#heading
  4. Actually, a better way to do this is to add an endline to the text, then pass the normalize: false option to layout_heading. But default, Asciidoctor PDF folds endlines. The normalize: false disables this behavior.

Move the table of contents so it starts on a particular page (after the colophon, dedication and acknowledgements).

As you may have figured out by now, the biggest complexity is counting pages. (I really dread working on anything that touches the page counts). Once we start moving things around, it gets complicated really quick. I can see how it can be solved, but it's going to be a task. Related issues: #340 and #233.

Replace title page with colophon.

In general, I think we just need to start with some special handling for the colophon. That should allow extension points to emerge and get refined. I don't think we have an issue for that yet.

@mojavelinux

This comment has been minimized.

Show comment
Hide comment
@mojavelinux

mojavelinux Oct 28, 2015

Member

One of the biggest challenges with making a PDF converter is that PDF just doesn't have a lot of the styling capabilities that we are used to from the web (especially CSS3). The key is going to be to continue building abstractions that let us work at this level. We've made important strides so far. If you try to use Prawn standalone you will quickly see how many building blocks are in Asciidoctor PDF. But fine-tuning PDF creation (while keeping a separation of content and presentation) remains a challenge.

What's important about Asciidoctor PDF over the DocBook toolchain is that you can use programming to solve the issue rather than getting lost in XSLT stylesheets.

Member

mojavelinux commented Oct 28, 2015

One of the biggest challenges with making a PDF converter is that PDF just doesn't have a lot of the styling capabilities that we are used to from the web (especially CSS3). The key is going to be to continue building abstractions that let us work at this level. We've made important strides so far. If you try to use Prawn standalone you will quickly see how many building blocks are in Asciidoctor PDF. But fine-tuning PDF creation (while keeping a separation of content and presentation) remains a challenge.

What's important about Asciidoctor PDF over the DocBook toolchain is that you can use programming to solve the issue rather than getting lost in XSLT stylesheets.

@mojavelinux

This comment has been minimized.

Show comment
Hide comment
@mojavelinux

mojavelinux Oct 28, 2015

Member

Btw, you can get rid of the title page simply by passing the attribute notitle to Asciidoctor PDF:

-a notitle

You can also add it to your document as follows:

= Document Title
Author Name
ifdef::backend-pdf[:notitle:]

content
Member

mojavelinux commented Oct 28, 2015

Btw, you can get rid of the title page simply by passing the attribute notitle to Asciidoctor PDF:

-a notitle

You can also add it to your document as follows:

= Document Title
Author Name
ifdef::backend-pdf[:notitle:]

content
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment