Skip to content

Commit

Permalink
Handle /SigFields, /DA und /Q from main AcroForm dictionary when merging
Browse files Browse the repository at this point in the history
  • Loading branch information
gettalong committed Sep 15, 2024
1 parent a63f5bc commit a764a39
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 2 deletions.
15 changes: 13 additions & 2 deletions lib/hexapdf/task/merge_acro_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,13 @@ def self.call(doc, source:, pages:)
acro_form.root_fields << root_field

# Merge the main AcroForm dictionary
font_name_mapping = merge_form_dictionary(acro_form, source.acro_form)
font_name_mapping = merge_form_dictionary(acro_form, source.acro_form, root_field)
font_name_re = font_name_mapping.keys.map {|name| Regexp.escape(name) }.join('|')
root_field[:DA] && root_field[:DA].sub!(font_name_re, font_name_mapping)

# Process all field widgets of the given pages
process_calculate_actions = false
signature_field_seen = false
pages.each do |page|
page.each_annotation do |widget|
next unless widget[:Subtype] == :Widget
Expand All @@ -99,6 +101,7 @@ def self.call(doc, source:, pages:)
field[:DA] && field[:DA].sub!(font_name_re, font_name_mapping)

process_calculate_actions = true if field[:AA]&.[](:C)
signature_field_seen = true if field.field_type == :Sig

# Add to the root field
field = field[:Parent] while field[:Parent]
Expand All @@ -111,11 +114,16 @@ def self.call(doc, source:, pages:)

# Update calculation JavaScript actions with changed field names
fix_calculate_actions(acro_form, source.acro_form, import_name) if process_calculate_actions

# Update signature flags if necessary
if signature_field_seen && source.acro_form.signature_flag?(:signatures_exist)
acro_form.signature_flag(:signatures_exist)
end
end

# Merges the AcroForm +source_form+ into the +target_form+ and returns a mapping of old font
# names to new ones.
def self.merge_form_dictionary(target_form, source_form)
def self.merge_form_dictionary(target_form, source_form, root_field)
target_resources = target_form.default_resources
font_name_mapping = {}
serializer = HexaPDF::Serializer.new
Expand All @@ -125,6 +133,9 @@ def self.merge_form_dictionary(target_form, source_form)
font_name_mapping[serializer.serialize(font_name)] = serializer.serialize(new_name)
end

root_field[:DA] = target_form.document.import(source_form[:DA])
root_field[:Q] = target_form.document.import(source_form[:Q])

font_name_mapping
end

Expand Down
21 changes: 21 additions & 0 deletions test/hexapdf/task/test_merge_acro_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,27 @@
assert(@doc.acro_form.default_resources[:Font].key?(:F2))
end

it "updates the /SigFlags if necessary" do
@doc.task(:merge_acro_form, source: @doc1, pages: [@pages[0]])
refute(@doc.acro_form.signature_flag?(:signatures_exist))

@pages[0][:Annots][0].form_field[:FT] = :Sig
@doc.task(:merge_acro_form, source: @doc1, pages: [@pages[0]])
refute(@doc.acro_form.signature_flag?(:signatures_exist))

@doc1.acro_form.signature_flag(:signatures_exist)
@doc.task(:merge_acro_form, source: @doc1, pages: [@pages[0]])
assert(@doc.acro_form.signature_flag?(:signatures_exist))
end

it "applies the /DA and /Q entries of the source AcroForm to the created root field" do
@doc1.acro_form.set_default_appearance_string
@doc1.acro_form[:Q] = @doc1.add(5)
@doc.task(:merge_acro_form, source: @doc1, pages: [@pages[0]])
assert_equal('0.0 g /F2 0 Tf', @root_fields[3][:DA])
assert_equal(5, @root_fields[3][:Q])
end

it "merges only the fields references in the given pages" do
@doc.task(:merge_acro_form, source: @doc1, pages: [@pages[0]])
assert_equal('merged_1', @root_fields[3][:T])
Expand Down

0 comments on commit a764a39

Please sign in to comment.