pdf_tempura 0.0.2

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 (80) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +342 -0
  8. data/Rakefile +1 -0
  9. data/example/my_pdf.rb +37 -0
  10. data/lib/pdf_tempura.rb +8 -0
  11. data/lib/pdf_tempura/document.rb +121 -0
  12. data/lib/pdf_tempura/document/boxed_characters.rb +70 -0
  13. data/lib/pdf_tempura/document/boxed_characters/groups.rb +53 -0
  14. data/lib/pdf_tempura/document/character_field.rb +37 -0
  15. data/lib/pdf_tempura/document/checkbox_field.rb +15 -0
  16. data/lib/pdf_tempura/document/default_commands.rb +40 -0
  17. data/lib/pdf_tempura/document/field/base.rb +55 -0
  18. data/lib/pdf_tempura/document/field_set.rb +51 -0
  19. data/lib/pdf_tempura/document/page.rb +33 -0
  20. data/lib/pdf_tempura/document/table.rb +95 -0
  21. data/lib/pdf_tempura/document/table/boxed_character_column.rb +20 -0
  22. data/lib/pdf_tempura/document/table/checkbox_column.rb +9 -0
  23. data/lib/pdf_tempura/document/table/column.rb +18 -0
  24. data/lib/pdf_tempura/document/table/spacer.rb +13 -0
  25. data/lib/pdf_tempura/document/table/text_column.rb +9 -0
  26. data/lib/pdf_tempura/document/text_field.rb +18 -0
  27. data/lib/pdf_tempura/document/validation.rb +79 -0
  28. data/lib/pdf_tempura/extensions/hash/stringify_keys.rb +35 -0
  29. data/lib/pdf_tempura/render.rb +18 -0
  30. data/lib/pdf_tempura/render/boxed_characters.rb +42 -0
  31. data/lib/pdf_tempura/render/character_field.rb +49 -0
  32. data/lib/pdf_tempura/render/checkbox_field.rb +35 -0
  33. data/lib/pdf_tempura/render/debug.rb +16 -0
  34. data/lib/pdf_tempura/render/debug/annotation/base.rb +83 -0
  35. data/lib/pdf_tempura/render/debug/character_field_annotation.rb +13 -0
  36. data/lib/pdf_tempura/render/debug/checkbox_field_annotation.rb +24 -0
  37. data/lib/pdf_tempura/render/debug/field_set_annotation.rb +23 -0
  38. data/lib/pdf_tempura/render/debug/grid.rb +59 -0
  39. data/lib/pdf_tempura/render/debug/outside_annotation.rb +42 -0
  40. data/lib/pdf_tempura/render/debug/table_annotation.rb +19 -0
  41. data/lib/pdf_tempura/render/debug/text_field_annotation.rb +42 -0
  42. data/lib/pdf_tempura/render/field.rb +40 -0
  43. data/lib/pdf_tempura/render/field_bounds.rb +26 -0
  44. data/lib/pdf_tempura/render/field_data_mapper.rb +15 -0
  45. data/lib/pdf_tempura/render/field_set.rb +31 -0
  46. data/lib/pdf_tempura/render/option_access.rb +21 -0
  47. data/lib/pdf_tempura/render/page.rb +23 -0
  48. data/lib/pdf_tempura/render/table.rb +35 -0
  49. data/lib/pdf_tempura/render/text_field.rb +13 -0
  50. data/lib/pdf_tempura/renderer.rb +39 -0
  51. data/lib/pdf_tempura/version.rb +3 -0
  52. data/pdf_tempura.gemspec +27 -0
  53. data/spec/assets/sample_pdf_form.odg +0 -0
  54. data/spec/assets/sample_pdf_form.pdf +0 -0
  55. data/spec/integration_spec.rb +88 -0
  56. data/spec/lib/pdf_tempura/document/boxed_characters_spec.rb +125 -0
  57. data/spec/lib/pdf_tempura/document/checkbox_field_spec.rb +54 -0
  58. data/spec/lib/pdf_tempura/document/field_common.rb +12 -0
  59. data/spec/lib/pdf_tempura/document/field_set_spec.rb +38 -0
  60. data/spec/lib/pdf_tempura/document/page_spec.rb +57 -0
  61. data/spec/lib/pdf_tempura/document/table_spec.rb +161 -0
  62. data/spec/lib/pdf_tempura/document/text_field_spec.rb +195 -0
  63. data/spec/lib/pdf_tempura/document_spec.rb +131 -0
  64. data/spec/lib/pdf_tempura/extensions/hash/stringify_keys_spec.rb +42 -0
  65. data/spec/lib/pdf_tempura/render/boxed_characters_spec.rb +68 -0
  66. data/spec/lib/pdf_tempura/render/checkbox_field_spec.rb +39 -0
  67. data/spec/lib/pdf_tempura/render/debug/annotation_renderer/base_spec.rb +45 -0
  68. data/spec/lib/pdf_tempura/render/debug/checkbox_field_annotation_spec.rb +45 -0
  69. data/spec/lib/pdf_tempura/render/debug/grid_spec.rb +15 -0
  70. data/spec/lib/pdf_tempura/render/debug/text_field_annotation_spec.rb +46 -0
  71. data/spec/lib/pdf_tempura/render/field_data_mapper_spec.rb +31 -0
  72. data/spec/lib/pdf_tempura/render/field_set_spec.rb +41 -0
  73. data/spec/lib/pdf_tempura/render/field_spec.rb +37 -0
  74. data/spec/lib/pdf_tempura/render/page_spec.rb +77 -0
  75. data/spec/lib/pdf_tempura/render/table_spec.rb +44 -0
  76. data/spec/lib/pdf_tempura/render/text_field_spec.rb +39 -0
  77. data/spec/lib/pdf_tempura/renderer_spec.rb +79 -0
  78. data/spec/spec_helper.rb +29 -0
  79. data/spec/support/shared_examples/field_examples.rb +265 -0
  80. metadata +219 -0
@@ -0,0 +1,35 @@
1
+ module PdfTempura
2
+ module Render
3
+ class CheckboxField < Field
4
+
5
+ private
6
+
7
+ def set_styling(pdf)
8
+ pdf.fill_color = "000000"
9
+ pdf.font "Courier", style: :normal
10
+ end
11
+
12
+ def render_field(pdf)
13
+ field_bounds_box(pdf) do
14
+ padding_bounds_box(pdf) do
15
+ pdf.text_box("X", field_options) if @value
16
+ end
17
+ end
18
+ end
19
+
20
+ def field_options
21
+ {
22
+ valign: :center,
23
+ align: :center,
24
+ single_line: true,
25
+ size: @field.height
26
+ }
27
+ end
28
+
29
+ def render_debug_annotation(pdf)
30
+ Debug::CheckboxFieldAnnotation.new(@field).render(pdf)
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ module PdfTempura
2
+ module Render
3
+ module Debug
4
+
5
+ end
6
+ end
7
+ end
8
+
9
+ require_relative 'debug/annotation/base'
10
+ require_relative 'debug/character_field_annotation'
11
+ require_relative 'debug/checkbox_field_annotation'
12
+ require_relative 'debug/outside_annotation'
13
+ require_relative 'debug/text_field_annotation'
14
+ require_relative 'debug/grid'
15
+ require_relative 'debug/field_set_annotation'
16
+ require_relative 'debug/table_annotation'
@@ -0,0 +1,83 @@
1
+ module PdfTempura
2
+ module Render
3
+ module Debug::Annotation
4
+ class Base
5
+ include Render::FieldBounds
6
+
7
+ def initialize(field)
8
+ @field = field
9
+ end
10
+
11
+ def render(pdf)
12
+ set_field_styling(pdf)
13
+ render_boxes(pdf)
14
+ render_text(pdf)
15
+ end
16
+
17
+ private
18
+
19
+ def set_field_styling(pdf)
20
+ pdf.font_size = 7
21
+ pdf.fill_color = "000066"
22
+ pdf.line_width = 0.5
23
+ end
24
+
25
+ def render_text(pdf)
26
+ field_bounds_box(pdf) do
27
+ render_xy(pdf)
28
+ render_label(pdf)
29
+ end
30
+ end
31
+
32
+ def render_xy(pdf)
33
+ pdf.text_box "x: #{@field.x} y: #{@field.y} w: #{@field.width} h: #{@field.height}", field_options
34
+ end
35
+
36
+ def render_label(pdf)
37
+ pdf.text_box "#{@field.name}", label_options
38
+ end
39
+
40
+ def render_boxes(pdf)
41
+ pdf.transparent 0.5 do
42
+ field_bounds_box(pdf) do
43
+ draw_box_border(pdf, box_color)
44
+ fill_box_color(pdf, box_color)
45
+ draw_padding(pdf)
46
+ end
47
+ end
48
+ end
49
+
50
+ def box_color
51
+ "CCCC33"
52
+ end
53
+
54
+ def draw_box_border(pdf, color)
55
+ pdf.stroke_color = color
56
+ pdf.stroke_bounds
57
+ end
58
+
59
+ def fill_box_color(pdf, color)
60
+ pdf.fill_color = color
61
+ pdf.fill{ pdf.rectangle [0,pdf.bounds.height], pdf.bounds.width, pdf.bounds.height }
62
+ end
63
+
64
+ def draw_padding(pdf)
65
+ pdf.transparent 0.25 do
66
+ padding_bounds_box(pdf) do
67
+ draw_box_border(pdf, "0000CC")
68
+ end
69
+ end
70
+ end
71
+
72
+ def field_options
73
+ raise NotImplementedError, "Implement field_options in your subclass."
74
+ end
75
+
76
+ def label_options
77
+ raise NotImplementedError, "Implement label_options in your subclass."
78
+ end
79
+
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,13 @@
1
+ module PdfTempura
2
+ module Render
3
+ module Debug
4
+ class CharacterFieldAnnotation < Annotation::Base
5
+
6
+ def render(pdf)
7
+ render_boxes(pdf)
8
+ end
9
+
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'outside_annotation'
2
+
3
+ module PdfTempura
4
+ module Render
5
+ module Debug
6
+ class CheckboxFieldAnnotation < OutsideAnnotation
7
+
8
+ private
9
+
10
+ def coordinate_offsets
11
+ {
12
+ xy: [1,16],
13
+ label: [1,-9]
14
+ }
15
+ end
16
+
17
+ def label_options
18
+ super.merge(align: :left)
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ module PdfTempura
2
+ module Render
3
+ module Debug
4
+ class FieldSetAnnotation < OutsideAnnotation
5
+
6
+ private
7
+
8
+ def box_color
9
+ "66CCFF"
10
+ end
11
+
12
+ def render_xy(pdf)
13
+ #don't render an xy label for this annotation
14
+ end
15
+
16
+ def render_label(pdf)
17
+ pdf.text_box "fieldset: #{@field.name}", label_options
18
+ end
19
+
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,59 @@
1
+ module PdfTempura
2
+ module Render
3
+ module Debug
4
+ class Grid
5
+
6
+ def render(pdf)
7
+ set_styling(pdf)
8
+ render_grid(pdf)
9
+ end
10
+
11
+ private
12
+
13
+ def set_styling(pdf)
14
+ pdf.stroke_color = "000000"
15
+ pdf.fill_color = "000000"
16
+ pdf.line_width = 0.5
17
+ end
18
+
19
+ def render_grid(pdf)
20
+ pdf.transparent(0.125) do
21
+ render_vertical_lines(pdf)
22
+ render_horizontal_lines(pdf)
23
+ end
24
+ end
25
+
26
+ def render_vertical_lines(pdf)
27
+ line_loop(pdf.bounds.width, 25) do |x|
28
+ vertical_line_with_label pdf, x
29
+ end
30
+ end
31
+
32
+ def render_horizontal_lines(pdf)
33
+ line_loop(pdf.bounds.height, 25) do |y|
34
+ horizontal_line_with_label pdf, y
35
+ end
36
+ end
37
+
38
+ def line_loop(max, increment)
39
+ (0 .. max).step(increment){ |n| yield(n) }
40
+ end
41
+
42
+ def vertical_line_with_label(pdf, x)
43
+ pdf.stroke do
44
+ pdf.line([x, 0], [x, pdf.bounds.height])
45
+ pdf.draw_text x.to_s, at: [x+3, 3], size: 6
46
+ end
47
+ end
48
+
49
+ def horizontal_line_with_label(pdf, y)
50
+ pdf.stroke do
51
+ pdf.line([0, y], [pdf.bounds.width, y])
52
+ pdf.draw_text y.to_s, at: [3, y+3], size: 6
53
+ end
54
+ end
55
+
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,42 @@
1
+ module PdfTempura
2
+ module Render
3
+ module Debug
4
+ class OutsideAnnotation < Annotation::Base
5
+
6
+ private
7
+
8
+ def coordinate_offsets
9
+ {
10
+ xy: [1,8],
11
+ label: [1,-9]
12
+ }
13
+ end
14
+
15
+ def field_options
16
+ off = coordinate_offsets[:xy]
17
+
18
+ {
19
+ at: [off[0], @field.height + off[1]],
20
+ width: @field.width * 4,
21
+ height: @field.height - 2,
22
+ valign: :top
23
+ }
24
+ end
25
+
26
+ def label_options
27
+ off = coordinate_offsets[:label]
28
+
29
+ {
30
+ at: [off[0], @field.height + off[1]],
31
+ width: @field.width - 2,
32
+ height: @field.height - 2,
33
+ valign: :bottom,
34
+ align: :right,
35
+ single_line: true
36
+ }
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,19 @@
1
+ module PdfTempura
2
+ module Render
3
+ module Debug
4
+ class TableAnnotation < OutsideAnnotation
5
+
6
+ private
7
+
8
+ def box_color
9
+ "66CCFF"
10
+ end
11
+
12
+ def transparency
13
+ 0.20
14
+ end
15
+
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,42 @@
1
+ module PdfTempura
2
+ module Render
3
+ module Debug
4
+ class TextFieldAnnotation < Annotation::Base
5
+
6
+ private
7
+
8
+ def coordinate_offsets
9
+ {
10
+ xy: [1,-1],
11
+ label: [1,-1]
12
+ }
13
+ end
14
+
15
+ def field_options
16
+ off = coordinate_offsets[:xy]
17
+
18
+ {
19
+ at: [off[0], @field.height + off[1]],
20
+ width: @field.width - 2,
21
+ height: @field.height - 2,
22
+ valign: :top,
23
+ single_line: true
24
+ }
25
+ end
26
+
27
+ def label_options
28
+ off = coordinate_offsets[:label]
29
+ {
30
+ at: [off[0], @field.height + off[1]],
31
+ width: @field.width - 2,
32
+ height: @field.height - 2,
33
+ valign: :bottom,
34
+ align: :right,
35
+ single_line: true
36
+ }
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,40 @@
1
+ module PdfTempura
2
+ module Render
3
+ class Field
4
+ include OptionAccess
5
+ include FieldBounds
6
+
7
+ def self.generate(field, value, options)
8
+ case field
9
+ when Document::CheckboxField
10
+ CheckboxField.new(field, value, options)
11
+ when Document::TextField
12
+ TextField.new(field, value, options)
13
+ when Document::CharacterField
14
+ CharacterField.new(field, value, options)
15
+ when Document::BoxedCharacters
16
+ BoxedCharacters.new(field, value, options)
17
+ when Document::Table
18
+ Table.new(field, value, options)
19
+ when Document::FieldSet
20
+ FieldSet.new(field, value, options)
21
+ else
22
+ raise ArgumentError, "don't know how to handle field kind: #{field.class}"
23
+ end
24
+ end
25
+
26
+ def initialize(field, value, options = {})
27
+ @field = field
28
+ @value = value
29
+ @options = options
30
+ end
31
+
32
+ def render(pdf)
33
+ set_styling(pdf)
34
+ render_field(pdf)
35
+ render_debug_annotation(pdf) if draw_outlines?
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,26 @@
1
+ module PdfTempura
2
+ module Render
3
+ module FieldBounds
4
+
5
+ private
6
+
7
+ def field_bounds_box(pdf)
8
+ pdf.bounding_box([@field.x, @field.y], width: @field.width, height: @field.height) do
9
+ yield
10
+ end
11
+ end
12
+
13
+ def padding_bounds_box(pdf)
14
+ x = @field.padding[3]
15
+ y = pdf.bounds.height - @field.padding[0]
16
+ width = pdf.bounds.width - @field.padding[1] - @field.padding[3]
17
+ height = pdf.bounds.height - @field.padding[0] - @field.padding[2]
18
+
19
+ pdf.bounding_box([x,y], width: width, height: height) do
20
+ yield
21
+ end
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ module PdfTempura
2
+ module Render
3
+ class FieldDataMapper
4
+
5
+ def self.map(fields, data)
6
+ data ||= {}
7
+
8
+ fields.each_with_object({}){ |field, memo|
9
+ memo[field] = data[field.name]
10
+ }
11
+ end
12
+
13
+ end
14
+ end
15
+ end