代码之家  ›  专栏  ›  技术社区  ›  MrWater

如何使pdf签名可见(以及有效性图标)

  •  1
  • MrWater  · 技术社区  · 11 年前

    最初的问题是如何用Ruby显示pdf签名。我现在可以使用下面的代码了。

    我现在唯一的问题是有效性图标。它显示在 FoxIt Reader ,但未打开 Acrobat Reader (我现在正在使用XI)

    这就是我现在拥有的

    require 'openssl'
    
    begin
      require 'origami'
    rescue LoadError
      ORIGAMIDIR = "C:\RailsInstaller\Ruby1.9.3\lib\ruby\gems\1.9.1\gems\origami-1.2.4\lib"
      $: << ORIGAMIDIR
      require 'origami'
    end
    include Origami
    
    def draw_signature(name, attr = {})
      load! if @instructions.nil?
    
      x, y = attr[:x], attr[:y]
    
      @instructions << PDF::Instruction.new('q')
      @instructions << PDF::Instruction.new('cm', 1, 0, 0, 1, x, y)
      @instructions << PDF::Instruction.new('Do', name)
      @instructions << PDF::Instruction.new('Q')
    end
    
    def SignPdf(inputF)
    
        @inputfile = String.new(inputF)
        outputF = @inputfile.insert(inputF.rindex("."),"_signed8")
        certFile = "cert.pem"
        rsakeyFile = "pk.pem"
        passphrase = "mypass"
    
        key4pem=File.read rsakeyFile
        key = OpenSSL::PKey::RSA.new key4pem, passphrase
        cert = OpenSSL::X509::Certificate.new(File.read certFile)
    
        pdf = PDF.read(inputF)
        page = pdf.get_page(1)
    
    
    #signature image
    imageobject = Origami::Graphics::ImageXObject.from_image_file('c:\rails_projects\RecibosOnline\app\assets\images\logo.jpg', 'jpg')
    imageobject.Width = 200
    imageobject.Height = 141
    
     #formobject = Origami::Graphics::FormXObject.new
     #formobject.write("Teste")
    
    width = 300
    height=141
    x=201
    y=186
    
    signedby = "My Company"
    location = "Portugal"#pdf.signature[pdf.signature.keys[5]]
    contact = "mail@mail.com" #pdf.signature[pdf.signature.keys[6]]
    reason = "Testing" #pdf.signature[pdf.signature.keys[7]]
    date = Time.now
    
    caption="Digitally Signed By: #{signedby}\nContact: #{contact}\nLocation: #{location}\nReason: #{reason}\nDate: #{date} "
    
    n0 = Annotation::AppearanceStream.new
    n0.Type=Origami::Name.new("XObject")
    n0.BBox = [ 0, 0, 100, 100 ]
    n0.Matrix = [ 1, 0, 0, 1, 0, 0 ]
    n0.set_indirect(true)
    n0.Resources = Resources.new
    n0.Resources.ProcSet = [Origami::Name.new("PDF"),Origami::Name.new("Text"),Origami::Name.new("Text"),Origami::Name.new("ImageB"),Origami::Name.new("ImageC"),Origami::Name.new("ImageI")]
    n0.draw_stream('% DSBlank')
    #n0.write(Origami::Name.new("% DSBlank"))
    
    n2 = Annotation::AppearanceStream.new
    n2.Type = Origami::Name.new("XObject")
    #n2.Subtype = Origami::Name.new("Form")
    n2.Resources = Resources.new
    n2.Resources.ProcSet = [Origami::Name.new("Text")]
    n2.set_indirect(true)
    n2.Matrix = [ 1, 0, 0, 1, 0, 0 ]
    n2.BBox = [ 0, 0, width, height ]
    n2.write(caption,:x => 40, :y => height-35, :size => 15)
    #n2.draw_stream("q 0 0 198 48 re W n BT /Helv 7.645 Tf 0 g 0 40.135 Td (Digitally ) Tj 28.889 0 Td (signed ) Tj 24.652 0 Td (by ) Tj10.198 0 Td (James ) Tj 24.641 0 Td (Pravetz ) Tj-88.38 -9.174 Td (DN: ) Tj 15.29 0 Td (cn=James ) Tj37.18 0 Td (Pravetz, ) Tj 30.165 0 Td (c=CA, ) Tj 23.156 0 Td0 -9.174 Td (Reason: ) Tj 30.599 0 Td (I ) Tj 4.248 0 Td(have ) Tj 18.702 0 Td (reviewed ) Tj 32.719 0 Td(this ) Tj 14.02 0 Td (document ) Tj -100.288 -9.174 Td(Date: ) Tj 20.397 0 Td (2006.06.08 ) Tj 40.386 0 Td(13:39:35 ) Tj 31.883 0 Td (-07'00') Tj ET Q")
    
    #Sets the root dictionary element
    
    frm = Annotation::AppearanceStream.new
    frm.set_indirect(true)
    #frm.Type = Origami::Name.new("XObject")
    #frm.Subtype = Origami::Name.new("Form")
    frm.Resources = Resources.new
    frm.Resources.ProcSet = [Origami::Name.new("PDF")]
    frm.Resources.add_xobject(Origami::Name.new("n0"), n0)
    frm.Resources.add_xobject(Origami::Name.new("n2"), n2)
    frm.Matrix = [ 1, 0, 0, 1, 0, 0 ]
    frm.BBox = [ 0, 0, width, height ]
    frm.draw_stream('q 1 0 0 1 0 0 cm /n0 Do Q')
    frm.draw_stream('q 1 0 0 1 0 0 cm /n2 Do Q')
    
    
    
    
    xo17 = Annotation::Widget::Signature.new
    #xo17 = Annotation::Widget::Signature.new
    xo17.Rect = Rectangle[ llx: x, lly: y, urx: x+width, ury: y+height ]
    #xo17.Resources = Resources.new
    #xo17.Resources.add_xobject(Origami::Name.new("FRM"), frm)
    xo17.F = Annotation::Flags::PRINT #sets the print mode on
    xo17.H = Annotation::Widget::Highlight::INVERT
    
    streamN = Annotation::AppearanceStream.new #.setFilter(:FlateDecode)
    streamN.set_indirect(true)
    streamN.BBox = [ 0, 0, width, height ]
    streamN.Resources = Resources.new
    streamN.Resources.ProcSet = [Origami::Name.new("PDF")]
    streamN.Resources.add_xobject(Origami::Name.new("FRM"), frm)
    streamN.Subtype = nil
    #cs = ContentStream.new('q 1 0 0 1 0 0 cm /FRM Do Q',streamN)
    streamN.draw_stream('q 1 0 0 1 0 0 cm /FRM Do Q')
    #streamN.draw_image(Origami::Name.new("FRM"),{x:x,y:y})
    #streamN.write(caption,:x => 40, :y => height-35, :size => 15)
    xo17.set_normal_appearance(streamN)
    
    # page.add_xobject(Origami::Name.new("FRM"),frm)
    # page.add_xobject(Origami::Name.new("n0"),n0)
    # page.add_xobject(Origami::Name.new("n2"),n2)
    
    page.add_annot(xo17)    
    
    # Sign the PDF with the specified keys
    pdf.sign(cert, key, 
      :method => 'adbe.pkcs7.sha1',
      :annotation => xo17, 
      :location => location, 
      :contact => contact, 
      :reason => reason
    )
    
    # Save the resulting file
    pdf.save(outputF)
    
    
    end
    SignPdf("Sample.pdf")
    

    编辑2

    在mkl介入之后,我更深入地了解了消息来源。。。

    我注意到 xobject.rb 文件,带有以下用于绘制图像的代码

    def draw_image(name, attr = {})
          load! if @instructions.nil?
    
          x, y = attr[:x], attr[:y]
    
          @instructions << PDF::Instruction.new('q')
          @instructions << PDF::Instruction.new('cm', 300, 0, 0, 300, x, y)
          @instructions << PDF::Instruction.new('Do', name)
          @instructions << PDF::Instruction.new('Q')
    end
    

    然后我在同一个文件上创建了下面的方法

    def draw_stream(name)
          load! if @instructions.nil?
    
          @instructions << PDF::Instruction.new(name)
    end
    

    这允许我从其输入控制流。

    我也去了 ISO32000:2008 ,并对我的代码进行了一点迭代,但没有进一步深入。

    这是我当前生成的 pdf file ,以及其中与签名有关的部分:

    16 0 obj
    <<
        /Rect [ 201 186 501 327 ]
        /F 4
        /H /I
        /AP <<
            /N 18 0 R
        >>
        /P 1 0 R
        /V 17 0 R
        /T (undef28504)
        /Subtype /Widget
        /FT /Sig
        /DA (/F1 10 Tf 0 g)
    >>
    endobj
    17 0 obj
    <<
        /Type /Sig
        /SubFilter /adbe.pkcs7.sha1
        /Reason <54657374696E67>
        /Prop_Build <<
            /Filter <<
                /Name /Adobe.PPKMS
                /R 131101
                /Date (2013-04-03 14:18:41 +0100)
            >>
            /SigQ <<
                /Preview false
                /R 131101
            >>
            /PubSec <<
                /NonEFontNoWarn false
                /Date (2013-04-03 14:18:41 +0100)
                /R 131101
            >>
            /App <<
                /TrustedMode false
                /OS [ /Win ]
                /R 458752
                /Name /Exchange-Pro
            >>
        >>
        /M (D:20130403131841Z00'00)
        /Location <506F72747567616C>
        /Filter /Adobe.PPKMS
        /Contents <308207AE06092A864886F70D010702A082079F3082079B020101310B300906052B0E03021A0500302306092A864886F70D010701A0160414BBA1B7480DDB1B75B136B4DFA2A4C120EC7972DFA0820597308205933082047BA0030201020204426F938C300D06092A864886F70D0101050500303E310B300906035504061302707431153013060355040A130C4D554C5449434552542D4341311830160603550403130F4D554C5449434552542D4341203032301E170D3133303332303137303134375A170D3134303332303136343733365A3081A5310B300906035504061302505431153013060355040A130C4D554C5449434552542D434131163014060355040B130D4345525449504F52202D20524131123010060355040B1309436F72706F726174653120301E060355040B13174553435249544120494E54454C4947454E5445204C444131183016060355040B130F576562204170706C69636174696F6E311730150603550403130E52454349424F53204F4E4C494E4530819F300D06092A864886F70D010101050003818D0030818902818100ACCEA4069031B578896C450D77C83C13DD75C668BF2762368DB0A0B1591B1800E58C1ACDBB25DA15501AF931F9F6BAE0F8F64C481686E959DE005AEC82B33D0D32665037D18BF36BF77C4D56620C42FBBA92D3FF397F9D8377FEABBA93478FCEF009216483D346ACCC76CA10C9B8653B80B8F6EB49BD93897A43DF062D0D9ED30203010001A38202B3308202AF300B0603551D0F0404030203F8303806082B06010505070101042C302A302806082B06010505073001861C687474703A2F2F6F6373702E6D756C7469636572742E636F6D2F63613081E00603551D200481D83081D5304D06092B06010401B03C0A023040303E06082B060105050702011632687474703A2F2F7777772E6D756C7469636572742E636F6D2F6370732F6D756C7469636572742D63612D6370732E68746D6C308183060B2B06010401B03C0A0288063074307206082B0601050507020230661E640068007400740070003A002F002F007700770077002E006D0075006C007400690063006500720074002E0063006F006D002F00630070002F006D0075006C007400690063006500720074002D00630061002D0031003000330030002E00680074006D006C301106096086480186F84201010404030204B030200603551D11041930178115696E666F4072656369626F736F6E6C696E652E7074308201010603551D1F0481F93081F630819AA08197A08194862F687474703A2F2F7777772E6D756C7469636572742E636F6D2F63612F6D756C7469636572742D63612D30322E63726C86616C6461703A2F2F6C6461702E6D756C7469636572742E636F6D2F636E3D4D554C5449434552542D434125323030322C6F3D4D554C5449434552542D43412C633D50543F63657274696669636174655265766F636174696F6E4C6973743F626173653057A055A053A451304F310B300906035504061302707431153013060355040A130C4D554C5449434552542D4341311830160603550403130F4D554C5449434552542D4341203032310F300D0603550403130643524C323935301F0603551D230418301680141DC3B988A518BE60A72CA663CA662AFC0C27C1BD301D0603551D0E0416041406D81F7236619EEB17369C299E2D74FFD038301930090603551D1304023000300D06092A864886F70D0101050500038201010041511FCD5C7561981B0D54326B57F7B87C435AACB7A2962808768313892AB1407237E957577B875414DE810A41323F9E0A768E9AC45C0F66AE093C32C11453C6463F856FEF62E27821134DD09F75208000040E89A814E6309623C5D04163C03CFDE33153908AC3DFCA5B1C66C3DCB89644A3030FE794D50BD255D396535A7AF267C3A538147B9371D05F23D8CA481AEBC7D7A7D97C2E7FB5AB49C4E4554E4800648BC76B1AF5612A1D9361D172084E70690928A911FC209833C506219CF186B6507B599E4C0F42F3BF23C2B8F0A078D01D9BF5FD4746D97253EE4FE8F472489B3DC26F7072C6587218825BB3061074B9C240F8928D36FEFC0F708897752CD946318201C7308201C30201013046303E310B300906035504061302707431153013060355040A130C4D554C5449434552542D4341311830160603550403130F4D554C5449434552542D43412030320204426F938C300906052B0E03021A0500A081D8301806092A864886F70D010903310B06092A864886F70D010701301C06092A864886F70D010905310F170D3133303430333133313834315A302306092A864886F70D010904311604142948A25663C43F9571225B0F12B9097DFE7149DB307906092A864886F70D01090F316C306A300B060960864801650304012A300B0609608648016503040116300B0609608648016503040102300A06082A864886F70D0307300E06082A864886F70D030202020080300D06082A864886F70D0302020140300706052B0E030207300D06082A864886F70D0302020128300D06092A864886F70D010101050004818021F8A3A104E8B6EC1D9026CA9A822C4357EEBAABD5D87422BE6199802F45E83E9D2417711CE26DCB28A8246ACE119B128956394A8FA641346E5F3CBBDD84ED7E36B2F947DD5D92EC1C2C078A1630A729773F17027FC3B64C18844C26F7FA18A7B4FC9DE334741235E178280ED25CD8840A83A91FCE240646EB84117E348BF82E0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000>
        /ContactInfo <6D61696C406D61696C2E636F6D>
        /ByteRange [ 0 12880 17078 2366 ]
    >>
    endobj
    18 0 obj
    <<
        /BBox [ 0 0 300 141 ]
        /Resources <<
            /ProcSet [ /PDF ]
            /XObject <<
                /FRM 19 0 R
            >>
            /Font <<
                /F1 <<
                    /Type /Font
                    /Subtype /Type1
                    /BaseFont /Helvetica
                    /Name /F1
                >>
            >>
        >>
        /Length 27
        /Subtype /Form
    >>stream
    q 1 0 0 1 0 0 cm /FRM Do Q
    
    endstream
    endobj
    19 0 obj
    <<
        /Resources <<
            /ProcSet [ /PDF ]
            /XObject <<
                /n0 20 0 R
                /n2 21 0 R
            >>
            /Font <<
                /F1 <<
                    /Type /Font
                    /Subtype /Type1
                    /BaseFont /Helvetica
                    /Name /F1
                >>
            >>
        >>
        /Matrix [ 1 0 0 1 0 0 ]
        /BBox [ 0 0 300 141 ]
        /Length 52
        /Subtype /Form
    >>stream
    q 1 0 0 1 0 0 cm /n0 Do Q
    q 1 0 0 1 0 0 cm /n2 Do Q
    
    endstream
    endobj
    20 0 obj
    <<
        /Type /XObject
        /BBox [ 0 0 100 100 ]
        /Matrix [ 1 0 0 1 0 0 ]
        /Resources <<
            /ProcSet [ /PDF /Text /Text /ImageB /ImageC /ImageI ]
            /Font <<
                /F1 <<
                    /Type /Font
                    /Subtype /Type1
                    /BaseFont /Helvetica
                    /Name /F1
                >>
            >>
        >>
        /Length 10
        /Subtype /Form
    >>stream
    % DSBlank
    
    endstream
    endobj
    21 0 obj
    <<
        /Type /XObject
        /Resources <<
            /ProcSet [ /Text ]
            /Font <<
                /F1 <<
                    /Type /Font
                    /Subtype /Type1
                    /BaseFont /Helvetica
                    /Name /F1
                >>
            >>
        >>
        /Matrix [ 1 0 0 1 0 0 ]
        /BBox [ 0 0 300 141 ]
        /Length 176
        /Subtype /Form
    >>stream
    BT
    /F1 15 Tf
    40 106 Td
    20 TL
    (Digitally Signed By: My Company) Tj
    (Contact: mail@mail.com) '
    (Location: Portugal) '
    (Reason: Testing) '
    (Date: 2013-04-03 14:18:41 +0100 ) '
    ET
    
    endstream
    endobj
    22 0 obj
    <<
        /Fields [ 16 0 R ]
        /SigFlags 3
    >>
    endobj
    

    我错过了什么?

    1 回复  |  直到 11 年前
        1
  •  1
  •   MrWater    11 年前

    有时候,一个男人只需要知道如何真正理解他一遍又一遍地读到的东西。。。

    ppkapperances文件中包含了所有内容。在遵守他们推荐的词典结构方面,我甚至没有达到预期的程度。 我只需要添加n1和n3层,流内容甚至可以只是“%DS空白”。你找到的问号字符串流就是我从中提取的 PdfSignatureAppearance.cs 文件来自 iText 解决方案如果我使用一个Foxit阅读器,它会显示问号(即使签名有效)。对于Adobe来说,我使用它或 DSBlank .

    require 'openssl'
    
    begin
      require 'origami'
    rescue LoadError
      ORIGAMIDIR = "C:\RailsInstaller\Ruby1.9.3\lib\ruby\gems\1.9.1\gems\origami-1.2.4\lib"
      $: << ORIGAMIDIR
      require 'origami'
    end
    include Origami
    
    def draw_signature(name, attr = {})
      load! if @instructions.nil?
    
      x, y = attr[:x], attr[:y]
    
      @instructions << PDF::Instruction.new('q')
      @instructions << PDF::Instruction.new('cm', 1, 0, 0, 1, x, y)
      @instructions << PDF::Instruction.new('Do', name)
      @instructions << PDF::Instruction.new('Q')
    end
    
    def SignPdf(inputF)
    
        @inputfile = String.new(inputF)
        outputF = @inputfile.insert(inputF.rindex("."),"_signed8")
        certFile = "cert.pem"
        rsakeyFile = "pk.pem"
        passphrase = "mypass"
    
        key4pem=File.read rsakeyFile
        key = OpenSSL::PKey::RSA.new key4pem, passphrase
        cert = OpenSSL::X509::Certificate.new(File.read certFile)
    
        pdf = PDF.read(inputF)
        page = pdf.get_page(1)
    
    
    #signature image
    imageobject = Origami::Graphics::ImageXObject.from_image_file('c:\rails_projects\RecibosOnline\app\assets\images\logo.jpg', 'jpg')
    imageobject.Width = 200
    imageobject.Height = 141
    
     #formobject = Origami::Graphics::FormXObject.new
     #formobject.write("Teste")
    
    width = 300
    height=141
    x=201
    y=186
    
    signedby = "My Company"
    location = "Portugal"#pdf.signature[pdf.signature.keys[5]]
    contact = "mail@mail.com" #pdf.signature[pdf.signature.keys[6]]
    reason = "Testing" #pdf.signature[pdf.signature.keys[7]]
    date = Time.now
    
    caption="Digitally Signed By: #{signedby}\nContact: #{contact}\nLocation: #{location}\nReason: #{reason}\nDate: #{date} "
    
        #DSBlankstream= "% DSBLank"
    
        questionMark = "% DSUnknown\n" +
                "q\n" +
                "1 G\n" +
                "1 g\n" +
                "0.1 0 0 0.1 9 0 cm\n" +
                "0 J 0 j 4 M []0 d\n" +
                "1 i \n" +
                "0 g\n" +
                "313 292 m\n" +
                "313 404 325 453 432 529 c\n" +
                "478 561 504 597 504 645 c\n" +
                "504 736 440 760 391 760 c\n" +
                "286 760 271 681 265 626 c\n" +
                "265 625 l\n" +
                "100 625 l\n" +
                "100 828 253 898 381 898 c\n" +
                "451 898 679 878 679 650 c\n" +
                "679 555 628 499 538 435 c\n" +
                "488 399 467 376 467 292 c\n" +
                "313 292 l\n" +
                "h\n" +
                "308 214 170 -164 re\n" +
                "f\n" +
                "0.44 G\n" +
                "1.2 w\n" +
                "1 1 0.4 rg\n" +
                "287 318 m\n" +
                "287 430 299 479 406 555 c\n" +
                "451 587 478 623 478 671 c\n" +
                "478 762 414 786 365 786 c\n" +
                "260 786 245 707 239 652 c\n" +
                "239 651 l\n" +
                "74 651 l\n" +
                "74 854 227 924 355 924 c\n" +
                "425 924 653 904 653 676 c\n" +
                "653 581 602 525 512 461 c\n" +
                "462 425 441 402 441 318 c\n" +
                "287 318 l\n" +
                "h\n" +
                "282 240 170 -164 re\n" +
                "B\n" +
                "Q\n";
    
        n0 = Annotation::AppearanceStream.new
        n0.Type=Origami::Name.new("XObject")
        n0.BBox = [ 0, 0, 100, 100 ]
        n0.Matrix = [ 1, 0, 0, 1, 0, 0 ]
        n0.set_indirect(true)
        n0.Resources = Resources.new
        n0.Resources.ProcSet = [Origami::Name.new("PDF"),Origami::Name.new("Text"),Origami::Name.new("Text"),Origami::Name.new("ImageB"),Origami::Name.new("ImageC"),Origami::Name.new("ImageI")]
        n0.draw_stream('% DSBlank')
        #n0.write(Origami::Name.new("% DSBlank"))
    
    
        n1 = Annotation::AppearanceStream.new
        n1.Type=Origami::Name.new("XObject")
        n1.BBox = [ 0, 0, 100, 100 ]
        n1.Matrix = [ 1, 0, 0, 1, 0, 0 ]
        n1.set_indirect(true)
        n1.Resources = Resources.new
        n1.Resources.ProcSet = [Origami::Name.new("PDF"),Origami::Name.new("Text"),Origami::Name.new("Text"),Origami::Name.new("ImageB"),Origami::Name.new("ImageC"),Origami::Name.new("ImageI")]
        n1.draw_stream('% DSBlank')
    
        n3 = Annotation::AppearanceStream.new
        n3.Type=Origami::Name.new("XObject")
        n3.BBox = [ 0, 0, 100, 100 ]
        n3.Matrix = [ 1, 0, 0, 1, 0, 0 ]
        n3.set_indirect(true)
        n3.Resources = Resources.new
        n3.Resources.ProcSet = [Origami::Name.new("PDF"),Origami::Name.new("Text"),Origami::Name.new("Text"),Origami::Name.new("ImageB"),Origami::Name.new("ImageC"),Origami::Name.new("ImageI")]
        n3.draw_stream('% DSBlank')
    
        n2 = Annotation::AppearanceStream.new
        n2.Type = Origami::Name.new("XObject")
        #n2.Subtype = Origami::Name.new("Form")
        n2.Resources = Resources.new
        n2.Resources.ProcSet = [Origami::Name.new("Text")]
        n2.set_indirect(true)
        n2.Matrix = [ 1, 0, 0, 1, 0, 0 ]
        n2.BBox = [ 0, 0, width, height ]
        n2.write(caption,:x => 40, :y => height-35, :size => 15)
        #n2.draw_stream("q 0 0 198 48 re W n BT /Helv 7.645 Tf 0 g 0 40.135 Td (Digitally ) Tj 28.889 0 Td (signed ) Tj 24.652 0 Td (by ) Tj10.198 0 Td (James ) Tj 24.641 0 Td (Pravetz ) Tj-88.38 -9.174 Td (DN: ) Tj 15.29 0 Td (cn=James ) Tj37.18 0 Td (Pravetz, ) Tj 30.165 0 Td (c=CA, ) Tj 23.156 0 Td0 -9.174 Td (Reason: ) Tj 30.599 0 Td (I ) Tj 4.248 0 Td(have ) Tj 18.702 0 Td (reviewed ) Tj 32.719 0 Td(this ) Tj 14.02 0 Td (document ) Tj -100.288 -9.174 Td(Date: ) Tj 20.397 0 Td (2006.06.08 ) Tj 40.386 0 Td(13:39:35 ) Tj 31.883 0 Td (-07'00') Tj ET Q")
    
    ##Sets the root dictionary element
    
        frm = Annotation::AppearanceStream.new
        frm.set_indirect(true)
        #frm.Type = Origami::Name.new("XObject")
        #frm.Subtype = Origami::Name.new("Form")
        frm.Resources = Resources.new
        frm.Resources.ProcSet = [Origami::Name.new("PDF")]
        frm.Resources.add_xobject(Origami::Name.new("n0"), n0)
        frm.Resources.add_xobject(Origami::Name.new("n1"), n1)
        frm.Resources.add_xobject(Origami::Name.new("n2"), n2)
        frm.Resources.add_xobject(Origami::Name.new("n3"), n3)
        frm.Matrix = [ 1, 0, 0, 1, 0, 0 ]
        frm.BBox = [ 0, 0, width, height ]
        frm.draw_stream('q 1 0 0 1 0 0 cm /n0 Do Q')
        frm.draw_stream('q 1 0 0 1 0 0 cm /n1 Do Q')
        frm.draw_stream('q 1 0 0 1 0 0 cm /n2 Do Q')
        frm.draw_stream('q 1 0 0 1 0 0 cm /n3 Do Q')
    
    
        xo17 = Annotation::Widget::Signature.new
        #xo17 = Annotation::Widget::Signature.new
        xo17.Rect = Rectangle[ llx: x, lly: y, urx: x+width, ury: y+height ]
        #xo17.Resources = Resources.new
        #xo17.Resources.add_xobject(Origami::Name.new("FRM"), frm)
        xo17.F = Annotation::Flags::PRINT #sets the print mode on
        xo17.H = Annotation::Widget::Highlight::INVERT
    
        streamN = Annotation::AppearanceStream.new #.setFilter(:FlateDecode)
        streamN.set_indirect(true)
        streamN.BBox = [ 0, 0, width, height ]
        streamN.Resources = Resources.new
        streamN.Resources.ProcSet = [Origami::Name.new("PDF")]
        streamN.Resources.add_xobject(Origami::Name.new("FRM"), frm)
        streamN.Subtype = nil
        #cs = ContentStream.new('q 1 0 0 1 0 0 cm /FRM Do Q',streamN)
        streamN.draw_stream('q 1 0 0 1 0 0 cm /FRM Do Q')
        #streamN.draw_image(Origami::Name.new("FRM"),{x:x,y:y})
        #streamN.write(caption,:x => 40, :y => height-35, :size => 15)
        xo17.set_normal_appearance(streamN)
    
        # page.add_xobject(Origami::Name.new("FRM"),frm)
        # page.add_xobject(Origami::Name.new("n0"),n0)
        # page.add_xobject(Origami::Name.new("n2"),n2)
    
        page.add_annot(xo17)    
    
        # Sign the PDF with the specified keys
        pdf.sign(cert, key, 
          :method => 'adbe.pkcs7.sha1',
          :annotation => xo17, 
          :location => location, 
          :contact => contact, 
          :reason => reason
        )
    
        # Save the resulting file
        pdf.save(outputF)
    
    
    end
    
    SignPdf("Sample.pdf")
    

    多么激烈的战斗!

    我想说:

    最终,胜利者是那些站在战场中央的人。悲伤地看着他们周围的战场,想知道为什么会这样。只有当他们知道如何阅读。。。那么这些事情就不会发生了。然而,与此同时,如果这件事没有发生,他们就不知道自己不知道如何以正确的焦点阅读。