From 4ed29f32274308e3f9121e6dc378f78fa036c31a Mon Sep 17 00:00:00 2001 From: Dan Allen Date: Fri, 19 Jan 2024 01:26:42 -0700 Subject: [PATCH] resolves #2477 force color space to be set when setting up graphic 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 --- lib/asciidoctor/pdf/converter.rb | 25 ++++++++++++++++--------- spec/image_spec.rb | 27 +++++++++++++++++++++++++-- spec/media_spec.rb | 25 +++++++++++++++++++++++++ spec/running_content_spec.rb | 8 ++++++++ 4 files changed, 74 insertions(+), 11 deletions(-) diff --git a/lib/asciidoctor/pdf/converter.rb b/lib/asciidoctor/pdf/converter.rb index 63b07a2d7..305db1854 100644 --- a/lib/asciidoctor/pdf/converter.rb +++ b/lib/asciidoctor/pdf/converter.rb @@ -1826,9 +1826,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 left = bounds.left @@ -1867,9 +1864,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 @@ -3608,7 +3602,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) @@ -3719,7 +3722,12 @@ def ink_running_content periphery, doc, skip = [1, 1], body_start_page_number = end end end - + # NOTE: force repeater to save current graphic state per page instead of cloned graphic state of first page in sequence + # if this stops working, use the commented code above the call to repeat instead + current_page = method :page + (repeaters[-1].instance_variable_get :@graphic_state).define_singleton_method :color_space, (proc do + current_page.call.graphic_state.color_space + end) go_to_page prev_page_number nil end @@ -4413,7 +4421,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 diff --git a/spec/image_spec.rb b/spec/image_spec.rb index b519d6730..bdfcf873c 100644 --- a/spec/image_spec.rb +++ b/spec/image_spec.rb @@ -1176,7 +1176,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 end @@ -1399,7 +1410,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 diff --git a/spec/media_spec.rb b/spec/media_spec.rb index 45dbcb258..ab979b284 100644 --- a/spec/media_spec.rb +++ b/spec/media_spec.rb @@ -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 <<~'END', 'running-content-on-empty-verso-pages.pdf', enable_footer: true + = Document Title + :doctype: book + :media: prepress + + == Beginning + + content + + == Middle + + content + + == End + + content + END + + 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 diff --git a/spec/running_content_spec.rb b/spec/running_content_spec.rb index 0d9f4d18d..205a9df8d 100644 --- a/spec/running_content_spec.rb +++ b/spec/running_content_spec.rb @@ -35,6 +35,14 @@ END (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