origami 1.2.7 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -0
  3. data/README.md +112 -0
  4. data/bin/config/pdfcop.conf.yml +232 -233
  5. data/bin/gui/about.rb +27 -37
  6. data/bin/gui/config.rb +108 -117
  7. data/bin/gui/file.rb +416 -365
  8. data/bin/gui/gtkhex.rb +1138 -1153
  9. data/bin/gui/hexview.rb +55 -57
  10. data/bin/gui/imgview.rb +48 -51
  11. data/bin/gui/menu.rb +388 -386
  12. data/bin/gui/properties.rb +114 -130
  13. data/bin/gui/signing.rb +571 -617
  14. data/bin/gui/textview.rb +77 -95
  15. data/bin/gui/treeview.rb +382 -387
  16. data/bin/gui/walker.rb +227 -232
  17. data/bin/gui/xrefs.rb +56 -60
  18. data/bin/pdf2pdfa +53 -57
  19. data/bin/pdf2ruby +212 -228
  20. data/bin/pdfcop +338 -348
  21. data/bin/pdfdecompress +58 -65
  22. data/bin/pdfdecrypt +56 -60
  23. data/bin/pdfencrypt +75 -80
  24. data/bin/pdfexplode +185 -182
  25. data/bin/pdfextract +201 -218
  26. data/bin/pdfmetadata +83 -82
  27. data/bin/pdfsh +4 -5
  28. data/bin/pdfwalker +1 -2
  29. data/bin/shell/.irbrc +45 -82
  30. data/bin/shell/console.rb +105 -130
  31. data/bin/shell/hexdump.rb +40 -64
  32. data/examples/README.md +34 -0
  33. data/examples/attachments/attachment.rb +38 -0
  34. data/examples/attachments/nested_document.rb +51 -0
  35. data/examples/encryption/encryption.rb +28 -0
  36. data/{samples/actions/triggerevents/trigger.rb → examples/events/events.rb} +13 -16
  37. data/examples/flash/flash.rb +37 -0
  38. data/{samples → examples}/flash/helloworld.swf +0 -0
  39. data/examples/forms/javascript.rb +54 -0
  40. data/examples/forms/xfa.rb +115 -0
  41. data/examples/javascript/hello_world.rb +22 -0
  42. data/examples/javascript/js_emulation.rb +54 -0
  43. data/examples/loop/goto.rb +32 -0
  44. data/examples/loop/named.rb +33 -0
  45. data/examples/signature/signature.rb +65 -0
  46. data/examples/uri/javascript.rb +56 -0
  47. data/examples/uri/open-uri.rb +21 -0
  48. data/examples/uri/submitform.rb +47 -0
  49. data/lib/origami.rb +29 -42
  50. data/lib/origami/3d.rb +350 -225
  51. data/lib/origami/acroform.rb +262 -288
  52. data/lib/origami/actions.rb +268 -288
  53. data/lib/origami/annotations.rb +697 -722
  54. data/lib/origami/array.rb +258 -184
  55. data/lib/origami/boolean.rb +74 -84
  56. data/lib/origami/catalog.rb +397 -434
  57. data/lib/origami/collections.rb +144 -0
  58. data/lib/origami/destinations.rb +233 -194
  59. data/lib/origami/dictionary.rb +253 -232
  60. data/lib/origami/encryption.rb +1274 -1243
  61. data/lib/origami/export.rb +232 -268
  62. data/lib/origami/extensions/fdf.rb +307 -220
  63. data/lib/origami/extensions/ppklite.rb +368 -435
  64. data/lib/origami/filespec.rb +197 -0
  65. data/lib/origami/filters.rb +301 -295
  66. data/lib/origami/filters/ascii.rb +177 -180
  67. data/lib/origami/filters/ccitt.rb +528 -535
  68. data/lib/origami/filters/crypt.rb +26 -35
  69. data/lib/origami/filters/dct.rb +46 -52
  70. data/lib/origami/filters/flate.rb +95 -94
  71. data/lib/origami/filters/jbig2.rb +49 -55
  72. data/lib/origami/filters/jpx.rb +38 -44
  73. data/lib/origami/filters/lzw.rb +189 -183
  74. data/lib/origami/filters/predictors.rb +221 -235
  75. data/lib/origami/filters/runlength.rb +103 -104
  76. data/lib/origami/font.rb +173 -186
  77. data/lib/origami/functions.rb +67 -81
  78. data/lib/origami/graphics.rb +25 -21
  79. data/lib/origami/graphics/colors.rb +178 -187
  80. data/lib/origami/graphics/instruction.rb +79 -85
  81. data/lib/origami/graphics/path.rb +142 -148
  82. data/lib/origami/graphics/patterns.rb +160 -167
  83. data/lib/origami/graphics/render.rb +43 -50
  84. data/lib/origami/graphics/state.rb +138 -153
  85. data/lib/origami/graphics/text.rb +188 -205
  86. data/lib/origami/graphics/xobject.rb +819 -815
  87. data/lib/origami/header.rb +63 -78
  88. data/lib/origami/javascript.rb +596 -597
  89. data/lib/origami/linearization.rb +285 -290
  90. data/lib/origami/metadata.rb +139 -148
  91. data/lib/origami/name.rb +112 -148
  92. data/lib/origami/null.rb +53 -62
  93. data/lib/origami/numeric.rb +162 -175
  94. data/lib/origami/obfuscation.rb +186 -174
  95. data/lib/origami/object.rb +593 -573
  96. data/lib/origami/outline.rb +42 -47
  97. data/lib/origami/outputintents.rb +73 -82
  98. data/lib/origami/page.rb +703 -592
  99. data/lib/origami/parser.rb +238 -290
  100. data/lib/origami/parsers/fdf.rb +41 -33
  101. data/lib/origami/parsers/pdf.rb +75 -95
  102. data/lib/origami/parsers/pdf/lazy.rb +137 -0
  103. data/lib/origami/parsers/pdf/linear.rb +64 -66
  104. data/lib/origami/parsers/ppklite.rb +34 -70
  105. data/lib/origami/pdf.rb +1030 -1005
  106. data/lib/origami/reference.rb +102 -102
  107. data/lib/origami/signature.rb +591 -609
  108. data/lib/origami/stream.rb +668 -551
  109. data/lib/origami/string.rb +397 -373
  110. data/lib/origami/template/patterns.rb +56 -0
  111. data/lib/origami/template/widgets.rb +151 -0
  112. data/lib/origami/trailer.rb +144 -158
  113. data/lib/origami/tree.rb +62 -0
  114. data/lib/origami/version.rb +23 -0
  115. data/lib/origami/webcapture.rb +88 -79
  116. data/lib/origami/xfa.rb +2863 -2882
  117. data/lib/origami/xreftable.rb +472 -384
  118. data/test/dataset/calc.pdf +85 -0
  119. data/test/dataset/crypto.pdf +82 -0
  120. data/test/dataset/empty.pdf +49 -0
  121. data/test/test_actions.rb +27 -0
  122. data/test/test_annotations.rb +90 -0
  123. data/test/test_pages.rb +31 -0
  124. data/test/test_pdf.rb +16 -0
  125. data/test/test_pdf_attachment.rb +34 -0
  126. data/test/test_pdf_create.rb +24 -0
  127. data/test/test_pdf_encrypt.rb +95 -0
  128. data/test/test_pdf_parse.rb +96 -0
  129. data/test/test_pdf_sign.rb +58 -0
  130. data/test/test_streams.rb +182 -0
  131. data/test/test_xrefs.rb +67 -0
  132. metadata +88 -58
  133. data/README +0 -67
  134. data/bin/pdf2graph +0 -121
  135. data/bin/pdfcocoon +0 -104
  136. data/lib/origami/file.rb +0 -233
  137. data/samples/README.txt +0 -45
  138. data/samples/actions/launch/calc.rb +0 -87
  139. data/samples/actions/launch/winparams.rb +0 -22
  140. data/samples/actions/loop/loopgoto.rb +0 -24
  141. data/samples/actions/loop/loopnamed.rb +0 -21
  142. data/samples/actions/named/named.rb +0 -31
  143. data/samples/actions/samba/smbrelay.rb +0 -26
  144. data/samples/actions/webbug/submitform.js +0 -26
  145. data/samples/actions/webbug/webbug-browser.rb +0 -68
  146. data/samples/actions/webbug/webbug-js.rb +0 -67
  147. data/samples/actions/webbug/webbug-reader.rb +0 -90
  148. data/samples/attachments/attach.rb +0 -40
  149. data/samples/attachments/attached.txt +0 -1
  150. data/samples/crypto/crypto.rb +0 -28
  151. data/samples/digsig/signed.rb +0 -46
  152. data/samples/exploits/cve-2008-2992-utilprintf.rb +0 -87
  153. data/samples/exploits/cve-2009-0927-geticon.rb +0 -65
  154. data/samples/exploits/exploit_customdictopen.rb +0 -55
  155. data/samples/exploits/getannots.rb +0 -69
  156. data/samples/flash/flash.rb +0 -31
  157. data/samples/javascript/attached.txt +0 -1
  158. data/samples/javascript/js.rb +0 -52
  159. data/templates/patterns.rb +0 -66
  160. data/templates/widgets.rb +0 -173
  161. data/templates/xdp.rb +0 -92
  162. data/test/ts_pdf.rb +0 -50
@@ -1,83 +1,59 @@
1
1
  =begin
2
2
 
3
- = File
4
- hexdump.rb
3
+ This file is part of Origami, PDF manipulation framework for Ruby
4
+ Copyright (C) 2016 Guillaume Delugré.
5
5
 
6
- = Info
7
- This file is part of Origami, PDF manipulation framework for Ruby
8
- Copyright (C) 2009 Guillaume Delugr� <guillaume@security-labs.org>
9
- All right reserved.
10
-
11
- Origami is free software: you can redistribute it and/or modify
12
- it under the terms of the GNU General Public License as published by
13
- the Free Software Foundation, either version 3 of the License, or
14
- (at your option) any later version.
6
+ Origami is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
15
10
 
16
- Origami is distributed in the hope that it will be useful,
17
- but WITHOUT ANY WARRANTY; without even the implied warranty of
18
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
- GNU General Public License for more details.
11
+ Origami is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
20
15
 
21
- You should have received a copy of the GNU General Public License
22
- along with Origami. If not, see <http://www.gnu.org/licenses/>.
16
+ You should have received a copy of the GNU General Public License
17
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
23
18
 
24
19
  =end
25
20
 
26
- if RUBY_VERSION < '1.9'
27
- class Fixnum
28
- def ord; self; end
29
- end
30
- end
21
+ require 'colorize'
31
22
 
32
23
  class String #:nodoc:
33
24
 
34
- def hexdump(bytesperline = 16, upcase = true, offsets = true, delta = 0)
35
-
36
- dump = ""
37
- counter = 0
25
+ def hexdump(bytesperline: 16, upcase: true, offsets: true, delta: 0)
26
+ dump = ""
27
+ counter = 0
38
28
 
39
- while counter < length
29
+ while counter < length
30
+ offset = sprintf("%010X", counter + delta)
40
31
 
41
- offset = sprintf("%010X", counter + delta)
32
+ linelen = (counter < length - bytesperline) ? bytesperline : (length - counter)
33
+ bytes = ""
34
+ linelen.times do |i|
35
+ byte = self[counter + i].ord.to_s(16)
36
+ byte.insert(0, "0") if byte.size < 2
37
+ bytes << byte
38
+ bytes << " " unless i == bytesperline - 1
39
+ end
40
+
41
+ ascii = self[counter, linelen].ascii_print
42
42
 
43
- linelen = (counter < length - bytesperline) ? bytesperline : (length - counter)
44
- bytes = ""
45
- linelen.times do |i|
46
-
47
- byte = self[counter + i].ord.to_s(base=16)
48
- if byte.size < 2 then byte.insert(0, "0") end
49
- bytes << byte
50
- bytes << " " unless i == bytesperline - 1
51
-
52
- end
53
-
54
- ascii = self[counter, linelen].ascii_print
43
+ if upcase
44
+ offset.upcase!
45
+ bytes.upcase!
46
+ end
55
47
 
56
- if upcase
57
- offset.upcase!
58
- bytes.upcase!
59
- end
60
-
61
- if RUBY_PLATFORM =~ /win32/
62
- dump << "#{offset if offsets} #{bytes.to_s.ljust(bytesperline * 3 - 1)} #{ascii}\n"
63
- else
64
- dump << "#{Console.colorize(offset, Console::Colors::YELLOW) if offsets} #{Console.colorize(bytes.to_s.ljust(bytesperline * 3 - 1), Console::Colors::BRIGHT_GREY)} #{ascii}\n"
65
- end
66
-
67
- counter += bytesperline
68
- end
69
-
70
- dump
71
- end
72
-
73
- def ascii_print
48
+ dump << "#{offset.yellow if offsets} #{bytes.to_s.ljust(bytesperline * 3 - 1).bold} #{ascii}\n"
74
49
 
75
- printable = ""
76
- self.each_byte { |c|
77
- if c >= ' '[0].ord && c <= '~'[0].ord then printable << c else printable << '.' end
78
- }
50
+ counter += bytesperline
51
+ end
79
52
 
80
- return printable
81
- end
53
+ dump
54
+ end
82
55
 
56
+ def ascii_print
57
+ self.gsub(/[^[[:print:]]]/, ".")
58
+ end
83
59
  end
@@ -0,0 +1,34 @@
1
+ # Origami samples
2
+
3
+ ## ``attachments``
4
+
5
+ Adding a file attachment to a PDF document.
6
+
7
+ ## ``javascript``
8
+
9
+ Adding JavaScript to a document and emulating it.
10
+
11
+ ## ``encryption``
12
+
13
+ PDF encryption (supports RC4 40-128 bits, and AES128).
14
+ Create a new encrypted document.
15
+
16
+ ## ``signature``
17
+
18
+ PDF digital signatures. Create a new document and signs it.
19
+
20
+ ## ``flash``
21
+
22
+ Create a document with an embedded SWF file.
23
+
24
+ ## ``loop``
25
+
26
+ Create a looping document using ``GoTo`` and ``Named`` actions.
27
+
28
+ ## ``events``
29
+
30
+ Create a document running JavaScript on various events.
31
+
32
+ ## ``uri``
33
+
34
+ Various methods for connecting to a remote URL.
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'origami'
5
+ rescue LoadError
6
+ $: << File.join(__dir__, "../../lib")
7
+ require 'origami'
8
+ end
9
+ include Origami
10
+
11
+ OUTPUT_FILE = "#{File.basename(__FILE__, ".rb")}.pdf"
12
+
13
+ # Creating a new file
14
+ pdf = PDF.new
15
+
16
+ # Embedding the file into the PDF.
17
+ pdf.attach_file(DATA,
18
+ name: "README.txt",
19
+ filter: :ASCIIHexDecode
20
+ )
21
+
22
+ contents = ContentStream.new
23
+ contents.write "File attachment sample",
24
+ x: 150, y: 750, rendering: Text::Rendering::FILL, size: 30
25
+
26
+ pdf.append_page Page.new.setContents(contents)
27
+
28
+ pdf.onDocumentOpen Action::JavaScript <<JS
29
+ this.exportDataObject({cName:"README.txt", nLaunch:2});
30
+ JS
31
+
32
+
33
+ pdf.save(OUTPUT_FILE)
34
+
35
+ puts "PDF file saved as #{OUTPUT_FILE}."
36
+
37
+ __END__
38
+ This is the attached file contents.
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'origami'
5
+ rescue LoadError
6
+ $: << File.join(__dir__, '../../lib')
7
+ require 'origami'
8
+ end
9
+ include Origami
10
+
11
+ require 'stringio'
12
+
13
+ OUTPUT_FILE = "#{File.basename(__FILE__, ".rb")}.pdf"
14
+ EMBEDDED_NAME = "#{('a'..'z').to_a.sample(8).join}.pdf"
15
+
16
+ #
17
+ # Creates the nested document.
18
+ # A simple document displaying a message box.
19
+ #
20
+ output_str = StringIO.new
21
+ nested_doc = PDF.write(output_str) do |pdf|
22
+ pdf.onDocumentOpen Action::JavaScript "app.alert('Hello world!');"
23
+ end
24
+
25
+ output_str.rewind
26
+
27
+ # The envelope document.
28
+ pdf = PDF.new.append_page
29
+
30
+ # Create an object stream to compress objects.
31
+ objstm = ObjectStream.new
32
+ objstm.Filter = :FlateDecode
33
+
34
+ pdf.insert(objstm)
35
+
36
+ objstm.insert pdf.attach_file(output_str, register: true, name: EMBEDDED_NAME)
37
+
38
+ # Compress the page tree.
39
+ objstm.insert(pdf.Catalog.Pages)
40
+ objstm.insert(pdf.pages.first)
41
+
42
+ # Compress the name tree.
43
+ objstm.insert(pdf.Catalog.Names)
44
+ objstm.insert(pdf.Catalog.Names.EmbeddedFiles)
45
+
46
+ # Compress the catalog.
47
+ objstm.insert(pdf.Catalog)
48
+
49
+ pdf.pages.first.onOpen Action::GoToE[EMBEDDED_NAME]
50
+
51
+ pdf.save(OUTPUT_FILE, noindent: true)
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'origami'
5
+ rescue LoadError
6
+ $: << File.join(__dir__, "../../lib")
7
+ require 'origami'
8
+ end
9
+ include Origami
10
+
11
+ #
12
+ # Encrypts a document with an empty password.
13
+ #
14
+
15
+ OUTPUT_FILE = "#{File.basename(__FILE__, ".rb")}.pdf"
16
+
17
+ # Creates an encrypted document with AES256 and a null password.
18
+ pdf = PDF.new.encrypt(cipher: 'aes', key_size: 256)
19
+
20
+ contents = ContentStream.new
21
+ contents.write "Encrypted document sample",
22
+ x: 100, y: 750, rendering: Text::Rendering::STROKE, size: 30
23
+
24
+ pdf.append_page Page.new.setContents(contents)
25
+
26
+ pdf.save(OUTPUT_FILE)
27
+
28
+ puts "PDF file saved as #{OUTPUT_FILE}."
@@ -1,25 +1,22 @@
1
- #!/usr/bin/ruby
1
+ #!/usr/bin/ruby
2
2
 
3
3
  begin
4
- require 'origami'
4
+ require 'origami'
5
5
  rescue LoadError
6
- ORIGAMIDIR = "#{File.dirname(__FILE__)}/../../../lib"
7
- $: << ORIGAMIDIR
8
- require 'origami'
6
+ $: << File.join(__dir__, "../../lib")
7
+ require 'origami'
9
8
  end
10
9
  include Origami
11
10
 
12
- OUTPUTFILE = "#{File.basename(__FILE__, ".rb")}.pdf"
13
-
14
- puts "Now generating a new PDF file from scratch!"
11
+ OUTPUT_FILE = "#{File.basename(__FILE__, ".rb")}.pdf"
15
12
 
16
13
  pdf = PDF.new
17
14
 
18
15
  page = Page.new
19
16
 
20
17
  contents = ContentStream.new
21
- contents.write "Pass your mouse over the yellow square",
22
- :x => 250, :y => 750, :size => 15
18
+ contents.write "Pass your mouse over the square",
19
+ x: 180, y: 750, size: 15
23
20
 
24
21
  page.setContents( contents )
25
22
 
@@ -41,9 +38,9 @@ pdf.onDocumentOpen(ondocumentopen)
41
38
  pdf.onDocumentClose(ondocumentclose)
42
39
  page.onOpen(onpageopen).onClose(onpageclose)
43
40
 
44
- pdf.register(Names::Root::JAVASCRIPT, "test", namedscript)
41
+ pdf.register(Names::JAVASCRIPT, "test", namedscript)
45
42
 
46
- rect_coord = Rectangle[:llx => 350, :lly => 700, :urx => 415, :ury => 640]
43
+ rect_coord = Rectangle[llx: 270, lly: 700, urx: 330, ury: 640]
47
44
 
48
45
  # Just draw a yellow rectangle.
49
46
  rect = Annotation::Square.new
@@ -64,12 +61,12 @@ annot.onPageClose(onparentclose)
64
61
  annot.onPageVisible(onparentvisible)
65
62
  annot.onPageInvisible(onparentinvisible)
66
63
 
67
- page.add_annot(annot)
68
- page.add_annot(rect)
64
+ page.add_annotation(annot)
65
+ page.add_annotation(rect)
69
66
 
70
67
  pdf.append_page(page)
71
68
 
72
69
  # Save the resulting file.
73
- pdf.save(OUTPUTFILE)
70
+ pdf.save(OUTPUT_FILE)
74
71
 
75
- puts "PDF file saved as #{OUTPUTFILE}."
72
+ puts "PDF file saved as #{OUTPUT_FILE}."
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'origami'
5
+ rescue LoadError
6
+ $: << File.join(__dir__, "../../lib")
7
+ require 'origami'
8
+ end
9
+ include Origami
10
+
11
+ #
12
+ # Embeding a Flash asset inside a PDF document.
13
+ #
14
+
15
+ SWF_PATH = File.join(__dir__, "helloworld.swf")
16
+ OUTPUT_FILE = "#{File.basename(__FILE__, ".rb")}.pdf"
17
+
18
+ # Creating a new file
19
+ pdf = PDF.new
20
+
21
+ # Embedding the SWF file into the PDF.
22
+ swf = pdf.attach_file(SWF_PATH)
23
+
24
+ # Creating a Flash annotation on the page.
25
+ pdf.append_page do |page|
26
+ annot = page.add_flash_application(swf,
27
+ windowed: true,
28
+ navigation_pane: true,
29
+ toolbar: true)
30
+
31
+ # Setting the player position on the page.
32
+ annot.Rect = Rectangle.new [204, 573, 403, 718]
33
+ end
34
+
35
+ pdf.save(OUTPUT_FILE)
36
+
37
+ puts "PDF file saved as #{OUTPUT_FILE}."
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/ruby
2
+
3
+ begin
4
+ require 'origami'
5
+ rescue LoadError
6
+ $: << File.join(__dir__, "../../lib")
7
+ require 'origami'
8
+ end
9
+ include Origami
10
+
11
+ #
12
+ # Interactive JavaScript interpreter using an Acrobat Form.
13
+ #
14
+
15
+ require 'origami/template/widgets'
16
+
17
+ OUTPUT_FILE = "#{File.basename(__FILE__, ".rb")}.pdf"
18
+
19
+ pdf = PDF.new.append_page(page = Page.new)
20
+
21
+ contents = ContentStream.new.setFilter(:FlateDecode)
22
+
23
+ contents.write "Write your JavaScript below and run it",
24
+ x: 100, y: 750, size: 24, rendering: Text::Rendering::FILL,
25
+ fill_color: Graphics::Color::RGB.new(0xFF, 0x80, 0x80)
26
+
27
+ contents.write "You need at least Acrobat Reader 8 to use this document.",
28
+ x: 50, y: 80, size: 12, rendering: Text::Rendering::FILL
29
+
30
+ contents.write "\nGenerated with Origami #{Origami::VERSION}.",
31
+ color: Graphics::Color::RGB.new(0, 0, 255)
32
+
33
+ contents.draw_rectangle(45, 35, 320, 60,
34
+ line_width: 2.0, dash: Graphics::DashPattern.new([3]),
35
+ fill: false, stroke: true, stroke_color: Graphics::Color::GrayScale.new(0.7))
36
+
37
+ page.Contents = contents
38
+
39
+ ml = Template::MultiLineEdit.new('scriptedit', x: 50, y: 280, width: 500, height: 400)
40
+ ml.V = <<JS
41
+ console.show();
42
+ console.println('Script entry point');
43
+ app.alert("Hello");
44
+ JS
45
+
46
+ button = Template::Button.new("Run!", x: 490, y: 240, width: 60, height: 30)
47
+ button.onActivate Action::JavaScript["eval(this.getField('scriptedit').value);"]
48
+
49
+ page.add_annotation(ml, button)
50
+ pdf.create_form(button, ml)
51
+
52
+ pdf.save(OUTPUT_FILE, noindent: true)
53
+
54
+ puts "PDF file saved as #{OUTPUT_FILE}."
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/ruby
2
+
3
+ begin
4
+ require 'origami'
5
+ rescue LoadError
6
+ $: << File.join(__dir__, "../../lib")
7
+ require 'origami'
8
+ end
9
+ include Origami
10
+
11
+ require 'origami/template/widgets'
12
+
13
+ OUTPUT_FILE = "#{File.basename(__FILE__, ".rb")}.pdf"
14
+
15
+ #
16
+ # Interactive FormCalc interpreter using a XFA form.
17
+ #
18
+
19
+ #
20
+ # XDP Packet holding the Form.
21
+ #
22
+ class SampleXDP < XDP::Package
23
+ def initialize(script = "")
24
+ super()
25
+
26
+ self.root.add_element(create_config_packet)
27
+ self.root.add_element(create_template_packet(script))
28
+ self.root.add_element(create_datasets_packet)
29
+ end
30
+
31
+ def create_config_packet
32
+ config = XDP::Packet::Config.new
33
+
34
+ present = config.add_element(XFA::Element.new("present"))
35
+ pdf = present.add_element(XFA::Element.new("pdf"))
36
+ interactive = pdf.add_element(XFA::Element.new("interactive"))
37
+ interactive.text = 1
38
+
39
+ config
40
+ end
41
+
42
+ def create_template_packet(script)
43
+ template = XDP::Packet::Template.new
44
+
45
+ form1 = template.add_subform(layout: 'tb', name: 'form1')
46
+ form1.add_pageSet
47
+ form1.add_event(activity: 'initialize', name: 'event__ready')
48
+ .add_script(contentType: 'application/x-formcalc')
49
+ .text = script
50
+
51
+ subform = form1.add_subform
52
+
53
+ button = subform.add_field(name: 'Button1')
54
+ button.add_ui.add_button(highlight: 'inverted')
55
+ btncaption = button.add_caption
56
+ btncaption.add_value.add_text.text = "Send!"
57
+ btncaption.add_para(vAlign: 'middle', hAlign: 'center')
58
+ button.add_bind(match: 'none')
59
+ button.add_event(activity: 'click', name: 'event__click')
60
+ .add_script(contentType: 'application/x-formcalc')
61
+ .text = script
62
+
63
+ txtfield = subform.add_field(name: 'TextField1')
64
+ txtfield.add_ui.add_textEdit.add_border.add_edge(stroke: 'lowered')
65
+
66
+ template
67
+ end
68
+
69
+ def create_datasets_packet
70
+ datasets = XDP::Packet::Datasets.new
71
+ data = datasets.add_element(XDP::Packet::Datasets::Data.new)
72
+
73
+ data.add_element(XFA::Element.new('form1'))
74
+ .add_element(XFA::Element.new('TextField1'))
75
+ .text = '$host.messageBox("Hello from FormCalc!")'
76
+
77
+ datasets
78
+ end
79
+ end
80
+
81
+ pdf = PDF.new.append_page(page = Page.new)
82
+
83
+ contents = ContentStream.new.setFilter(:FlateDecode)
84
+
85
+ contents.write "Write your FormCalc below and run it",
86
+ x: 100, y: 750, size: 24, rendering: Text::Rendering::FILL,
87
+ fill_color: Graphics::Color::RGB.new(0xFF, 0x80, 0x80)
88
+
89
+ contents.write "You need at least Acrobat Reader 8 to use this document.",
90
+ x: 50, y: 80, size: 12, rendering: Text::Rendering::FILL
91
+
92
+ contents.write "\nGenerated with Origami #{Origami::VERSION}.",
93
+ color: Graphics::Color::RGB.new(0, 0, 255)
94
+
95
+ contents.draw_rectangle(45, 35, 320, 60,
96
+ line_width: 2.0, dash: Graphics::DashPattern.new([3]),
97
+ fill: false, stroke: true, stroke_color: Graphics::Color::GrayScale.new(0.7))
98
+
99
+ page.Contents = contents
100
+
101
+ ml = Template::MultiLineEdit.new('TextField1[0]', x: 50, y: 280, width: 500, height: 400)
102
+ button = Template::Button.new('Send!', id: 'Button1[0]', x: 490, y: 240, width: 60, height: 30)
103
+
104
+ page.add_annotation(ml, button)
105
+
106
+ form1 = Field::Subform.new(T: "form1[0]")
107
+ form1.add_fields(subform = Field::Subform.new(T: "#subform[0]"))
108
+ subform.add_fields(ml, button)
109
+
110
+ xdp = SampleXDP.new('Eval(Ref(form1[0].#subform[0].TextField1[0]))').to_s
111
+ pdf.create_xfa_form(xdp, form1)
112
+
113
+ pdf.save(OUTPUT_FILE)
114
+
115
+ puts "PDF file saved as #{OUTPUT_FILE}."