thinreports 0.9.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (213) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/test.yml +39 -0
  3. data/.gitignore +1 -0
  4. data/CHANGELOG.md +59 -2
  5. data/Dockerfile +12 -0
  6. data/Gemfile +7 -4
  7. data/README.md +44 -22
  8. data/Rakefile +14 -31
  9. data/lib/thinreports.rb +16 -15
  10. data/lib/thinreports/config.rb +2 -24
  11. data/lib/thinreports/core/errors.rb +6 -17
  12. data/lib/thinreports/core/format/base.rb +62 -61
  13. data/lib/thinreports/core/shape.rb +10 -12
  14. data/lib/thinreports/core/shape/base.rb +3 -12
  15. data/lib/thinreports/core/shape/base/interface.rb +34 -32
  16. data/lib/thinreports/core/shape/base/internal.rb +45 -43
  17. data/lib/thinreports/core/shape/basic.rb +12 -12
  18. data/lib/thinreports/core/shape/basic/block_format.rb +8 -6
  19. data/lib/thinreports/core/shape/basic/block_interface.rb +24 -22
  20. data/lib/thinreports/core/shape/basic/block_internal.rb +28 -26
  21. data/lib/thinreports/core/shape/basic/format.rb +11 -9
  22. data/lib/thinreports/core/shape/basic/interface.rb +79 -77
  23. data/lib/thinreports/core/shape/basic/internal.rb +17 -14
  24. data/lib/thinreports/core/shape/image_block.rb +9 -9
  25. data/lib/thinreports/core/shape/image_block/format.rb +7 -5
  26. data/lib/thinreports/core/shape/image_block/interface.rb +15 -13
  27. data/lib/thinreports/core/shape/image_block/internal.rb +10 -8
  28. data/lib/thinreports/core/shape/list.rb +13 -13
  29. data/lib/thinreports/core/shape/list/format.rb +83 -77
  30. data/lib/thinreports/core/shape/list/manager.rb +179 -176
  31. data/lib/thinreports/core/shape/list/page.rb +91 -93
  32. data/lib/thinreports/core/shape/list/page_state.rb +42 -40
  33. data/lib/thinreports/core/shape/list/section_format.rb +28 -26
  34. data/lib/thinreports/core/shape/list/section_interface.rb +42 -40
  35. data/lib/thinreports/core/shape/list/section_internal.rb +21 -19
  36. data/lib/thinreports/core/shape/manager.rb +4 -13
  37. data/lib/thinreports/core/shape/manager/format.rb +21 -19
  38. data/lib/thinreports/core/shape/manager/internal.rb +87 -84
  39. data/lib/thinreports/core/shape/manager/target.rb +93 -95
  40. data/lib/thinreports/core/shape/page_number.rb +9 -9
  41. data/lib/thinreports/core/shape/page_number/format.rb +20 -18
  42. data/lib/thinreports/core/shape/page_number/interface.rb +20 -18
  43. data/lib/thinreports/core/shape/page_number/internal.rb +46 -44
  44. data/lib/thinreports/core/shape/style.rb +5 -14
  45. data/lib/thinreports/core/shape/style/base.rb +121 -120
  46. data/lib/thinreports/core/shape/style/basic.rb +12 -10
  47. data/lib/thinreports/core/shape/style/graphic.rb +35 -33
  48. data/lib/thinreports/core/shape/style/text.rb +113 -107
  49. data/lib/thinreports/core/shape/text.rb +9 -9
  50. data/lib/thinreports/core/shape/text/format.rb +10 -9
  51. data/lib/thinreports/core/shape/text/interface.rb +13 -11
  52. data/lib/thinreports/core/shape/text/internal.rb +14 -12
  53. data/lib/thinreports/core/shape/text_block.rb +10 -10
  54. data/lib/thinreports/core/shape/text_block/format.rb +35 -33
  55. data/lib/thinreports/core/shape/text_block/formatter.rb +26 -24
  56. data/lib/thinreports/core/shape/text_block/formatter/basic.rb +25 -25
  57. data/lib/thinreports/core/shape/text_block/formatter/datetime.rb +15 -12
  58. data/lib/thinreports/core/shape/text_block/formatter/number.rb +52 -34
  59. data/lib/thinreports/core/shape/text_block/formatter/padding.rb +17 -14
  60. data/lib/thinreports/core/shape/text_block/interface.rb +25 -23
  61. data/lib/thinreports/core/shape/text_block/internal.rb +66 -68
  62. data/lib/thinreports/core/utils.rb +7 -3
  63. data/lib/thinreports/generator/pdf.rb +24 -25
  64. data/lib/thinreports/generator/pdf/document.rb +109 -110
  65. data/lib/thinreports/generator/pdf/document/draw_shape.rb +57 -51
  66. data/lib/thinreports/generator/pdf/document/draw_template_items.rb +50 -47
  67. data/lib/thinreports/generator/pdf/document/font.rb +67 -58
  68. data/lib/thinreports/generator/pdf/document/graphics.rb +32 -33
  69. data/lib/thinreports/generator/pdf/document/graphics/attributes.rb +121 -121
  70. data/lib/thinreports/generator/pdf/document/graphics/basic.rb +112 -114
  71. data/lib/thinreports/generator/pdf/document/graphics/image.rb +58 -150
  72. data/lib/thinreports/generator/pdf/document/graphics/text.rb +149 -137
  73. data/lib/thinreports/generator/pdf/document/page.rb +60 -64
  74. data/lib/thinreports/generator/pdf/document/parse_color.rb +37 -37
  75. data/lib/thinreports/generator/pdf/drawer/base.rb +41 -41
  76. data/lib/thinreports/generator/pdf/drawer/list.rb +56 -54
  77. data/lib/thinreports/generator/pdf/drawer/list_section.rb +42 -40
  78. data/lib/thinreports/generator/pdf/drawer/page.rb +101 -96
  79. data/lib/thinreports/generator/pdf/prawn_ext.rb +4 -30
  80. data/lib/thinreports/generator/pdf/prawn_ext/calc_image_dimensions.rb +32 -0
  81. data/lib/thinreports/generator/pdf/prawn_ext/width_of.rb +35 -0
  82. data/lib/thinreports/layout.rb +5 -7
  83. data/lib/thinreports/layout/base.rb +5 -9
  84. data/lib/thinreports/layout/format.rb +17 -13
  85. data/lib/thinreports/layout/legacy_schema.rb +17 -13
  86. data/lib/thinreports/layout/version.rb +22 -25
  87. data/lib/thinreports/report.rb +4 -6
  88. data/lib/thinreports/report/base.rb +24 -51
  89. data/lib/thinreports/report/internal.rb +13 -15
  90. data/lib/thinreports/report/page.rb +5 -11
  91. data/lib/thinreports/version.rb +2 -2
  92. data/thinreports.gemspec +10 -19
  93. metadata +13 -288
  94. data/.travis.yml +0 -19
  95. data/examples/character_spacing/character_spacing.rb +0 -8
  96. data/examples/character_spacing/character_spacing.tlf +0 -293
  97. data/examples/dynamic_image/dynamic_image.rb +0 -31
  98. data/examples/dynamic_image/dynamic_image.tlf +0 -661
  99. data/examples/dynamic_image/img200x100.png +0 -0
  100. data/examples/dynamic_image/img50x50.png +0 -0
  101. data/examples/dynamic_style/dynamic_style.rb +0 -150
  102. data/examples/dynamic_style/dynamic_style.tlf +0 -1835
  103. data/examples/dynamic_style/dynamic_style_in_list.tlf +0 -344
  104. data/examples/dynamic_style/image.png +0 -0
  105. data/examples/eudc/eudc.rb +0 -20
  106. data/examples/eudc/eudc.tlf +0 -180
  107. data/examples/eudc/eudc.ttf +0 -0
  108. data/examples/helper.rb +0 -50
  109. data/examples/hidden_shapes/hidden_shapes.rb +0 -9
  110. data/examples/hidden_shapes/hidden_shapes.tlf +0 -449
  111. data/examples/list_events/list_events.rb +0 -32
  112. data/examples/list_events/list_events.tlf +0 -361
  113. data/examples/list_manual_generation/list_manual_generation.rb +0 -22
  114. data/examples/list_manual_generation/list_manual_generation.tlf +0 -132
  115. data/examples/list_page_number/list_page_number.rb +0 -17
  116. data/examples/list_page_number/list_page_number.tlf +0 -254
  117. data/examples/page_number/page_number.rb +0 -33
  118. data/examples/page_number/page_number.tlf +0 -215
  119. data/examples/palleted_png/palleted_png.png +0 -0
  120. data/examples/palleted_png/palleted_png.rb +0 -11
  121. data/examples/palleted_png/palleted_png.tlf +0 -47
  122. data/examples/password_setting/password_setting.rb +0 -10
  123. data/examples/password_setting/password_setting.tlf +0 -45
  124. data/examples/report_callbacks/report_callbacks.rb +0 -14
  125. data/examples/report_callbacks/report_callbacks.tlf +0 -147
  126. data/examples/single_line_tblock/single_line_tblock.rb +0 -13
  127. data/examples/single_line_tblock/single_line_tblock.tlf +0 -170
  128. data/examples/tblock_overflow/tblock_overflow.rb +0 -20
  129. data/examples/tblock_overflow/tblock_overflow.tlf +0 -538
  130. data/examples/tblock_styles/font_size.tlf +0 -383
  131. data/examples/tblock_styles/tblock_styles.rb +0 -43
  132. data/examples/tblock_styles/tblock_styles.tlf +0 -889
  133. data/examples/text_align/text_align.rb +0 -8
  134. data/examples/text_align/text_align.tlf +0 -241
  135. data/examples/typeB_page_size/B4_ISO.tlf +0 -45
  136. data/examples/typeB_page_size/B4_JIS.tlf +0 -45
  137. data/examples/typeB_page_size/typeB_page_size.rb +0 -17
  138. data/examples/word_wrap/word_wrap.rb +0 -26
  139. data/examples/word_wrap/word_wrap.tlf +0 -297
  140. data/lib/thinreports/generator.rb +0 -29
  141. data/lib/thinreports/generator/base.rb +0 -40
  142. data/lib/thinreports/generator/configuration.rb +0 -31
  143. data/lib/thinreports/report/events.rb +0 -32
  144. data/test/data/font.ttf +0 -0
  145. data/test/data/image_normal.jpg +0 -0
  146. data/test/data/image_normal.png +0 -0
  147. data/test/data/image_normal_jpg_noext +0 -0
  148. data/test/data/image_normal_png_noext +0 -0
  149. data/test/data/image_pallete_based.png +0 -0
  150. data/test/data/legacy_layout/all-items.tlf +0 -1
  151. data/test/schema_helper.rb +0 -121
  152. data/test/test_helper.rb +0 -42
  153. data/test/tmp/.gitkeep +0 -0
  154. data/test/unit/core/format/test_base.rb +0 -152
  155. data/test/unit/core/shape/base/test_internal.rb +0 -87
  156. data/test/unit/core/shape/basic/test_block_format.rb +0 -23
  157. data/test/unit/core/shape/basic/test_block_interface.rb +0 -29
  158. data/test/unit/core/shape/basic/test_block_internal.rb +0 -55
  159. data/test/unit/core/shape/basic/test_format.rb +0 -37
  160. data/test/unit/core/shape/basic/test_interface.rb +0 -108
  161. data/test/unit/core/shape/basic/test_internal.rb +0 -55
  162. data/test/unit/core/shape/image_block/test_interface.rb +0 -24
  163. data/test/unit/core/shape/image_block/test_internal.rb +0 -31
  164. data/test/unit/core/shape/list/test_format.rb +0 -111
  165. data/test/unit/core/shape/list/test_manager.rb +0 -67
  166. data/test/unit/core/shape/list/test_page.rb +0 -82
  167. data/test/unit/core/shape/list/test_page_state.rb +0 -31
  168. data/test/unit/core/shape/list/test_section_format.rb +0 -36
  169. data/test/unit/core/shape/list/test_section_interface.rb +0 -75
  170. data/test/unit/core/shape/list/test_section_internal.rb +0 -50
  171. data/test/unit/core/shape/manager/test_format.rb +0 -38
  172. data/test/unit/core/shape/manager/test_internal.rb +0 -132
  173. data/test/unit/core/shape/manager/test_target.rb +0 -140
  174. data/test/unit/core/shape/page_number/test_format.rb +0 -55
  175. data/test/unit/core/shape/page_number/test_interface.rb +0 -33
  176. data/test/unit/core/shape/page_number/test_internal.rb +0 -81
  177. data/test/unit/core/shape/styles/test_base.rb +0 -191
  178. data/test/unit/core/shape/styles/test_basic.rb +0 -24
  179. data/test/unit/core/shape/styles/test_graphic.rb +0 -50
  180. data/test/unit/core/shape/styles/test_text.rb +0 -97
  181. data/test/unit/core/shape/text/test_format.rb +0 -44
  182. data/test/unit/core/shape/text/test_internal.rb +0 -20
  183. data/test/unit/core/shape/text_block/formatter/test_basic.rb +0 -24
  184. data/test/unit/core/shape/text_block/formatter/test_datetime.rb +0 -49
  185. data/test/unit/core/shape/text_block/formatter/test_number.rb +0 -76
  186. data/test/unit/core/shape/text_block/formatter/test_padding.rb +0 -77
  187. data/test/unit/core/shape/text_block/test_format.rb +0 -169
  188. data/test/unit/core/shape/text_block/test_formatter.rb +0 -28
  189. data/test/unit/core/shape/text_block/test_interface.rb +0 -63
  190. data/test/unit/core/shape/text_block/test_internal.rb +0 -128
  191. data/test/unit/core/test_shape.rb +0 -52
  192. data/test/unit/core/test_utils.rb +0 -68
  193. data/test/unit/generator/pdf/document/graphics/test_attributes.rb +0 -135
  194. data/test/unit/generator/pdf/document/graphics/test_basic.rb +0 -45
  195. data/test/unit/generator/pdf/document/graphics/test_image.rb +0 -150
  196. data/test/unit/generator/pdf/document/graphics/test_text.rb +0 -171
  197. data/test/unit/generator/pdf/document/test_font.rb +0 -84
  198. data/test/unit/generator/pdf/document/test_graphics.rb +0 -42
  199. data/test/unit/generator/pdf/document/test_page.rb +0 -122
  200. data/test/unit/generator/pdf/document/test_parse_color.rb +0 -30
  201. data/test/unit/generator/pdf/test_document.rb +0 -20
  202. data/test/unit/generator/test_base.rb +0 -40
  203. data/test/unit/generator/test_configuration.rb +0 -21
  204. data/test/unit/generator/test_pdf.rb +0 -24
  205. data/test/unit/layout/test_base.rb +0 -41
  206. data/test/unit/layout/test_format.rb +0 -100
  207. data/test/unit/layout/test_legacy_schema.rb +0 -574
  208. data/test/unit/layout/test_version.rb +0 -95
  209. data/test/unit/report/test_base.rb +0 -262
  210. data/test/unit/report/test_internal.rb +0 -206
  211. data/test/unit/test_config.rb +0 -51
  212. data/test/unit/test_layout.rb +0 -12
  213. data/test/unit/test_report.rb +0 -18
@@ -1,172 +1,80 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'tempfile'
4
4
  require 'base64'
5
5
  require 'digest/md5'
6
- require 'chunky_png'
7
6
 
8
7
  module Thinreports
9
8
  module Generator
10
-
11
- module PDF::Graphics
12
- # @param [String] filename
13
- # @param [Numeric, Strng] x
14
- # @param [Numeric, Strng] y
15
- # @param [Numeric, Strng] w
16
- # @param [Numeric, Strng] h
17
- def image(filename, x, y, w, h)
18
- w, h = s2f(w, h)
19
- pdf.image(filename, at: pos(x, y), width: w, height: h)
20
- end
21
-
22
- # @param [String] image_type Mime-type of image
23
- # @param [String] base64
24
- # @param [Numeric, Strng] x
25
- # @param [Numeric, Strng] y
26
- # @param [Numeric, Strng] w
27
- # @param [Numeric, Strng] h
28
- def base64image(image_type, base64_data, x, y, w, h)
29
- image_path = normalize_image_from_base64(image_type, base64_data)
30
- image(image_path, x, y, w, h)
31
- end
32
-
33
- # @param [String, IO] file
34
- # @param [Numeric, Strng] x
35
- # @param [Numeric, Strng] y
36
- # @param [Numeric, Strng] w
37
- # @param [Numeric, Strng] h
38
- # @param [Hash] options
39
- # @option options [:left, :center, :right] :position_x (:left)
40
- # @option options [:top, :center, :bottom] :position_y (:top)
41
- def image_box(file, x, y, w, h, options = {})
42
- image_data_or_path = normalize_image_from_file(file)
43
-
44
- w, h = s2f(w, h)
45
- pdf.bounding_box(pos(x, y), width: w, height: h) do
46
- pdf.image(
47
- image_data_or_path,
48
- position: options[:position_x] || :left,
49
- vposition: options[:position_y] || :top,
50
- auto_fit: [w, h]
51
- )
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)
52
19
  end
53
- end
54
-
55
- def normalize_image_from_base64(image_type, base64_string)
56
- raw_image_data = Base64.decode64(base64_string)
57
-
58
- image_data =
59
- if png_conversion_enabled? && image_type == 'image/png'
60
- png_normalizer = PNGNormalizer.load_blob(raw_image_data)
61
-
62
- if png_normalizer.need_normalize?
63
- png_normalizer.normalize
64
- else
65
- raw_image_data
66
- end
67
- else
68
- raw_image_data
69
- end
70
20
 
71
- image_id = Digest::MD5.hexdigest(base64_string)
72
- create_temp_imagefile(image_id, image_data)
73
- end
74
-
75
- def normalize_image_from_file(file)
76
- return file unless file.is_a?(String)
77
-
78
- filename = file
79
- extname = File.extname(filename)
80
-
81
- return filename unless png_conversion_enabled?
82
- return filename unless extname.downcase == '.png' || extname.empty?
83
-
84
- return temp_image_registry[filename].path if temp_image_registry.key?(filename)
85
-
86
- png_normalizer = PNGNormalizer.load_file(filename)
87
-
88
- # Returns the original filename when the image is not PNG.
89
- return filename if png_normalizer.nil?
90
- return filename unless png_normalizer.need_normalize?
91
-
92
- image_id = filename
93
- image_data = png_normalizer.normalize
94
-
95
- create_temp_imagefile(image_id, image_data)
96
- end
97
-
98
- def clean_temp_images
99
- temp_image_registry.each_value do |image_path|
100
- File.delete(image_path) if File.exist?(image_path)
101
- end
102
- end
103
-
104
- def temp_image_registry
105
- @temp_image_registry ||= {}
106
- end
107
-
108
- # @param [String] image_id
109
- # @param [String] image_data
110
- # @return [String] Path to imagefile
111
- def create_temp_imagefile(image_id, image_data)
112
- temp_image_registry[image_id] ||= begin
113
- file = Tempfile.new('temp-image')
114
- file.binmode
115
- file.write(image_data)
116
- file.open
117
- file
118
- end
119
- temp_image_registry[image_id].path
120
- end
121
-
122
- def png_conversion_enabled?
123
- Thinreports.config.convert_palleted_transparency_png
124
- end
125
-
126
- class PNGNormalizer
127
- def self.load_file(filename)
128
- image = ChunkyPNG::Image.from_file(filename)
129
- datastream = ChunkyPNG::Datastream.from_file(filename)
130
- self.new image, datastream
131
- rescue ChunkyPNG::SignatureMismatch
132
- # Returns nil if image is not PNG.
133
- nil
134
- end
135
-
136
- def self.load_blob(data)
137
- image = ChunkyPNG::Image.from_blob(data)
138
- datastream = ChunkyPNG::Datastream.from_blob(data)
139
- self.new image, datastream
140
- rescue ChunkyPNG::SignatureMismatch
141
- # Returns nil if image is not PNG.
142
- nil
143
- end
144
-
145
- def initialize(image, datastream)
146
- @image = image
147
- @datastream = datastream
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)
148
32
  end
149
33
 
150
- def need_normalize?
151
- pallete_based? && transparency_chunk?
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
+ def image_box(filename_or_io, x, y, w, h, options = {})
43
+ w, h = s2f(w, h)
44
+ pdf.bounding_box(pos(x, y), width: w, height: h) do
45
+ pdf.image(
46
+ filename_or_io,
47
+ position: options[:position_x] || :left,
48
+ vposition: options[:position_y] || :top,
49
+ auto_fit: [w, h]
50
+ )
51
+ end
152
52
  end
153
53
 
154
- def normalize
155
- @image.to_blob(color_mode: ChunkyPNG::COLOR_TRUECOLOR_ALPHA)
54
+ def clean_temp_images
55
+ temp_image_registry.each_value do |image_path|
56
+ File.delete(image_path) if File.exist?(image_path)
57
+ end
156
58
  end
157
59
 
158
- private
159
-
160
- def pallete_based?
161
- color_mode, _depth = @image.palette.best_color_settings
162
- color_mode == ChunkyPNG::COLOR_INDEXED
60
+ def temp_image_registry
61
+ @temp_image_registry ||= {}
163
62
  end
164
63
 
165
- def transparency_chunk?
166
- !@datastream.transparency_chunk.nil?
64
+ # @param [String] image_id
65
+ # @param [String] image_data
66
+ # @return [String] Path to imagefile
67
+ def create_temp_imagefile(image_id, image_data)
68
+ temp_image_registry[image_id] ||= begin
69
+ file = Tempfile.new('temp-image')
70
+ file.binmode
71
+ file.write(image_data)
72
+ file.open
73
+ file
74
+ end
75
+ temp_image_registry[image_id].path
167
76
  end
168
77
  end
169
78
  end
170
-
171
79
  end
172
80
  end
@@ -1,161 +1,173 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Thinreports
4
4
  module Generator
5
-
6
- module PDF::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 = {})
26
- w, h = s2f(w, h)
27
- box_attrs = text_box_attrs(x, y, w, h, single: attrs.delete(:single),
28
- overflow: attrs[:overflow])
29
- # Do not break by word unless :word_wrap is :break_word
30
- content = text_without_line_wrap(content) if attrs[:word_wrap] == :none
31
-
32
- with_text_styles(attrs) do |built_attrs, font_styles|
33
- pdf.formatted_text_box([{ text: content, styles: font_styles }],
34
- built_attrs.merge(box_attrs))
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 = {})
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
+ pdf.formatted_text_box(
39
+ [{ text: content, styles: font_styles }],
40
+ built_attrs.merge(box_attrs)
41
+ )
42
+ end
43
+ rescue Prawn::Errors::CannotFit
44
+ # Nothing to do.
45
+ #
46
+ # When the area is too small compared
47
+ # with the content and the style of the text.
48
+ # (See prawn/core/text/formatted/line_wrap.rb#L185)
35
49
  end
36
- rescue Prawn::Errors::CannotFit
37
- # Nothing to do.
38
- #
39
- # When the area is too small compared
40
- # with the content and the style of the text.
41
- # (See prawn/core/text/formatted/line_wrap.rb#L185)
42
- end
43
50
 
44
- # @see #text_box
45
- def text(content, x, y, w, h, attrs = {})
46
- # Set the :overflow property to :shirink_to_fit.
47
- text_box(content, x, y, w, h, { overflow: :shirink_to_fit }.merge(attrs))
48
- end
49
-
50
- private
51
-
52
- # @param x (see #text_box)
53
- # @param y (see #text_box)
54
- # @param w (see #text_box)
55
- # @param h (see #text_box)
56
- # @param [Hash] states
57
- # @option states [Boolean] :single
58
- # @option states [Symbold] :overflow
59
- # @return [Hash]
60
- def text_box_attrs(x, y, w, h, states = {})
61
- attrs = {at: pos(x, y),
62
- width: s2f(w)}
63
- if states[:single]
64
- states[:overflow] != :expand ? attrs.merge(single_line: true) : attrs
65
- else
66
- attrs.merge(height: s2f(h))
51
+ # @see #text_box
52
+ def text(content, x, y, w, h, attrs = {})
53
+ # Set the :overflow property to :shirink_to_fit.
54
+ text_box(content, x, y, w, h, { overflow: :shirink_to_fit }.merge(attrs))
67
55
  end
68
- end
69
56
 
70
- # @param attrs (see #text)
71
- # @yield [built_attrs, font_styles]
72
- # @yieldparam [Hash] built_attrs The finalized attributes.
73
- # @yieldparam [Array] font_styles The finalized styles.
74
- def with_text_styles(attrs, &block)
75
- # When no color is given, do not draw.
76
- return unless attrs.key?(:color) && attrs[:color] != 'none'
77
-
78
- save_graphics_state
79
-
80
- fontinfo = {name: attrs.delete(:font).to_s,
81
- color: parse_color(attrs.delete(:color)),
82
- size: s2f(attrs.delete(:size))}
83
-
84
- # Add the specified value to :leading option.
85
- line_height = attrs.delete(:line_height)
86
- if line_height
87
- attrs[:leading] = text_line_leading(s2f(line_height),
88
- name: fontinfo[:name],
89
- size: fontinfo[:size])
57
+ private
58
+
59
+ # @param x (see #text_box)
60
+ # @param y (see #text_box)
61
+ # @param w (see #text_box)
62
+ # @param h (see #text_box)
63
+ # @param [Hash] states
64
+ # @option states [Boolean] :single
65
+ # @option states [Symbold] :overflow
66
+ # @return [Hash]
67
+ def text_box_attrs(x, y, w, h, states = {})
68
+ attrs = {
69
+ at: pos(x, y),
70
+ width: s2f(w)
71
+ }
72
+ if states[:single]
73
+ states[:overflow] != :expand ? attrs.merge(single_line: true) : attrs
74
+ else
75
+ attrs.merge(height: s2f(h))
76
+ end
90
77
  end
91
78
 
92
- # Set the :character_spacing option.
93
- spacing = attrs.delete(:letter_spacing)
94
- attrs[:character_spacing] = s2f(spacing) if spacing
79
+ # @param attrs (see #text)
80
+ # @yield [built_attrs, font_styles]
81
+ # @yieldparam [Hash] built_attrs The finalized attributes.
82
+ # @yieldparam [Array] font_styles The finalized styles.
83
+ def with_text_styles(attrs, &block)
84
+ # When no color is given, do not draw.
85
+ return unless attrs.key?(:color) && attrs[:color] != 'none'
86
+
87
+ save_graphics_state
88
+
89
+ fontinfo = {
90
+ name: attrs.delete(:font).to_s,
91
+ color: parse_color(attrs.delete(:color)),
92
+ size: s2f(attrs.delete(:size))
93
+ }
94
+
95
+ # Add the specified value to :leading option.
96
+ line_height = attrs.delete(:line_height)
97
+ if line_height
98
+ attrs[:leading] = text_line_leading(
99
+ s2f(line_height),
100
+ name: fontinfo[:name],
101
+ size: fontinfo[:size]
102
+ )
103
+ end
95
104
 
96
- # Or... with_font_styles(attrs, fontinfo, &block)
97
- with_font_styles(attrs, fontinfo) do |modified_attrs, styles|
98
- block.call(modified_attrs, styles)
99
- end
105
+ # Set the :character_spacing option.
106
+ spacing = attrs.delete(:letter_spacing)
107
+ attrs[:character_spacing] = s2f(spacing) if spacing
100
108
 
101
- restore_graphics_state
102
- end
109
+ # Or... with_font_styles(attrs, fontinfo, &block)
110
+ with_font_styles(attrs, fontinfo) do |modified_attrs, styles|
111
+ block.call(modified_attrs, styles)
112
+ end
103
113
 
104
- # @param [Numeric] line_height
105
- # @param [Hash] font
106
- # @option font [String] :name Name of font.
107
- # @option font [Numeric] :size Size of font.
108
- # @return [Numeric]
109
- def text_line_leading(line_height, font)
110
- line_height - pdf.font(font[:name], size: font[:size]).height
111
- end
114
+ restore_graphics_state
115
+ end
112
116
 
113
- # @param [String] content
114
- # @return [String]
115
- def text_without_line_wrap(content)
116
- content.gsub(/ /, Prawn::Text::NBSP)
117
- end
117
+ # @param [Numeric] line_height
118
+ # @param [Hash] font
119
+ # @option font [String] :name Name of font.
120
+ # @option font [Numeric] :size Size of font.
121
+ # @return [Numeric]
122
+ def text_line_leading(line_height, font)
123
+ line_height - pdf.font(font[:name], size: font[:size]).height
124
+ end
118
125
 
119
- # @param [Hash] attrs
120
- # @param [Hash] font
121
- # @option font [String] :color
122
- # @option font [Numeric] :size
123
- # @option font [String] :name
124
- # @yield [attributes, styles]
125
- # @yieldparam [Hash] modified_attrs
126
- # @yieldparam [Array] styles
127
- def with_font_styles(attrs, font, &block)
128
- # Building font styles.
129
- styles = attrs.delete(:styles)
130
-
131
- if styles
132
- manual, styles = styles.partition do |style|
133
- [:bold, :italic].include?(style) && !font_has_style?(font[:name], style)
134
- end
126
+ # @param [String] content
127
+ # @return [String]
128
+ def text_without_line_wrap(content)
129
+ content.gsub(/ /, Prawn::Text::NBSP)
135
130
  end
136
131
 
137
- # Emulate bold style.
138
- if manual && manual.include?(:bold)
139
- pdf.stroke_color(font[:color])
140
- pdf.line_width(font[:size] * 0.025)
132
+ # @param [Hash] attrs
133
+ # @param [Hash] font
134
+ # @option font [String] :color
135
+ # @option font [Numeric] :size
136
+ # @option font [String] :name
137
+ # @yield [attributes, styles]
138
+ # @yieldparam [Hash] modified_attrs
139
+ # @yieldparam [Array] styles
140
+ def with_font_styles(attrs, font, &block)
141
+ # Building font styles.
142
+ styles = attrs.delete(:styles)
143
+
144
+ if styles
145
+ manual, styles = styles.partition do |style|
146
+ %i[bold italic].include?(style) && !font_has_style?(font[:name], style)
147
+ end
148
+ end
141
149
 
142
- # Change rendering mode to :fill_stroke.
143
- attrs[:mode] = :fill_stroke
144
- end
150
+ # Emulate bold style.
151
+ if manual && manual.include?(:bold)
152
+ pdf.stroke_color(font[:color])
153
+ pdf.line_width(font[:size] * 0.025)
145
154
 
146
- # Emulate italic style.
147
- if manual && manual.include?(:italic)
148
- # FIXME
149
- # pdf.transformation_matrix(1, 0, 0.26, 1, 0, 0)
150
- end
155
+ # Change rendering mode to :fill_stroke.
156
+ attrs[:mode] = :fill_stroke
157
+ end
158
+
159
+ # Emulate italic style.
160
+ if manual && manual.include?(:italic)
161
+ # FIXME
162
+ # pdf.transformation_matrix(1, 0, 0.26, 1, 0, 0)
163
+ end
151
164
 
152
- pdf.font(font[:name], size: font[:size]) do
153
- pdf.fill_color(font[:color])
154
- block.call(attrs, styles || [])
165
+ pdf.font(font[:name], size: font[:size]) do
166
+ pdf.fill_color(font[:color])
167
+ block.call(attrs, styles || [])
168
+ end
155
169
  end
156
170
  end
157
-
158
171
  end
159
-
160
172
  end
161
173
  end