Skip to content

Commit

Permalink
backport fix for #2477 force color space to be set when setting up gr…
Browse files Browse the repository at this point in the history
…aphic state for stamp

- map color_space from graphic state on repeater to color space of current page so color space is set properly
- remove obsolete workaround to set color space on pages with images
  • Loading branch information
mojavelinux committed Jan 20, 2024
1 parent 7f42cb8 commit c8a5c13
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 11 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ Enhancements::

* upgrade prawn-svg dependency to 0.33.x (PR #2469)

Bug Fixes::

* ensure color spaces are set on page before adding running content (#2477)

== 2.3.10 (2023-12-04) - @mojavelinux

Bug Fixes::
Expand Down
28 changes: 19 additions & 9 deletions lib/asciidoctor/pdf/converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1809,9 +1809,6 @@ def convert_image node, opts = {}
rendered_w = (svg_obj.resize height: (rendered_h = available_h)).output_width if rendered_h > available_h
end
add_dest_for_block node if node.id
# NOTE: workaround to fix Prawn not adding fill and stroke commands on page that only has an image;
# breakage occurs when running content (stamps) are added to page
update_colors if graphic_state.color_space.empty?
ink_caption node, category: :image, end: :top, block_align: alignment, block_width: rendered_w, max_width: caption_max_width if caption_end == :top && node.title?
image_y = y
# NOTE: prawn-svg does not compute :at for alignment correctly in column box, so resort to our own logic
Expand Down Expand Up @@ -1851,9 +1848,6 @@ def convert_image node, opts = {}
rendered_w = (image_info.calc_image_dimensions height: (rendered_h = available_h))[0] if rendered_h > available_h
end
add_dest_for_block node if node.id
# NOTE: workaround to fix Prawn not adding fill and stroke commands on page that only has an image;
# breakage occurs when running content (stamps) are added to page
update_colors if graphic_state.color_space.empty?
ink_caption node, category: :image, end: :top, block_align: alignment, block_width: rendered_w, max_width: caption_max_width if caption_end == :top && node.title?
image_y = y
left = bounds.left
Expand Down Expand Up @@ -3590,7 +3584,16 @@ def ink_running_content periphery, doc, skip = [1, 1], body_start_page_number =

pagenums_enabled = doc.attr? 'pagenums'
periphery_layout_cache = {}
# NOTE: this block is invoked during PDF generation, after #write -> #render_file and thus after #convert_document
# NOTE: Prawn fails to properly set color spaces on empty pages, but repeater relies on them
# prefer simpler fix below call to repeat; keep this workaround in case that workaround stops working
#(content_start_page_number..num_pages).each do |pgnum|
# next if (disable_on_pages.include? pgnum) || (pg = state.pages[pgnum - 1]).imported_page? || !pg.graphic_state.color_space.empty?
# go_to_page pgnum
# set_color_space :fill, (color_space graphic_state.fill_color)
# set_color_space :stroke, (color_space graphic_state.stroke_color)
#end
#go_to_page content_start_page_number if page_number != content_start_page_number
# NOTE: this block is invoked during PDF generation, during call to #write -> #render_file and thus after #convert_document
repeat (content_start_page_number..num_pages), dynamic: true do
pgnum = page_number
# NOTE: don't write on pages which are imported / inserts (otherwise we can get a corrupt PDF)
Expand Down Expand Up @@ -3701,7 +3704,11 @@ def ink_running_content periphery, doc, skip = [1, 1], body_start_page_number =
end
end
end

# NOTE: force repeater to consult color spaces on current page instead of the page on which repeater was created
# if this stops working, use the commented code above repeat call instead
unless (repeater_graphic_state = repeaters[-1].instance_variable_get :@graphic_state).singleton_methods.include? :color_space
repeater_graphic_state.define_singleton_method :color_space, &(method :page_color_space)
end
go_to_page prev_page_number
nil
end
Expand Down Expand Up @@ -4382,7 +4389,6 @@ def stamp_foreground_image doc, has_front_cover

def start_new_chapter chapter
start_new_page unless at_page_top?
# TODO: must call update_colors before advancing to next page if start_new_page is called in ink_chapter_title
start_new_page if @ppbook && verso_page? && !(chapter.option? 'nonfacing')
end

Expand Down Expand Up @@ -5062,6 +5068,10 @@ def on_image_error _reason, node, target, opts
nil
end

def page_color_space
page.graphic_state.color_space
end

def remove_tmp_files
@tmp_files.reject! {|_, path| path ? (unlink_tmp_file path) : true }
end
Expand Down
27 changes: 25 additions & 2 deletions spec/image_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1119,7 +1119,18 @@ def traverse node

(expect pdf.pages).to have_size 3
page_contents = pdf.objects[(pdf.page 2).page_object[:Contents]].data
(expect (page_contents.split ?\n).slice 0, 3).to eql ['q', '/DeviceRGB cs', '0.0 0.0 0.0 scn']
page_content_lines = page_contents.split ?\n
(expect page_content_lines.shift).to eql 'q'
(expect page_content_lines.shift).to eql 'q'
stack_size = 1
until (line = page_content_lines.shift).nil?
if line == 'q'
stack_size += 1
elsif line == 'Q'
break if (stack_size -= 1) == 0
end
end
(expect page_content_lines.slice 0, 3).to eql ['q', '/DeviceRGB cs', '0.0 0.0 0.0 scn']
end

it 'should set graphic state for running content when image does not occupy whole page' do
Expand Down Expand Up @@ -1340,7 +1351,19 @@ def traverse node

(expect pdf.pages).to have_size 3
page_contents = pdf.objects[(pdf.page 2).page_object[:Contents]].data
(expect (page_contents.split ?\n).slice 0, 3).to eql ['q', '/DeviceRGB cs', '0.0 0.0 0.0 scn']
page_content_lines = page_contents.split ?\n
(expect page_content_lines.shift).to eql 'q'
page_content_lines.shift if page_content_lines[0].empty?
(expect page_content_lines.shift).to eql 'q'
stack_size = 1
until (line = page_content_lines.shift).nil?
if line == 'q'
stack_size += 1
elsif line == 'Q'
break if (stack_size -= 1) == 0
end
end
(expect page_content_lines.slice 0, 3).to eql ['q', '/DeviceRGB cs', '0.0 0.0 0.0 scn']
end

it 'should place raster image in correct column when page columns are enabled' do
Expand Down
25 changes: 25 additions & 0 deletions spec/media_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -160,5 +160,30 @@
chapter_text = (pdf.find_text 'Chapter')[0]
(expect chapter_text[:page_number]).to be 2
end

it 'should initialize color space on empty verso pages', cli: true do
to_file = to_pdf_file <<~'EOS', 'running-content-on-empty-verso-pages.pdf', enable_footer: true
= Document Title
:doctype: book
:media: prepress
== Beginning
content
== Middle
content
== End
content
EOS

out, err, res = run_command 'pdftotext', to_file, '-'
(expect res.exitstatus).to be 0
(expect out).to include '4'
(expect err).to be_empty
end
end
end
23 changes: 23 additions & 0 deletions spec/running_content_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,29 @@
(expect text[0][:string]).to eql '1'
end

it 'should add running content to empty page' do
pdf = to_pdf <<~'EOS', enable_footer: true
first page
<<<
[%always]
<<<
third page
EOS
(expect pdf.pages).to have_size 3
(expect pdf.pages[1].text).to eql '2'
pdf.pages.each do |page|
contents = pdf.objects[page.page_object[:Contents]].data
content_lines = contents.lines
before_fill_color = (content_lines.slice 0, content_lines.index {|it| it.end_with? %( scn\n) }).join
before_stroke_color = (content_lines.slice 0, content_lines.index {|it| it.end_with? %( SCN\n) }).join
(expect before_fill_color).to include %(\n/DeviceRGB cs\n)
(expect before_stroke_color).to include %(\n/DeviceRGB CS\n)
end
end

it 'should start adding running content to page after imported page' do
pdf = to_pdf <<~'EOS', enable_footer: true, analyze: true
image::blue-letter.pdf[]
Expand Down

0 comments on commit c8a5c13

Please sign in to comment.