thinreports 0.12.1 → 0.13.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 (177) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +3 -3
  3. data/.github/workflows/test.yml +28 -36
  4. data/.gitignore +1 -1
  5. data/CHANGELOG.md +19 -1
  6. data/Gemfile +11 -0
  7. data/README.md +12 -17
  8. data/Rakefile +17 -11
  9. data/lib/thinreports/basic_report/core/errors.rb +62 -0
  10. data/lib/thinreports/basic_report/core/format/base.rb +91 -0
  11. data/lib/thinreports/basic_report/core/shape/base/interface.rb +42 -0
  12. data/lib/thinreports/basic_report/core/shape/base/internal.rb +53 -0
  13. data/lib/thinreports/basic_report/core/shape/basic/block_format.rb +15 -0
  14. data/lib/thinreports/basic_report/core/shape/basic/block_interface.rb +34 -0
  15. data/lib/thinreports/basic_report/core/shape/basic/block_internal.rb +36 -0
  16. data/lib/thinreports/basic_report/core/shape/basic/format.rb +24 -0
  17. data/lib/thinreports/basic_report/core/shape/basic/interface.rb +87 -0
  18. data/lib/thinreports/basic_report/core/shape/basic/internal.rb +28 -0
  19. data/lib/thinreports/{core → basic_report/core}/shape/basic.rb +6 -4
  20. data/lib/thinreports/basic_report/core/shape/image_block/format.rb +14 -0
  21. data/lib/thinreports/basic_report/core/shape/image_block/interface.rb +25 -0
  22. data/lib/thinreports/basic_report/core/shape/image_block/internal.rb +19 -0
  23. data/lib/thinreports/{core → basic_report/core}/shape/image_block.rb +6 -4
  24. data/lib/thinreports/basic_report/core/shape/list/format.rb +92 -0
  25. data/lib/thinreports/basic_report/core/shape/list/manager.rb +231 -0
  26. data/lib/thinreports/basic_report/core/shape/list/page.rb +112 -0
  27. data/lib/thinreports/basic_report/core/shape/list/page_state.rb +50 -0
  28. data/lib/thinreports/basic_report/core/shape/list/section_format.rb +37 -0
  29. data/lib/thinreports/basic_report/core/shape/list/section_interface.rb +51 -0
  30. data/lib/thinreports/basic_report/core/shape/list/section_internal.rb +33 -0
  31. data/lib/thinreports/{core → basic_report/core}/shape/list.rb +6 -4
  32. data/lib/thinreports/basic_report/core/shape/manager/format.rb +33 -0
  33. data/lib/thinreports/basic_report/core/shape/manager/internal.rb +109 -0
  34. data/lib/thinreports/basic_report/core/shape/manager/target.rb +114 -0
  35. data/lib/thinreports/basic_report/core/shape/page_number/format.rb +32 -0
  36. data/lib/thinreports/basic_report/core/shape/page_number/interface.rb +31 -0
  37. data/lib/thinreports/basic_report/core/shape/page_number/internal.rb +57 -0
  38. data/lib/thinreports/{core → basic_report/core}/shape/page_number.rb +6 -4
  39. data/lib/thinreports/basic_report/core/shape/stack_view/format.rb +29 -0
  40. data/lib/thinreports/basic_report/core/shape/stack_view/interface.rb +19 -0
  41. data/lib/thinreports/basic_report/core/shape/stack_view/internal.rb +24 -0
  42. data/lib/thinreports/basic_report/core/shape/stack_view/row_format.rb +41 -0
  43. data/lib/thinreports/{core → basic_report/core}/shape/stack_view.rb +6 -4
  44. data/lib/thinreports/basic_report/core/shape/style/base.rb +149 -0
  45. data/lib/thinreports/basic_report/core/shape/style/basic.rb +24 -0
  46. data/lib/thinreports/basic_report/core/shape/style/graphic.rb +43 -0
  47. data/lib/thinreports/basic_report/core/shape/style/text.rb +122 -0
  48. data/lib/thinreports/basic_report/core/shape/text/format.rb +17 -0
  49. data/lib/thinreports/basic_report/core/shape/text/interface.rb +20 -0
  50. data/lib/thinreports/basic_report/core/shape/text/internal.rb +24 -0
  51. data/lib/thinreports/{core → basic_report/core}/shape/text.rb +6 -4
  52. data/lib/thinreports/basic_report/core/shape/text_block/format.rb +43 -0
  53. data/lib/thinreports/basic_report/core/shape/text_block/formatter/basic.rb +41 -0
  54. data/lib/thinreports/basic_report/core/shape/text_block/formatter/datetime.rb +25 -0
  55. data/lib/thinreports/basic_report/core/shape/text_block/formatter/number.rb +69 -0
  56. data/lib/thinreports/basic_report/core/shape/text_block/formatter/padding.rb +27 -0
  57. data/lib/thinreports/basic_report/core/shape/text_block/formatter.rb +38 -0
  58. data/lib/thinreports/basic_report/core/shape/text_block/interface.rb +37 -0
  59. data/lib/thinreports/basic_report/core/shape/text_block/internal.rb +75 -0
  60. data/lib/thinreports/{core → basic_report/core}/shape/text_block.rb +6 -4
  61. data/lib/thinreports/basic_report/core/shape.rb +44 -0
  62. data/lib/thinreports/basic_report/core/utils.rb +47 -0
  63. data/lib/thinreports/basic_report/generator/pdf/document/draw_shape.rb +108 -0
  64. data/lib/thinreports/basic_report/generator/pdf/document/draw_template_items.rb +71 -0
  65. data/lib/thinreports/basic_report/generator/pdf/document/font.rb +90 -0
  66. data/lib/thinreports/basic_report/generator/pdf/document/graphics/attributes.rb +149 -0
  67. data/lib/thinreports/basic_report/generator/pdf/document/graphics/basic.rb +137 -0
  68. data/lib/thinreports/basic_report/generator/pdf/document/graphics/image.rb +99 -0
  69. data/lib/thinreports/basic_report/generator/pdf/document/graphics/text.rb +180 -0
  70. data/lib/thinreports/basic_report/generator/pdf/document/graphics.rb +42 -0
  71. data/lib/thinreports/basic_report/generator/pdf/document/page.rb +96 -0
  72. data/lib/thinreports/basic_report/generator/pdf/document/parse_color.rb +51 -0
  73. data/lib/thinreports/basic_report/generator/pdf/document.rb +132 -0
  74. data/lib/thinreports/basic_report/generator/pdf/drawer/base.rb +50 -0
  75. data/lib/thinreports/basic_report/generator/pdf/drawer/list.rb +65 -0
  76. data/lib/thinreports/basic_report/generator/pdf/drawer/list_section.rb +51 -0
  77. data/lib/thinreports/basic_report/generator/pdf/drawer/page.rb +127 -0
  78. data/lib/thinreports/basic_report/generator/pdf/prawn_ext/calc_image_dimensions.rb +34 -0
  79. data/lib/thinreports/basic_report/generator/pdf/prawn_ext/width_of.rb +31 -0
  80. data/lib/thinreports/basic_report/generator/pdf.rb +66 -0
  81. data/lib/thinreports/basic_report/layout/base.rb +48 -0
  82. data/lib/thinreports/basic_report/layout/format.rb +67 -0
  83. data/lib/thinreports/basic_report/layout/legacy_schema.rb +383 -0
  84. data/lib/thinreports/basic_report/layout/version.rb +41 -0
  85. data/lib/thinreports/{layout.rb → basic_report/layout.rb} +6 -4
  86. data/lib/thinreports/basic_report/report/base.rb +173 -0
  87. data/lib/thinreports/basic_report/report/internal.rb +107 -0
  88. data/lib/thinreports/basic_report/report/page.rb +97 -0
  89. data/lib/thinreports/basic_report/report.rb +26 -0
  90. data/lib/thinreports/basic_report.rb +15 -0
  91. data/lib/thinreports/config.rb +1 -1
  92. data/lib/thinreports/section_report.rb +12 -0
  93. data/lib/thinreports/version.rb +1 -1
  94. data/lib/thinreports.rb +2 -13
  95. data/thinreports.gemspec +3 -7
  96. metadata +97 -154
  97. data/gemfiles/prawn-2.2.gemfile +0 -5
  98. data/gemfiles/prawn-2.3.gemfile +0 -5
  99. data/gemfiles/prawn-2.4.gemfile +0 -5
  100. data/lib/thinreports/core/errors.rb +0 -60
  101. data/lib/thinreports/core/format/base.rb +0 -89
  102. data/lib/thinreports/core/shape/base/interface.rb +0 -40
  103. data/lib/thinreports/core/shape/base/internal.rb +0 -51
  104. data/lib/thinreports/core/shape/basic/block_format.rb +0 -13
  105. data/lib/thinreports/core/shape/basic/block_interface.rb +0 -32
  106. data/lib/thinreports/core/shape/basic/block_internal.rb +0 -34
  107. data/lib/thinreports/core/shape/basic/format.rb +0 -22
  108. data/lib/thinreports/core/shape/basic/interface.rb +0 -85
  109. data/lib/thinreports/core/shape/basic/internal.rb +0 -26
  110. data/lib/thinreports/core/shape/image_block/format.rb +0 -12
  111. data/lib/thinreports/core/shape/image_block/interface.rb +0 -23
  112. data/lib/thinreports/core/shape/image_block/internal.rb +0 -17
  113. data/lib/thinreports/core/shape/list/format.rb +0 -90
  114. data/lib/thinreports/core/shape/list/manager.rb +0 -229
  115. data/lib/thinreports/core/shape/list/page.rb +0 -110
  116. data/lib/thinreports/core/shape/list/page_state.rb +0 -48
  117. data/lib/thinreports/core/shape/list/section_format.rb +0 -35
  118. data/lib/thinreports/core/shape/list/section_interface.rb +0 -49
  119. data/lib/thinreports/core/shape/list/section_internal.rb +0 -31
  120. data/lib/thinreports/core/shape/manager/format.rb +0 -31
  121. data/lib/thinreports/core/shape/manager/internal.rb +0 -107
  122. data/lib/thinreports/core/shape/manager/target.rb +0 -112
  123. data/lib/thinreports/core/shape/page_number/format.rb +0 -30
  124. data/lib/thinreports/core/shape/page_number/interface.rb +0 -29
  125. data/lib/thinreports/core/shape/page_number/internal.rb +0 -55
  126. data/lib/thinreports/core/shape/stack_view/format.rb +0 -27
  127. data/lib/thinreports/core/shape/stack_view/interface.rb +0 -17
  128. data/lib/thinreports/core/shape/stack_view/internal.rb +0 -22
  129. data/lib/thinreports/core/shape/stack_view/row_format.rb +0 -39
  130. data/lib/thinreports/core/shape/style/base.rb +0 -146
  131. data/lib/thinreports/core/shape/style/basic.rb +0 -22
  132. data/lib/thinreports/core/shape/style/graphic.rb +0 -41
  133. data/lib/thinreports/core/shape/style/text.rb +0 -120
  134. data/lib/thinreports/core/shape/text/format.rb +0 -15
  135. data/lib/thinreports/core/shape/text/interface.rb +0 -18
  136. data/lib/thinreports/core/shape/text/internal.rb +0 -22
  137. data/lib/thinreports/core/shape/text_block/format.rb +0 -41
  138. data/lib/thinreports/core/shape/text_block/formatter/basic.rb +0 -39
  139. data/lib/thinreports/core/shape/text_block/formatter/datetime.rb +0 -23
  140. data/lib/thinreports/core/shape/text_block/formatter/number.rb +0 -67
  141. data/lib/thinreports/core/shape/text_block/formatter/padding.rb +0 -25
  142. data/lib/thinreports/core/shape/text_block/formatter.rb +0 -34
  143. data/lib/thinreports/core/shape/text_block/interface.rb +0 -35
  144. data/lib/thinreports/core/shape/text_block/internal.rb +0 -73
  145. data/lib/thinreports/core/shape.rb +0 -42
  146. data/lib/thinreports/core/utils.rb +0 -45
  147. data/lib/thinreports/generate.rb +0 -11
  148. data/lib/thinreports/generator/pdf/document/draw_shape.rb +0 -106
  149. data/lib/thinreports/generator/pdf/document/draw_template_items.rb +0 -69
  150. data/lib/thinreports/generator/pdf/document/font.rb +0 -88
  151. data/lib/thinreports/generator/pdf/document/graphics/attributes.rb +0 -147
  152. data/lib/thinreports/generator/pdf/document/graphics/basic.rb +0 -135
  153. data/lib/thinreports/generator/pdf/document/graphics/image.rb +0 -98
  154. data/lib/thinreports/generator/pdf/document/graphics/text.rb +0 -178
  155. data/lib/thinreports/generator/pdf/document/graphics.rb +0 -40
  156. data/lib/thinreports/generator/pdf/document/page.rb +0 -94
  157. data/lib/thinreports/generator/pdf/document/parse_color.rb +0 -49
  158. data/lib/thinreports/generator/pdf/document.rb +0 -130
  159. data/lib/thinreports/generator/pdf/drawer/base.rb +0 -48
  160. data/lib/thinreports/generator/pdf/drawer/list.rb +0 -63
  161. data/lib/thinreports/generator/pdf/drawer/list_section.rb +0 -49
  162. data/lib/thinreports/generator/pdf/drawer/page.rb +0 -125
  163. data/lib/thinreports/generator/pdf/prawn_ext/calc_image_dimensions.rb +0 -32
  164. data/lib/thinreports/generator/pdf/prawn_ext/width_of.rb +0 -29
  165. data/lib/thinreports/generator/pdf.rb +0 -63
  166. data/lib/thinreports/layout/base.rb +0 -46
  167. data/lib/thinreports/layout/format.rb +0 -65
  168. data/lib/thinreports/layout/legacy_schema.rb +0 -381
  169. data/lib/thinreports/layout/version.rb +0 -39
  170. data/lib/thinreports/report/base.rb +0 -169
  171. data/lib/thinreports/report/internal.rb +0 -105
  172. data/lib/thinreports/report/page.rb +0 -95
  173. data/lib/thinreports/report.rb +0 -24
  174. /data/lib/thinreports/{core → basic_report/core}/shape/base.rb +0 -0
  175. /data/lib/thinreports/{core → basic_report/core}/shape/manager.rb +0 -0
  176. /data/lib/thinreports/{core → basic_report/core}/shape/style.rb +0 -0
  177. /data/lib/thinreports/{generator → basic_report/generator}/pdf/prawn_ext.rb +0 -0
@@ -1,88 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Thinreports
4
- module Generator
5
- class PDF
6
- module Font
7
- FONT_STORE = Thinreports.root.join('fonts')
8
-
9
- BUILTIN_FONTS = {
10
- 'IPAMincho' => FONT_STORE.join('ipam.ttf').to_s,
11
- 'IPAPMincho' => FONT_STORE.join('ipamp.ttf').to_s,
12
- 'IPAGothic' => FONT_STORE.join('ipag.ttf').to_s,
13
- 'IPAPGothic' => FONT_STORE.join('ipagp.ttf').to_s
14
- }.freeze
15
-
16
- DEFAULT_FALLBACK_FONTS = %w[IPAMincho].freeze
17
-
18
- PRAWN_BUINTIN_FONT_ALIASES = {
19
- 'Courier New' => 'Courier',
20
- 'Times New Roman' => 'Times-Roman'
21
- }.freeze
22
-
23
- def setup_fonts
24
- # Install built-in fonts.
25
- BUILTIN_FONTS.each do |font_name, font_path|
26
- install_font(font_name, font_path)
27
- end
28
-
29
- # Create aliases from the font list provided by Prawn.
30
- PRAWN_BUINTIN_FONT_ALIASES.each do |alias_name, name|
31
- pdf.font_families[alias_name] = pdf.font_families[name]
32
- end
33
-
34
- # Setup custom fallback fonts
35
- fallback_fonts = Thinreports.config.fallback_fonts.uniq
36
- fallback_fonts.map!.with_index do |font, i|
37
- if pdf.font_families.key?(font)
38
- font
39
- else
40
- install_font "Custom-fallback-font#{i}", font
41
- end
42
- end
43
-
44
- # Set fallback fonts
45
- pdf.fallback_fonts(fallback_fonts + DEFAULT_FALLBACK_FONTS)
46
- end
47
-
48
- # @param [String] name
49
- # @param [String] file
50
- # @return [String] installed font name
51
- def install_font(name, file)
52
- raise Errors::FontFileNotFound unless File.exist?(file)
53
-
54
- pdf.font_families[name] = {
55
- normal: file,
56
- bold: file,
57
- italic: file,
58
- bold_italic: file
59
- }
60
- name
61
- end
62
-
63
- # @return [String]
64
- def default_family
65
- 'Helvetica'
66
- end
67
-
68
- # @param [String] family
69
- # @return [String]
70
- def default_family_if_missing(family)
71
- pdf.font_families.key?(family) ? family : default_family
72
- end
73
-
74
- # @param [String] font_name
75
- # @param [:bold, :italic] font_style
76
- # @return [Boolean]
77
- def font_has_style?(font_name, font_style)
78
- font = pdf.font_families[font_name]
79
-
80
- return false unless font
81
- return false unless font.key?(font_style)
82
-
83
- font[font_style] != font[:normal]
84
- end
85
- end
86
- end
87
- end
88
- end
@@ -1,147 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Thinreports
4
- module Generator
5
- class PDF
6
- module Graphics
7
- # @param [Hash] style
8
- # @yield [attrs]
9
- # @yieldparam [Hash] attrs
10
- # @return [Hash]
11
- def build_graphic_attributes(style, &block)
12
- graphic_attributes = {
13
- stroke: style['border-color'],
14
- stroke_width: style['border-width'],
15
- stroke_type: style['border-style'],
16
- fill: style['fill-color']
17
- }
18
- block.call(graphic_attributes) if block_given?
19
- graphic_attributes
20
- end
21
-
22
- # @param [Hash] style
23
- # @yield [attrs]
24
- # @yieldparam [Hash] attrs
25
- # @return [Hash]
26
- def build_text_attributes(style, &block)
27
- text_attributes = {
28
- font: font_family(style['font-family']),
29
- size: style['font-size'],
30
- color: style['color'],
31
- align: text_align(style['text-align']),
32
- valign: text_valign(style['vertical-align']),
33
- styles: font_styles(style['font-style']),
34
- letter_spacing: letter_spacing(style['letter-spacing']),
35
- line_height: line_height(style['line-height']),
36
- overflow: text_overflow(style['overflow']),
37
- word_wrap: word_wrap(style['word-wrap'])
38
- }
39
- block.call(text_attributes) if block_given?
40
- text_attributes
41
- end
42
-
43
- # @param [Array<String>] font_names
44
- # @return [String]
45
- def font_family(font_names)
46
- font_name = font_names.first
47
- default_family_if_missing(font_name)
48
- end
49
-
50
- # @param [Array<String>] styles
51
- # @return [Array<Symbol>]
52
- def font_styles(styles)
53
- styles.map do |font_style|
54
- case font_style
55
- when 'bold' then :bold
56
- when 'italic' then :italic
57
- when 'underline' then :underline
58
- when 'linethrough' then :strikethrough
59
- end
60
- end
61
- end
62
-
63
- # @param [Float, "", nil] spacing
64
- # @return [Float, nil]
65
- def letter_spacing(spacing)
66
- blank_value?(spacing) ? nil : spacing
67
- end
68
-
69
- # @param ["left", "center", "right", ""] align
70
- # @return [:left, :center, :right]
71
- def text_align(align)
72
- case align
73
- when 'left' then :left
74
- when 'center' then :center
75
- when 'right' then :right
76
- when '' then :left
77
- else :left
78
- end
79
- end
80
-
81
- # @param ["top", "middle", "bottom", "", nil] valign
82
- # @return [:top, :center, :bottom]
83
- def text_valign(valign)
84
- case valign
85
- when 'top' then :top
86
- when 'middle' then :center
87
- when 'bottom' then :bottom
88
- when '' then :top
89
- else :top
90
- end
91
- end
92
-
93
- # @param ["truncate", "fit", "expand", "", nil] overflow
94
- # @return [:truncate, :shrink_to_fit, :expand]
95
- def text_overflow(overflow)
96
- case overflow
97
- when 'truncate' then :truncate
98
- when 'fit' then :shrink_to_fit
99
- when 'expand' then :expand
100
- when '' then :truncate
101
- else :truncate
102
- end
103
- end
104
-
105
- # @param ["break-word", "none", "", nil] word_wrap
106
- # @return [:break_word, :none]
107
- def word_wrap(word_wrap)
108
- case word_wrap
109
- when 'break-word' then :break_word
110
- when 'none' then :none
111
- else :none
112
- end
113
- end
114
-
115
- # @param [Float, "", nil] height
116
- # @return [Float, nil]
117
- def line_height(height)
118
- blank_value?(height) ? nil : height
119
- end
120
-
121
- # @param ["left", "center", "right", ""] position
122
- # @return [:left, :center, :right]
123
- def image_position_x(position)
124
- case position
125
- when 'left' then :left
126
- when 'center' then :center
127
- when 'right' then :right
128
- when '' then :left
129
- else :left
130
- end
131
- end
132
-
133
- # @param ["top", "middle", "bottom", ""] position
134
- # @return [:left, :center, :right]
135
- def image_position_y(position)
136
- case position
137
- when 'top' then :top
138
- when 'middle' then :center
139
- when 'bottom' then :bottom
140
- when '' then :top
141
- else :top
142
- end
143
- end
144
- end
145
- end
146
- end
147
- end
@@ -1,135 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Thinreports
4
- module Generator
5
- class PDF
6
- module Graphics
7
- STROKE_DASH = {
8
- dashed: [2, 2],
9
- dotted: [1, 2]
10
- }.freeze
11
-
12
- # @param [Numeric, String] x1
13
- # @param [Numeric, String] y1
14
- # @param [Numeric, String] x2
15
- # @param [Numeric, String] y2
16
- # @param [Hash] attrs ({})
17
- # @option attrs [String] :stroke
18
- # @option attrs [Numeric, String] :stroke_width
19
- # @option attrs ["solid", "dashed", "dotted"] :stroke_type
20
- def line(x1, y1, x2, y2, attrs = {})
21
- with_graphic_styles(attrs) do
22
- pdf.line(pos(x1, y1), pos(x2, y2))
23
- end
24
- end
25
-
26
- # @param [Numeric, String] x
27
- # @param [Numeric, String] y
28
- # @param [Numeric, String] w width
29
- # @param [Numeric, String] h height
30
- # @param [Hash] attrs ({})
31
- # @option attrs [Integer, String] :radius
32
- # @option attrs [String] :stroke
33
- # @option attrs [Numeric, String] :stroke_width
34
- # @option attrs ["solid", "dashed", "dotted"] :stroke_type
35
- # @option attrs [String] :fill
36
- def rect(x, y, w, h, attrs = {})
37
- w, h = s2f(w, h)
38
- radius = s2f(attrs[:radius])
39
-
40
- with_graphic_styles(attrs) do
41
- if radius && !radius.zero?
42
- pdf.rounded_rectangle(pos(x, y), w, h, radius)
43
- else
44
- pdf.rectangle(pos(x, y), w, h)
45
- end
46
- end
47
- end
48
-
49
- # @param [Numeric, String] x center-x
50
- # @param [Numeric, String] y center-y
51
- # @param [Numeric, String] rx
52
- # @param [Numeric, String] ry
53
- # @param [Hash] attrs ({})
54
- # @option attrs [String] :stroke
55
- # @option attrs [Numeric, String] :stroke_width
56
- # @option attrs [Array<Integer, String>] :stroke_dash
57
- # @option attrs ["solid", "dashed", "dotted"] :stroke_type
58
- # @option attrs [String] :fill
59
- def ellipse(x, y, rx, ry, attrs = {})
60
- rx, ry = s2f(rx, ry)
61
-
62
- with_graphic_styles(attrs) do
63
- pdf.ellipse(pos(x, y), rx, ry)
64
- end
65
- end
66
-
67
- # @param [Hash] attrs
68
- def with_graphic_styles(attrs, &block)
69
- stroke = build_stroke_styles(attrs)
70
- fill = build_fill_styles(attrs)
71
-
72
- # Do not draw if no colors given.
73
- return unless fill || stroke
74
-
75
- save_graphics_state
76
-
77
- # Apply stroke-dashed.
78
- if stroke && stroke[:dash]
79
- length, space = stroke[:dash]
80
- pdf.dash(length, space: space)
81
- end
82
-
83
- # Draw with fill and stroke.
84
- if fill && stroke
85
- pdf.fill_and_stroke do
86
- line_width(stroke[:width])
87
- pdf.fill_color(fill[:color])
88
- pdf.stroke_color(stroke[:color])
89
- block.call
90
- end
91
- # Draw only with fill.
92
- elsif fill
93
- pdf.fill do
94
- pdf.fill_color(fill[:color])
95
- block.call
96
- end
97
- # Draw only with stroke.
98
- elsif stroke
99
- pdf.stroke do
100
- line_width(stroke[:width])
101
- pdf.stroke_color(stroke[:color])
102
- block.call
103
- end
104
- end
105
-
106
- restore_graphics_state
107
- end
108
-
109
- # @param [Hash] styles
110
- # @return [Hash, nil]
111
- def build_stroke_styles(styles)
112
- color = styles[:stroke]
113
- width = styles[:stroke_width]
114
- return nil unless color && color != 'none'
115
- return nil unless width && width != 0
116
-
117
- {
118
- color: parse_color(color),
119
- width: s2f(width),
120
- dash: STROKE_DASH[styles[:stroke_type].to_sym]
121
- }
122
- end
123
-
124
- # @param [Hash] styles
125
- # @return [Hash, nil]
126
- def build_fill_styles(styles)
127
- color = styles[:fill]
128
- return nil unless color && color != 'none'
129
-
130
- { color: parse_color(color) }
131
- end
132
- end
133
- end
134
- end
135
- end
@@ -1,98 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'tempfile'
4
- require 'base64'
5
- require 'digest/md5'
6
-
7
- module Thinreports
8
- module Generator
9
- class PDF
10
- module Graphics
11
- # @param [String, IO] filename_or_io
12
- # @param [Numeric, Strng] x
13
- # @param [Numeric, Strng] y
14
- # @param [Numeric, Strng] w
15
- # @param [Numeric, Strng] h
16
- def image(filename_or_io, x, y, w, h)
17
- w, h = s2f(w, h)
18
- pdf.image(filename_or_io, at: pos(x, y), width: w, height: h)
19
- end
20
-
21
- # @param [String] base64_data
22
- # @param [Numeric, Strng] x
23
- # @param [Numeric, Strng] y
24
- # @param [Numeric, Strng] w
25
- # @param [Numeric, Strng] h
26
- def base64image(base64_data, x, y, w, h)
27
- image_data = Base64.decode64(base64_data)
28
- image_id = Digest::MD5.hexdigest(base64_data)
29
- image_path = create_temp_imagefile(image_id, image_data)
30
-
31
- image(image_path, x, y, w, h)
32
- end
33
-
34
- # @param [String, IO] filename_or_io
35
- # @param [Numeric, Strng] x
36
- # @param [Numeric, Strng] y
37
- # @param [Numeric, Strng] w
38
- # @param [Numeric, Strng] h
39
- # @param [Hash] options
40
- # @option options [:left, :center, :right] :position_x (:left)
41
- # @option options [:top, :center, :bottom] :position_y (:top)
42
- # @option options [Numeric] :offset_x
43
- # @option options [Numeric] :offset_y
44
- def image_box(filename_or_io, x, y, w, h, options = {})
45
- w, h = s2f(w, h)
46
-
47
- computed_position = pos(
48
- x + (options[:offset_x] || 0),
49
- y + (options[:offset_y] || 0)
50
- )
51
- pdf.bounding_box(computed_position, width: w, height: h) do
52
- pdf.image(
53
- filename_or_io,
54
- position: options[:position_x] || :left,
55
- vposition: options[:position_y] || :top,
56
- auto_fit: [w, h]
57
- )
58
- end
59
- end
60
-
61
- def image_dimensions(filename_or_io, x, y, w, h, options = {})
62
- w, h = s2f(w, h)
63
- # XXX: Calling @private method
64
- _pdf_obj, info = pdf.build_image_object(filename_or_io)
65
- info.calc_image_dimensions(
66
- position: options[:position_x] || :left,
67
- vposition: options[:position_y] || :top,
68
- auto_fit: [w, h]
69
- )
70
- end
71
-
72
- def clean_temp_images
73
- temp_image_registry.each_value do |image_path|
74
- File.delete(image_path) if File.exist?(image_path)
75
- end
76
- end
77
-
78
- def temp_image_registry
79
- @temp_image_registry ||= {}
80
- end
81
-
82
- # @param [String] image_id
83
- # @param [String] image_data
84
- # @return [String] Path to imagefile
85
- def create_temp_imagefile(image_id, image_data)
86
- temp_image_registry[image_id] ||= begin
87
- file = Tempfile.new('temp-image')
88
- file.binmode
89
- file.write(image_data)
90
- file.open
91
- file
92
- end
93
- temp_image_registry[image_id].path
94
- end
95
- end
96
- end
97
- end
98
- end
@@ -1,178 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Thinreports
4
- module Generator
5
- class PDF
6
- module Graphics
7
- # @param [String] content
8
- # @param [Numeric, String] x
9
- # @param [Numeric, String] y
10
- # @param [Numeric, String] w
11
- # @param [Numeric, String] h
12
- # @param [Hash] attrs ({})
13
- # @option attrs [String] :font
14
- # @option attrs [Numeric, String] :size
15
- # @option attrs [String] :color
16
- # @option attrs [Array<:bold, :italic, :underline, :strikethrough>]
17
- # :styles (nil)
18
- # @option attrs [:left, :center, :right] :align (:left)
19
- # @option attrs [:top, :center, :bottom] :valign (:top)
20
- # @option attrs [Numeric, String] :line_height The total height of an text line.
21
- # @option attrs [Numeric, String] :letter_spacing
22
- # @option attrs [Boolean] :single (false)
23
- # @option attrs [:trancate, :shrink_to_fit, :expand] :overflow (:trancate)
24
- # @option attrs [:none, :break_word] :word_wrap (:none)
25
- def text_box(content, x, y, w, h, attrs = {}, &block)
26
- w, h = s2f(w, h)
27
-
28
- box_attrs = text_box_attrs(
29
- x, y, w, h,
30
- single: attrs.delete(:single),
31
- overflow: attrs[:overflow]
32
- )
33
-
34
- # Do not break by word unless :word_wrap is :break_word
35
- content = text_without_line_wrap(content) if attrs[:word_wrap] == :none
36
-
37
- with_text_styles(attrs) do |built_attrs, font_styles|
38
- if block
39
- block.call [{ text: content, styles: font_styles }],
40
- built_attrs.merge(box_attrs)
41
- else
42
- pdf.formatted_text_box(
43
- [{ text: content, styles: font_styles }],
44
- built_attrs.merge(box_attrs)
45
- )
46
- end
47
- end
48
- rescue Prawn::Errors::CannotFit
49
- # Nothing to do.
50
- #
51
- # When the area is too small compared
52
- # with the content and the style of the text.
53
- # (See prawn/core/text/formatted/line_wrap.rb#L185)
54
- end
55
-
56
- # @see #text_box
57
- def text(content, x, y, w, h, attrs = {})
58
- # Set the :overflow property to :shirink_to_fit.
59
- text_box(content, x, y, w, h, { overflow: :shirink_to_fit }.merge(attrs))
60
- end
61
-
62
- private
63
-
64
- # @param x (see #text_box)
65
- # @param y (see #text_box)
66
- # @param w (see #text_box)
67
- # @param h (see #text_box)
68
- # @param [Hash] states
69
- # @option states [Boolean] :single
70
- # @option states [Symbold] :overflow
71
- # @return [Hash]
72
- def text_box_attrs(x, y, w, h, states = {})
73
- attrs = {
74
- at: pos(x, y),
75
- width: s2f(w)
76
- }
77
- if states[:single]
78
- states[:overflow] != :expand ? attrs.merge(single_line: true) : attrs
79
- else
80
- attrs.merge(height: s2f(h))
81
- end
82
- end
83
-
84
- # @param attrs (see #text)
85
- # @yield [built_attrs, font_styles]
86
- # @yieldparam [Hash] built_attrs The finalized attributes.
87
- # @yieldparam [Array] font_styles The finalized styles.
88
- def with_text_styles(attrs, &block)
89
- # When no color is given, do not draw.
90
- return unless attrs.key?(:color) && attrs[:color] != 'none'
91
-
92
- save_graphics_state
93
-
94
- fontinfo = {
95
- name: attrs.delete(:font).to_s,
96
- color: parse_color(attrs.delete(:color)),
97
- size: s2f(attrs.delete(:size))
98
- }
99
-
100
- # Add the specified value to :leading option.
101
- line_height = attrs.delete(:line_height)
102
- if line_height
103
- attrs[:leading] = text_line_leading(
104
- s2f(line_height),
105
- name: fontinfo[:name],
106
- size: fontinfo[:size]
107
- )
108
- end
109
-
110
- # Set the :character_spacing option.
111
- spacing = attrs.delete(:letter_spacing)
112
- attrs[:character_spacing] = s2f(spacing) if spacing
113
-
114
- # Or... with_font_styles(attrs, fontinfo, &block)
115
- with_font_styles(attrs, fontinfo) do |modified_attrs, styles|
116
- block.call(modified_attrs, styles)
117
- end
118
-
119
- restore_graphics_state
120
- end
121
-
122
- # @param [Numeric] line_height
123
- # @param [Hash] font
124
- # @option font [String] :name Name of font.
125
- # @option font [Numeric] :size Size of font.
126
- # @return [Numeric]
127
- def text_line_leading(line_height, font)
128
- line_height - pdf.font(font[:name], size: font[:size]).height
129
- end
130
-
131
- # @param [String] content
132
- # @return [String]
133
- def text_without_line_wrap(content)
134
- content.gsub(/ /, Prawn::Text::NBSP)
135
- end
136
-
137
- # @param [Hash] attrs
138
- # @param [Hash] font
139
- # @option font [String] :color
140
- # @option font [Numeric] :size
141
- # @option font [String] :name
142
- # @yield [attributes, styles]
143
- # @yieldparam [Hash] modified_attrs
144
- # @yieldparam [Array] styles
145
- def with_font_styles(attrs, font, &block)
146
- # Building font styles.
147
- styles = attrs.delete(:styles)
148
-
149
- if styles
150
- manual, styles = styles.partition do |style|
151
- %i[bold italic].include?(style) && !font_has_style?(font[:name], style)
152
- end
153
- end
154
-
155
- # Emulate bold style.
156
- if manual && manual.include?(:bold)
157
- pdf.stroke_color(font[:color])
158
- pdf.line_width(font[:size] * 0.025)
159
-
160
- # Change rendering mode to :fill_stroke.
161
- attrs[:mode] = :fill_stroke
162
- end
163
-
164
- # Emulate italic style.
165
- if manual && manual.include?(:italic)
166
- # FIXME
167
- # pdf.transformation_matrix(1, 0, 0.26, 1, 0, 0)
168
- end
169
-
170
- pdf.font(font[:name], size: font[:size]) do
171
- pdf.fill_color(font[:color])
172
- block.call(attrs, styles || [])
173
- end
174
- end
175
- end
176
- end
177
- end
178
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Thinreports
4
- module Generator
5
- class PDF
6
- module Graphics
7
- BASE_LINE_WIDTH = 0.9
8
-
9
- private
10
-
11
- # Change the default graphic states defined by Prawn.
12
- def setup_custom_graphic_states
13
- pdf.line_width(BASE_LINE_WIDTH)
14
- end
15
-
16
- # @param [Numeric] width
17
- def line_width(width)
18
- pdf.line_width(width * BASE_LINE_WIDTH)
19
- end
20
-
21
- # Delegate to Prawn::Document#save_graphic_state
22
- # @see Prawn::Document#save_graphics_state
23
- def save_graphics_state
24
- pdf.save_graphics_state
25
- end
26
-
27
- # Delegate to Prawn::Document#restore_graphic_state
28
- # @see Prawn::Document#restore_graphics_state
29
- def restore_graphics_state
30
- pdf.restore_graphics_state
31
- end
32
- end
33
- end
34
- end
35
- end
36
-
37
- require_relative 'graphics/attributes'
38
- require_relative 'graphics/basic'
39
- require_relative 'graphics/image'
40
- require_relative 'graphics/text'