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
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module BasicReport
5
+ module Core
6
+ module Shape
7
+ module TextBlock
8
+ class Interface < Basic::BlockInterface
9
+ internal_delegators :format_enabled?
10
+
11
+ # @param [Boolean] enabled
12
+ # @return [self]
13
+ def format_enabled(enabled)
14
+ internal.format_enabled(enabled)
15
+ self
16
+ end
17
+
18
+ # @param [Object] val
19
+ # @param [Hash<Symbol, Object>] style_settings
20
+ # @return [self]
21
+ def set(val, style_settings = {})
22
+ value(val)
23
+ styles(style_settings) #=> self
24
+ end
25
+
26
+ private
27
+
28
+ # @see Thinreports::BasicReport::Core::Shape::Base::Interface#init_internal
29
+ def init_internal(parent, format)
30
+ TextBlock::Internal.new(parent, format)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module BasicReport
5
+ module Core
6
+ module Shape
7
+ module TextBlock
8
+ class Internal < Basic::BlockInternal
9
+ format_delegators :multiple?
10
+
11
+ attr_reader :style
12
+
13
+ def initialize(*args)
14
+ super(*args)
15
+
16
+ @reference = nil
17
+ @formatter = nil
18
+
19
+ @style = Style::Text.new(format)
20
+ @style.accessible_styles.delete(:valign) unless multiple?
21
+ end
22
+
23
+ def read_value
24
+ if format.has_reference?
25
+ @reference ||= parent.item(format.ref_id)
26
+ @reference.value
27
+ else
28
+ super
29
+ end
30
+ end
31
+
32
+ def write_value(val)
33
+ if format.has_reference?
34
+ warn 'The set value was not saved, ' \
35
+ "Because '#{format.id}' has reference to '#{format.ref_id}'."
36
+ else
37
+ super
38
+ end
39
+ end
40
+
41
+ def real_value
42
+ if format_enabled?
43
+ formatter.apply(read_value)
44
+ else
45
+ super
46
+ end
47
+ end
48
+
49
+ def format_enabled(enabled)
50
+ states[:format_enabled] = enabled
51
+ end
52
+
53
+ def format_enabled?
54
+ if states.key?(:format_enabled)
55
+ states[:format_enabled]
56
+ else
57
+ !blank_value?(format.format_base) || format.has_format?
58
+ end
59
+ end
60
+
61
+ def type_of?(type_name)
62
+ type_name == TextBlock::TYPE_NAME || super
63
+ end
64
+
65
+ private
66
+
67
+ def formatter
68
+ @formatter ||= TextBlock::Formatter.setup(format)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Thinreports
4
- module Core
5
- module Shape
6
- module TextBlock
7
- TYPE_NAME = 'text-block'
4
+ module BasicReport
5
+ module Core
6
+ module Shape
7
+ module TextBlock
8
+ TYPE_NAME = 'text-block'
9
+ end
8
10
  end
9
11
  end
10
12
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module BasicReport
5
+ module Core
6
+ module Shape
7
+ def Interface(parent, format)
8
+ find_by_type(format.type)::Interface.new(parent, format)
9
+ end
10
+
11
+ def Format(type)
12
+ find_by_type(type)::Format
13
+ end
14
+
15
+ module_function :Interface, :Format
16
+
17
+ def self.find_by_type(type)
18
+ case type
19
+ when TextBlock::TYPE_NAME then TextBlock
20
+ when ImageBlock::TYPE_NAME then ImageBlock
21
+ when List::TYPE_NAME then List
22
+ when StackView::TYPE_NAME then StackView
23
+ when Text::TYPE_NAME then Text
24
+ when PageNumber::TYPE_NAME then PageNumber
25
+ when *Basic::TYPE_NAMES then Basic
26
+ else
27
+ raise Thinreports::BasicReport::Errors::UnknownShapeType
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ require_relative 'shape/style'
36
+ require_relative 'shape/manager'
37
+ require_relative 'shape/base'
38
+ require_relative 'shape/basic'
39
+ require_relative 'shape/text'
40
+ require_relative 'shape/text_block'
41
+ require_relative 'shape/image_block'
42
+ require_relative 'shape/list'
43
+ require_relative 'shape/stack_view'
44
+ require_relative 'shape/page_number'
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module BasicReport
5
+ module Utils
6
+ def self.included(klass)
7
+ klass.extend self
8
+ end
9
+
10
+ def deep_copy(src)
11
+ case src
12
+ when Hash
13
+ src.each_with_object({}) do |(k, v), h|
14
+ h[k] = v.dup rescue v
15
+ end
16
+ when Array
17
+ src.map do |a|
18
+ a.dup rescue a
19
+ end
20
+ else
21
+ raise ArgumentError
22
+ end
23
+ end
24
+
25
+ def blank_value?(value)
26
+ case value
27
+ when String then value.empty?
28
+ when NilClass then true
29
+ else false
30
+ end
31
+ end
32
+
33
+ def call_block_in(scope, &block)
34
+ return scope unless block_given?
35
+
36
+ if block.arity == 1
37
+ block.call(scope)
38
+ else
39
+ scope.instance_eval(&block)
40
+ end
41
+ scope
42
+ end
43
+ end
44
+
45
+ extend Utils
46
+ end
47
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module BasicReport
5
+ module Generator
6
+ class PDF
7
+ module DrawShape
8
+ # @param [Thinreports::BasicReport::Core::Shape::TextBlock::Internal] shape
9
+ # @param [Numeric] height (nil) It will be used as rendering height if present.
10
+ # Otherwise, the rendering height is the height of schema.
11
+ # @param [:truncate, :shrink_to_fit, :expand] overflow (nil) It will be set the overflow attribute if present.
12
+ def draw_shape_tblock(shape, height: nil, overflow: nil, &block)
13
+ x, y, w = shape.format.attributes.values_at('x', 'y', 'width')
14
+
15
+ h = height || shape.format.attributes['height']
16
+
17
+ content = shape.real_value.to_s
18
+ return if content.empty?
19
+
20
+ attrs = build_text_attributes(shape.style.finalized_styles)
21
+ attrs[:overflow] = overflow if overflow
22
+
23
+ unless shape.multiple?
24
+ content = content.tr("\n", ' ')
25
+ attrs[:single] = true
26
+ end
27
+
28
+ text_box(content, x, y, w, h, attrs, &block)
29
+ end
30
+
31
+ def draw_shape_pageno(shape, page_no, page_count)
32
+ x, y, w, h = shape.format.attributes.values_at('x', 'y', 'width', 'height')
33
+
34
+ attrs = build_text_attributes(shape.style.finalized_styles)
35
+ text_box(shape.build_format(page_no, page_count), x, y, w, h, attrs)
36
+ end
37
+
38
+ # @param [Thinreports::BasicReport::Core::Shape::Basic::Internal] shape
39
+ def draw_shape_image(shape)
40
+ x, y, w, h = shape.format.attributes.values_at('x', 'y', 'width', 'height')
41
+
42
+ image_data = shape.format.attributes['data']
43
+ base64image(image_data['base64'], x, y, w, h)
44
+ end
45
+
46
+ # @param [Thinreports::BasicReport::Core::Shape::ImageBlock::Internal] shape
47
+ def draw_shape_iblock(shape)
48
+ return if blank_value?(shape.src)
49
+
50
+ x, y, w, h = shape.format.attributes.values_at('x', 'y', 'width', 'height')
51
+ style = shape.style.finalized_styles
52
+
53
+ image_box(
54
+ shape.src, x, y, w, h,
55
+ position_x: image_position_x(style['position-x']),
56
+ position_y: image_position_y(style['position-y']),
57
+ offset_x: style['offset-x'],
58
+ offset_y: style['offset-y']
59
+ )
60
+ end
61
+
62
+ def shape_iblock_dimenions(shape)
63
+ return nil if blank_value?(shape.src)
64
+
65
+ x, y, w, h = shape.format.attributes.values_at('x', 'y', 'width', 'height')
66
+ style = shape.style.finalized_styles
67
+
68
+ image_dimensions(
69
+ shape.src, x, y, w, h,
70
+ position_x: image_position_x(style['position-x']),
71
+ position_y: image_position_y(style['position-y'])
72
+ )
73
+ end
74
+
75
+ # @param [Thinreports::BasicReport::Core::Shape::Text::Internal] shape
76
+ def draw_shape_text(shape, dheight = 0)
77
+ x, y, w, h = shape.format.attributes.values_at('x', 'y', 'width', 'height')
78
+ text(
79
+ shape.texts.join("\n"), x, y, w, h + dheight,
80
+ build_text_attributes(shape.style.finalized_styles)
81
+ )
82
+ end
83
+
84
+ # @param [Thinreports::BasicReport::Core::Shape::Basic::Internal] shape
85
+ def draw_shape_ellipse(shape)
86
+ cx, cy, rx, ry = shape.format.attributes.values_at('cx', 'cy', 'rx', 'ry')
87
+ ellipse(cx, cy, rx, ry, build_graphic_attributes(shape.style.finalized_styles))
88
+ end
89
+
90
+ # @param [Thinreports::BasicReport::Core::Shape::Basic::Internal] shape
91
+ def draw_shape_line(shape, dy1 = 0, dy2 = 0)
92
+ x1, y1, x2, y2 = shape.format.attributes.values_at('x1', 'y1', 'x2', 'y2')
93
+ line(x1, y1 + dy1, x2, y2 + dy2, build_graphic_attributes(shape.style.finalized_styles))
94
+ end
95
+
96
+ # @param [Thinreports::BasicReport::Core::Shape::Basic::Internal] shape
97
+ def draw_shape_rect(shape, dheight = 0)
98
+ x, y, w, h = shape.format.attributes.values_at('x', 'y', 'width', 'height')
99
+ rect_attributes = build_graphic_attributes(shape.style.finalized_styles) do |attrs|
100
+ attrs[:radius] = shape.format.attributes['border-radius']
101
+ end
102
+ rect(x, y, w, h + dheight, rect_attributes)
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module BasicReport
5
+ module Generator
6
+ class PDF
7
+ module DrawTemplateItems
8
+ # @param [Array<Hash>] items
9
+ def draw_template_items(items)
10
+ items.each do |item_attributes|
11
+ next unless drawable?(item_attributes)
12
+
13
+ case item_attributes['type']
14
+ when 'text' then draw_text(item_attributes)
15
+ when 'image' then draw_image(item_attributes)
16
+ when 'rect' then draw_rect(item_attributes)
17
+ when 'ellipse' then draw_ellipse(item_attributes)
18
+ when 'line' then draw_line(item_attributes)
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ # @param [Hash] item_attributes
26
+ def draw_rect(item_attributes)
27
+ x, y, w, h = item_attributes.values_at('x', 'y', 'width', 'height')
28
+ graphic_attributes = build_graphic_attributes(item_attributes['style']) do |attrs|
29
+ attrs[:radius] = item_attributes['border-radius']
30
+ end
31
+
32
+ rect(x, y, w, h, graphic_attributes)
33
+ end
34
+
35
+ # @see #draw_rect
36
+ def draw_ellipse(item_attributes)
37
+ x, y, rx, ry = item_attributes.values_at('cx', 'cy', 'rx', 'ry')
38
+ ellipse(x, y, rx, ry, build_graphic_attributes(item_attributes['style']))
39
+ end
40
+
41
+ # @see #draw_rect
42
+ def draw_line(item_attributes)
43
+ x1, y1, x2, y2 = item_attributes.values_at('x1', 'y1', 'x2', 'y2')
44
+ line(x1, y1, x2, y2, build_graphic_attributes(item_attributes['style']))
45
+ end
46
+
47
+ # @see #draw_rect
48
+ def draw_text(item_attributes)
49
+ x, y, w, h = item_attributes.values_at('x', 'y', 'width', 'height')
50
+ text(
51
+ item_attributes['texts'].join("\n"), x, y, w, h,
52
+ build_text_attributes(item_attributes['style'])
53
+ )
54
+ end
55
+
56
+ # @see #draw_rect
57
+ def draw_image(item_attributes)
58
+ x, y, w, h = item_attributes.values_at('x', 'y', 'width', 'height')
59
+ image_data = item_attributes['data']
60
+
61
+ base64image(image_data['base64'], x, y, w, h)
62
+ end
63
+
64
+ def drawable?(item_attributes)
65
+ item_attributes['id'].empty? && item_attributes['display']
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module BasicReport
5
+ module Generator
6
+ class PDF
7
+ module Font
8
+ FONT_STORE = Thinreports.root.join('fonts')
9
+
10
+ BUILTIN_FONTS = {
11
+ 'IPAMincho' => FONT_STORE.join('ipam.ttf').to_s,
12
+ 'IPAPMincho' => FONT_STORE.join('ipamp.ttf').to_s,
13
+ 'IPAGothic' => FONT_STORE.join('ipag.ttf').to_s,
14
+ 'IPAPGothic' => FONT_STORE.join('ipagp.ttf').to_s
15
+ }.freeze
16
+
17
+ DEFAULT_FALLBACK_FONTS = %w[IPAMincho].freeze
18
+
19
+ PRAWN_BUINTIN_FONT_ALIASES = {
20
+ 'Courier New' => 'Courier',
21
+ 'Times New Roman' => 'Times-Roman'
22
+ }.freeze
23
+
24
+ def setup_fonts
25
+ # Install built-in fonts.
26
+ BUILTIN_FONTS.each do |font_name, font_path|
27
+ install_font(font_name, font_path)
28
+ end
29
+
30
+ # Create aliases from the font list provided by Prawn.
31
+ PRAWN_BUINTIN_FONT_ALIASES.each do |alias_name, name|
32
+ pdf.font_families[alias_name] = pdf.font_families[name]
33
+ end
34
+
35
+ # Setup custom fallback fonts
36
+ fallback_fonts = Thinreports.config.fallback_fonts.uniq
37
+ fallback_fonts.map!.with_index do |font, i|
38
+ if pdf.font_families.key?(font)
39
+ font
40
+ else
41
+ install_font "Custom-fallback-font#{i}", font
42
+ end
43
+ end
44
+
45
+ # Set fallback fonts
46
+ pdf.fallback_fonts(fallback_fonts + DEFAULT_FALLBACK_FONTS)
47
+ end
48
+
49
+ # @param [String] name
50
+ # @param [String] file
51
+ # @return [String] installed font name
52
+ def install_font(name, file)
53
+ raise Errors::FontFileNotFound unless File.exist?(file)
54
+
55
+ pdf.font_families[name] = {
56
+ normal: file,
57
+ bold: file,
58
+ italic: file,
59
+ bold_italic: file
60
+ }
61
+ name
62
+ end
63
+
64
+ # @return [String]
65
+ def default_family
66
+ 'Helvetica'
67
+ end
68
+
69
+ # @param [String] family
70
+ # @return [String]
71
+ def default_family_if_missing(family)
72
+ pdf.font_families.key?(family) ? family : default_family
73
+ end
74
+
75
+ # @param [String] font_name
76
+ # @param [:bold, :italic] font_style
77
+ # @return [Boolean]
78
+ def font_has_style?(font_name, font_style)
79
+ font = pdf.font_families[font_name]
80
+
81
+ return false unless font
82
+ return false unless font.key?(font_style)
83
+
84
+ font[font_style] != font[:normal]
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module BasicReport
5
+ module Generator
6
+ class PDF
7
+ module Graphics
8
+ # @param [Hash] style
9
+ # @yield [attrs]
10
+ # @yieldparam [Hash] attrs
11
+ # @return [Hash]
12
+ def build_graphic_attributes(style, &block)
13
+ graphic_attributes = {
14
+ stroke: style['border-color'],
15
+ stroke_width: style['border-width'],
16
+ stroke_type: style['border-style'],
17
+ fill: style['fill-color']
18
+ }
19
+ block.call(graphic_attributes) if block_given?
20
+ graphic_attributes
21
+ end
22
+
23
+ # @param [Hash] style
24
+ # @yield [attrs]
25
+ # @yieldparam [Hash] attrs
26
+ # @return [Hash]
27
+ def build_text_attributes(style, &block)
28
+ text_attributes = {
29
+ font: font_family(style['font-family']),
30
+ size: style['font-size'],
31
+ color: style['color'],
32
+ align: text_align(style['text-align']),
33
+ valign: text_valign(style['vertical-align']),
34
+ styles: font_styles(style['font-style']),
35
+ letter_spacing: letter_spacing(style['letter-spacing']),
36
+ line_height: line_height(style['line-height']),
37
+ overflow: text_overflow(style['overflow']),
38
+ word_wrap: word_wrap(style['word-wrap'])
39
+ }
40
+ block.call(text_attributes) if block_given?
41
+ text_attributes
42
+ end
43
+
44
+ # @param [Array<String>] font_names
45
+ # @return [String]
46
+ def font_family(font_names)
47
+ font_name = font_names.first
48
+ default_family_if_missing(font_name)
49
+ end
50
+
51
+ # @param [Array<String>] styles
52
+ # @return [Array<Symbol>]
53
+ def font_styles(styles)
54
+ styles.map do |font_style|
55
+ case font_style
56
+ when 'bold' then :bold
57
+ when 'italic' then :italic
58
+ when 'underline' then :underline
59
+ when 'linethrough' then :strikethrough
60
+ end
61
+ end
62
+ end
63
+
64
+ # @param [Float, "", nil] spacing
65
+ # @return [Float, nil]
66
+ def letter_spacing(spacing)
67
+ blank_value?(spacing) ? nil : spacing
68
+ end
69
+
70
+ # @param ["left", "center", "right", ""] align
71
+ # @return [:left, :center, :right]
72
+ def text_align(align)
73
+ case align
74
+ when 'left' then :left
75
+ when 'center' then :center
76
+ when 'right' then :right
77
+ when '' then :left
78
+ else :left
79
+ end
80
+ end
81
+
82
+ # @param ["top", "middle", "bottom", "", nil] valign
83
+ # @return [:top, :center, :bottom]
84
+ def text_valign(valign)
85
+ case valign
86
+ when 'top' then :top
87
+ when 'middle' then :center
88
+ when 'bottom' then :bottom
89
+ when '' then :top
90
+ else :top
91
+ end
92
+ end
93
+
94
+ # @param ["truncate", "fit", "expand", "", nil] overflow
95
+ # @return [:truncate, :shrink_to_fit, :expand]
96
+ def text_overflow(overflow)
97
+ case overflow
98
+ when 'truncate' then :truncate
99
+ when 'fit' then :shrink_to_fit
100
+ when 'expand' then :expand
101
+ when '' then :truncate
102
+ else :truncate
103
+ end
104
+ end
105
+
106
+ # @param ["break-word", "none", "", nil] word_wrap
107
+ # @return [:break_word, :none]
108
+ def word_wrap(word_wrap)
109
+ case word_wrap
110
+ when 'break-word' then :break_word
111
+ when 'none' then :none
112
+ else :none
113
+ end
114
+ end
115
+
116
+ # @param [Float, "", nil] height
117
+ # @return [Float, nil]
118
+ def line_height(height)
119
+ blank_value?(height) ? nil : height
120
+ end
121
+
122
+ # @param ["left", "center", "right", ""] position
123
+ # @return [:left, :center, :right]
124
+ def image_position_x(position)
125
+ case position
126
+ when 'left' then :left
127
+ when 'center' then :center
128
+ when 'right' then :right
129
+ when '' then :left
130
+ else :left
131
+ end
132
+ end
133
+
134
+ # @param ["top", "middle", "bottom", ""] position
135
+ # @return [:left, :center, :right]
136
+ def image_position_y(position)
137
+ case position
138
+ when 'top' then :top
139
+ when 'middle' then :center
140
+ when 'bottom' then :bottom
141
+ when '' then :top
142
+ else :top
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end