hexapdf-extras 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ea614bc7163af0c86933d2861f6c55fbab0e7a95cb799fd28167823db3f5b476
4
+ data.tar.gz: 2ae5cc1c597b8d6040c3a0f0803328692dad49cc011faf2e903e95758ee35260
5
+ SHA512:
6
+ metadata.gz: e8dc9518929b83e6ca2248fce24d1d0123b328af01e92c5f8831c3cf1ecd47655b640529ca8027aa6705c317e6875a54d701dbbbc3be17a9f0478cf3dc7dc0d3
7
+ data.tar.gz: 9266e72303a8c0a13608e24f74c6e5e47528e3875a198e5cdd1d6ded55dd0131978247b8646645e34019e4764396f5a512f4eb3ffd96d1b0f130723c08293eaf
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ hexapdf-extra - Additional functionality for HexaPDF
2
+ Copyright (C) 2022 Thomas Leitner <t_leitner@gmx.at>
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a
5
+ copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included
13
+ in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,38 @@
1
+ == HexaPDF Extras
2
+
3
+ This library contains additional functionality that is not provided by the main
4
+ {HexaPDF}[https://hexapdf.gettalong.org] library.
5
+
6
+ To use it, just <tt>require 'hexapdf-extras'</tt> and it will update the HexaPDF configuration
7
+ settings to make the various extensions available.
8
+
9
+ Note that you need to install the dependencies of the features you use yourself as they are not
10
+ listed in the gem file!
11
+
12
+ === QR code Generator
13
+
14
+ This extension plugs into the graphic objects and boxes system of HexaPDF and allows one to easily
15
+ create a fully-scalable QR code:
16
+
17
+ require 'hexapdf'
18
+ require 'hexapdf-extras'
19
+
20
+ doc = HexaPDF::Document.new
21
+ canvas = doc.pages.add.canvas
22
+ canvas.draw(:qrcode, at: [100, 100], size: 200, data: "https://hexapdf.gettalong.org")
23
+ doc.write('qrcode.pdf')
24
+
25
+ Underneath the +rqrcode_core+ library is used for actually generating the QR code. This means you
26
+ need to install that library for this extension to work.
27
+
28
+ The +data+ argument can be any data that +rqrcode_core+ understands. The other options understood by
29
+ +rqrcode_core+ are also supported.
30
+
31
+ See
32
+ {HexaPDF::Extras::GraphicObject::QRCode}[https://hexapdf-extras.gettalong.org/api/HexaPDF/Extras/GraphicObject/QRCode.html]
33
+ and
34
+ {HexaPDF::Extras::Layout::QRCodeBox}[https://hexapdf-extras.gettalong.org/api/HexaPDF/Extras/Layout/QRCodeBox.html]
35
+ for details.
36
+
37
+ Note: There was a {bug in poppler}[https://gitlab.freedesktop.org/poppler/poppler/-/issues/1281]
38
+ (already fixed) which leads to invalid rendering in Okular (as of 2022-08-06).
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ require 'rake/clean'
2
+ require 'rake/testtask'
3
+ require 'rubygems/package_task'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'test'
7
+ t.test_files = FileList['test/**/*.rb']
8
+ t.verbose = false
9
+ t.warning = true
10
+ end
11
+
12
+ CLOBBER << 'webgen-out'
13
+ CLOBBER << 'webgen-tmp'
14
+
15
+ task default: 'test'
16
+
17
+ spec = eval(File.read('hexapdf-extras.gemspec'), binding, 'hexapdf-extras.gemspec')
18
+ Gem::PackageTask.new(spec) do |pkg|
19
+ pkg.need_zip = true
20
+ pkg.need_tar = true
21
+ end
22
+
23
+ desc "Upload the release to Rubygems"
24
+ task publish_files: [:package] do
25
+ sh "gem push pkg/hexapdf-extras-#{HexaPDF::Extras::VERSION}.gem"
26
+ puts 'done'
27
+ end
28
+
29
+ task :test_all do
30
+ versions = `rbenv versions --bare | grep -i 2.[67]\\\\\\|3.`.split("\n")
31
+ versions.each do |version|
32
+ sh "eval \"$(rbenv init -)\"; rbenv shell #{version} && ruby -v && rake test"
33
+ end
34
+ puts "Looks okay? (enter to continue, Ctrl-c to abort)"
35
+ $stdin.gets
36
+ end
37
+
38
+ desc "Release HexaPDF Extras version #{HexaPDF::Extras::VERSION}"
39
+ task release: [:clobber, :test_all, :package, :publish_files]
40
+
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rqrcode_core'
4
+
5
+ module HexaPDF
6
+ module Extras
7
+ module GraphicObject
8
+
9
+ # Generates a QR code and renders it using simple PDF canvas graphics.
10
+ #
11
+ # It implements the {HexaPDF graphic object
12
+ # interface}[https://hexapdf.gettalong.org/documentation/reference/api/HexaPDF/Content/GraphicObject/index.html]
13
+ # and can therefore easily be used via the +:qrcode+ name:
14
+ #
15
+ # #>pdf-canvas100
16
+ # canvas.draw(:qrcode, data: 'hello', size: 100)
17
+ #
18
+ # This class relies on {rqrcode_core}[https://github.com/whomwah/rqrcode_core/] to generate
19
+ # the QR code from the given data. All options of rqrcode_core are supported, have a look at
20
+ # their documentation to see the allowed values.
21
+ class QRCode
22
+
23
+ # Creates and configures a new QRCode drawing support object.
24
+ #
25
+ # See #configure for the allowed keyword arguments.
26
+ def self.configure(**kwargs)
27
+ new.configure(**kwargs)
28
+ end
29
+
30
+ # The position of the bottom-left corner of the QR code.
31
+ #
32
+ # Default: [0, 0].
33
+ #
34
+ # Examples:
35
+ #
36
+ # #>pdf-canvas100
37
+ # canvas.draw(:qrcode, data: 'test', size: 30)
38
+ # canvas.draw(:qrcode, data: 'test', size: 20, at: [50, 50])
39
+ attr_accessor :at
40
+
41
+ # The size of the whole rendered QR code.
42
+ #
43
+ # Default: none
44
+ #
45
+ # Examples:
46
+ #
47
+ # #>pdf-canvas100
48
+ # canvas.draw(:qrcode, data: 'test', size: 80, at: [10, 10])
49
+ attr_accessor :size
50
+
51
+ # The color for the dark QR code modules ('pixels')
52
+ #
53
+ # Default: 'black'.
54
+ #
55
+ # Examples:
56
+ #
57
+ # #>pdf-canvas100
58
+ # canvas.draw(:qrcode, data: 'test', size: 100, dark_color: 'green')
59
+ attr_accessor :dark_color
60
+
61
+ # The color for the light QR code modules ('pixels').
62
+ #
63
+ # Default: none (i.e. they are not drawn).
64
+ #
65
+ # Examples:
66
+ #
67
+ # #>pdf-canvas100
68
+ # canvas.draw(:qrcode, data: 'test', size: 100, light_color: 'yellow')
69
+ attr_accessor :light_color
70
+
71
+ # The data for which the QR code should be generated.
72
+ #
73
+ # This is directly passed to rqrcode_core as the +data+ argument.
74
+ #
75
+ # Default: none
76
+ attr_accessor :data
77
+
78
+ # The code size of the the QR code (normally called 'version').
79
+ #
80
+ # This is directly passed to rqrcode_core as the +size+ argument.
81
+ #
82
+ # Default: nil (i.e. let rqrcode_core decide)
83
+ #
84
+ # Examples:
85
+ #
86
+ # #>pdf-canvas100
87
+ # canvas.draw(:qrcode, data: 'test', size: 100, code_size: 10)
88
+ attr_accessor :code_size
89
+
90
+ # The maximum code size of the QR code.
91
+ #
92
+ # This is directly passed to rqrcode_core as the +max_size+ argument.
93
+ #
94
+ # Default: nil (i.e. let rqrcode_core decide)
95
+ #
96
+ # Examples:
97
+ #
98
+ # #>pdf-canvas100
99
+ # canvas.draw(:qrcode, data: 't'*100, size: 100, max_code_size: 10)
100
+ attr_accessor :max_code_size
101
+
102
+ # The error correction level of the QR code.
103
+ #
104
+ # This is directly passed to rqrcode_core as the +level+ argument.
105
+ #
106
+ # Default: nil (i.e. let rqrcode_core decide)
107
+ #
108
+ # Examples:
109
+ #
110
+ # #>pdf-canvas100
111
+ # canvas.draw(:qrcode, data: 'test', size: 100, level: :l)
112
+ attr_accessor :level
113
+
114
+ # The mode of the QR code, i.e. which data it holds.
115
+ #
116
+ # This is directly passed to rqrcode_core as the +mode+ argument.
117
+ #
118
+ # Default: nil (i.e. let rqrcode_core decide)
119
+ #
120
+ # Examples:
121
+ #
122
+ # #>pdf-canvas100
123
+ # canvas.draw(:qrcode, data: 'test', size: 100, mode: :kanji)
124
+ attr_accessor :mode
125
+
126
+ # Creates a QRCode object.
127
+ def initialize
128
+ @data = @size = @code_size = @max_code_size = @level = @mode = nil
129
+ @at = [0, 0]
130
+ @dark_color = 'black'
131
+ @light_color = nil
132
+ end
133
+
134
+ # Configures the QRCode object and returns self.
135
+ #
136
+ # The following arguments are allowed:
137
+ #
138
+ # :at:: The position of the bottom-left corner.
139
+ # :size:: The size of the whole rendered QR code.
140
+ # :dark_color:: The color used for the dark QR code modules ('pixels').
141
+ # :light_color:: The color used for the light QR code modules ('pixels').
142
+ # :data:: The data for the QR code.
143
+ # :code_size:: The code size of the QR code.
144
+ # :max_code_size:: The maximum code size of the QR code.
145
+ # :level:: The error correction level of the QR code
146
+ # :mode:: The mode of the of the QR code.
147
+ #
148
+ # Any arguments not specified are not modified and retain their old value, see the attribute
149
+ # methods for the inital default values.
150
+ def configure(at: nil, size: nil, dark_color: nil, light_color: nil,
151
+ data: nil, code_size: nil, max_code_size: nil, level: nil, mode: nil)
152
+ @at = at if at
153
+ @size = size if size
154
+ @dark_color = dark_color if dark_color
155
+ @light_color = light_color if light_color
156
+ @data = data if data
157
+ @code_size = code_size if code_size
158
+ @max_code_size = max_code_size if max_code_size
159
+ @level = level if level
160
+ @mode = mode if mode
161
+ self
162
+ end
163
+
164
+ # Draws the QRCode object onto the given Canvas, with the bottom-left corner at the position
165
+ # specified by #at and the size specified by #size.
166
+ def draw(canvas)
167
+ qrcode = RQRCodeCore::QRCode.new(data, size: code_size, max_size: max_code_size,
168
+ level: level, mode: mode)
169
+
170
+ canvas.save_graphics_state do
171
+ canvas.translate(*at)
172
+ canvas.fill_color(light_color).rectangle(0, 0, size, size).fill if light_color
173
+
174
+ module_count = qrcode.modules.size
175
+ module_size = size.to_f / module_count
176
+ y_start = size - module_size / 2
177
+ canvas.line_cap_style(:butt)
178
+ canvas.line_width(module_size)
179
+ canvas.stroke_color(dark_color)
180
+
181
+ qrcode.modules.each_with_index do |row, row_index|
182
+ pattern = [0]
183
+ last_is_dark = row[0]
184
+ row.each do |col|
185
+ if col == last_is_dark
186
+ pattern[-1] += module_size
187
+ else
188
+ last_is_dark = !last_is_dark
189
+ pattern << module_size
190
+ end
191
+ end
192
+ pattern.unshift(0) unless row[0]
193
+
194
+ canvas.line_dash_pattern(pattern)
195
+ canvas.line(0, y_start - module_size * row_index,
196
+ size, y_start - module_size * row_index).
197
+ stroke
198
+ end
199
+ end
200
+ end
201
+
202
+ end
203
+
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HexaPDF
4
+ module Extras
5
+ module GraphicObject
6
+ autoload(:QRCode, 'hexapdf/extras/graphic_object/qr_code')
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'hexapdf/layout/box'
4
+
5
+ module HexaPDF
6
+ module Extras
7
+ module Layout
8
+
9
+ # A QRCodeBox object is used for displaying a QR code.
10
+ #
11
+ # The size of the QR code is determined by the width and height of the box (to be exact: by
12
+ # the smaller of the two values). The QR code is always placed at the top left corner of the
13
+ # box.
14
+ #
15
+ # Internally, HexaPDF::Extras::GraphicObject::QRCode is used, so any option except +at+ and
16
+ # +size+ supported there can be used here.
17
+ #
18
+ # Example:
19
+ #
20
+ # #>pdf-composer100
21
+ # composer.box(:qrcode, height: 50, data: 'Test', style: {position: :float})
22
+ # composer.box(:qrcode, width: 20, data: 'Test', dark_color: 'red', style: {position: :float})
23
+ # composer.box(:qrcode, width: 30, height: 50, data: 'Test', dark_color: 'green',
24
+ # style: {position: :float})
25
+ # composer.box(:qrcode, data: 'Test', dark_color: 'blue')
26
+ class QRCodeBox < HexaPDF::Layout::Box
27
+
28
+ # The HexaPDF::Extras::GraphicObject::QRCode object that will be drawn.
29
+ attr_reader :qr_code
30
+
31
+ # Creates a new QRCodeBox object with the given arguments (see
32
+ # HexaPDF::Extras::GraphicObject::QRCode for details).
33
+ #
34
+ # At least +data+ needs to be specified.
35
+ def initialize(dark_color: nil, light_color: nil, data: nil, code_size: nil,
36
+ max_code_size: nil, level: nil, mode: nil, **kwargs)
37
+ super(**kwargs)
38
+ @qr_code = HexaPDF::Extras::GraphicObject::QRCode.configure(
39
+ dark_color: dark_color, light_color: light_color, data: data, code_size: code_size,
40
+ max_code_size: max_code_size, level: level, mode: mode
41
+ )
42
+ end
43
+
44
+ # Fits the QRCode into the given area.
45
+ def fit(available_width, available_height, _frame)
46
+ super
47
+ @width = @height = [@width, @height].min
48
+ @qr_code.size = [content_width, content_height].min
49
+ @fit_successful = (@width <= available_width && @height <= available_height)
50
+ end
51
+
52
+ private
53
+
54
+ # Draws the QR code onto the canvas at position [x, y].
55
+ def draw_content(canvas, x, y)
56
+ @qr_code.at = [x, y]
57
+ canvas.draw(@qr_code)
58
+ end
59
+
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HexaPDF
4
+ module Extras
5
+ module Layout
6
+ autoload(:QRCodeBox, 'hexapdf/extras/layout/qr_code_box')
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HexaPDF
4
+ module Extras
5
+ VERSION = '1.0.0'
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'hexapdf/configuration'
4
+
5
+ module HexaPDF
6
+ module Extras
7
+ autoload(:GraphicObject, 'hexapdf/extras/graphic_object')
8
+ autoload(:Layout, 'hexapdf/extras/layout')
9
+ end
10
+ end
11
+
12
+ HexaPDF::DefaultDocumentConfiguration['graphic_object.map'][:qrcode] =
13
+ 'HexaPDF::Extras::GraphicObject::QRCode'
14
+
15
+ HexaPDF::DefaultDocumentConfiguration['layout.boxes.map'][:qrcode] =
16
+ 'HexaPDF::Extras::Layout::QRCodeBox'
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'hexapdf/extras'
@@ -0,0 +1,107 @@
1
+ require 'test_helper'
2
+ require 'hexapdf'
3
+ require 'hexapdf/extras/graphic_object/qr_code'
4
+
5
+ describe HexaPDF::Extras::GraphicObject::QRCode do
6
+ before do
7
+ @obj = HexaPDF::Extras::GraphicObject::QRCode.new
8
+ end
9
+
10
+ it "allows creation via the ::configure method" do
11
+ obj = HexaPDF::Extras::GraphicObject::QRCode.configure(data: 'test')
12
+ assert_equal('test', obj.data)
13
+ end
14
+
15
+ it "creates a default Geom2D drawing support object" do
16
+ [:size, :light_color, :data, :code_size, :max_code_size, :level, :mode].each do |method_name|
17
+ assert_nil(@obj.send(method_name))
18
+ end
19
+ assert_equal([0, 0], @obj.at)
20
+ assert_equal('black', @obj.dark_color)
21
+ end
22
+
23
+ it "allows configuration of the object" do
24
+ @obj.configure(data: 'test', size: 30)
25
+ assert_equal('test', @obj.data)
26
+ assert_equal(30, @obj.size)
27
+ end
28
+
29
+ describe "draw" do
30
+ before do
31
+ doc = HexaPDF::Document.new
32
+ @canvas = doc.pages.add.canvas
33
+ end
34
+
35
+ it "draws a QRCode onto the canvas" do
36
+ @obj.configure(data: 'test', size: 210)
37
+ @obj.draw(@canvas)
38
+ assert_operators(@canvas.contents,
39
+ [[:save_graphics_state],
40
+ [:concatenate_matrix, [1, 0, 0, 1, 0, 0]],
41
+ [:set_line_width, [10]],
42
+ [:set_device_rgb_stroking_color, [0, 0, 0]],
43
+ [:set_line_dash_pattern, [[70, 10, 30, 10, 10, 10, 70], 0]],
44
+ [:move_to, [0, 205]], [:line_to, [210, 205]], [:stroke_path],
45
+ [:set_line_dash_pattern,
46
+ [[10, 50, 10, 10, 20, 40, 10, 50, 10], 0]],
47
+ [:move_to, [0, 195]], [:line_to, [210, 195]], [:stroke_path],
48
+ [:set_line_dash_pattern,
49
+ [[10, 10, 30, 10, 10, 30, 20, 20, 10, 10, 30, 10, 10], 0]],
50
+ [:move_to, [0, 185]], [:line_to, [210, 185]], [:stroke_path],
51
+ [:set_line_dash_pattern,
52
+ [[10, 10, 30, 10, 10, 10, 10, 20, 20, 10, 10, 10, 30, 10, 10], 0]],
53
+ [:move_to, [0, 175]], [:line_to, [210, 175]], [:stroke_path],
54
+ [:set_line_dash_pattern,
55
+ [[10, 10, 30, 10, 10, 10, 10, 20, 10, 20, 10, 10, 30, 10, 10], 0]],
56
+ [:move_to, [0, 165]], [:line_to, [210, 165]], [:stroke_path],
57
+ [:set_line_dash_pattern,
58
+ [[10, 50, 10, 10, 20, 40, 10, 50, 10], 0]],
59
+ [:move_to, [0, 155]], [:line_to, [210, 155]], [:stroke_path],
60
+ [:set_line_dash_pattern,
61
+ [[70, 10, 10, 10, 10, 10, 10, 10, 70], 0]],
62
+ [:move_to, [0, 145]], [:line_to, [210, 145]], [:stroke_path],
63
+ [:set_line_dash_pattern, [[0, 90, 20, 10, 10, 80], 0]],
64
+ [:move_to, [0, 135]], [:line_to, [210, 135]], [:stroke_path],
65
+ [:set_line_dash_pattern,
66
+ [[0, 30, 10, 20, 10, 20, 10, 10, 10, 30, 30, 10, 20], 0]],
67
+ [:move_to, [0, 125]], [:line_to, [210, 125]], [:stroke_path],
68
+ [:set_line_dash_pattern,
69
+ [[0, 30, 20, 20, 20, 30, 10, 10, 20, 30, 20], 0]],
70
+ [:move_to, [0, 115]], [:line_to, [210, 115]], [:stroke_path],
71
+ [:set_line_dash_pattern,
72
+ [[10, 10, 20, 20, 30, 10, 10, 10, 10, 10, 50, 10, 10], 0]],
73
+ [:move_to, [0, 105]], [:line_to, [210, 105]], [:stroke_path],
74
+ [:set_line_dash_pattern,
75
+ [[20, 10, 10, 50, 10, 20, 10, 10, 40, 10, 20], 0]],
76
+ [:move_to, [0, 95]], [:line_to, [210, 95]], [:stroke_path],
77
+ [:set_line_dash_pattern,
78
+ [[20, 30, 20, 10, 30, 40, 10, 10, 10, 10, 20], 0]],
79
+ [:move_to, [0, 85]], [:line_to, [210, 85]], [:stroke_path],
80
+ [:set_line_dash_pattern,
81
+ [[0, 80, 10, 20, 30, 20, 20, 10, 20], 0]],
82
+ [:move_to, [0, 75]], [:line_to, [210, 75]], [:stroke_path],
83
+ [:set_line_dash_pattern,
84
+ [[70, 20, 30, 20, 10, 10, 10, 20, 10, 10], 0]],
85
+ [:move_to, [0, 65]], [:line_to, [210, 65]], [:stroke_path],
86
+ [:set_line_dash_pattern,
87
+ [[10, 50, 10, 20, 20, 10, 10, 10, 10, 40, 10, 10], 0]],
88
+ [:move_to, [0, 55]], [:line_to, [210, 55]], [:stroke_path],
89
+ [:set_line_dash_pattern,
90
+ [[10, 10, 30, 10, 10, 40, 10, 10, 20, 20, 10, 20, 10], 0]],
91
+ [:move_to, [0, 45]], [:line_to, [210, 45]], [:stroke_path],
92
+ [:set_line_dash_pattern,
93
+ [[10, 10, 30, 10, 10, 10, 20, 10, 10, 30, 10, 10, 10, 10, 20], 0]],
94
+ [:move_to, [0, 35]], [:line_to, [210, 35]], [:stroke_path],
95
+ [:set_line_dash_pattern,
96
+ [[10, 10, 30, 10, 10, 50, 20, 10, 10, 20, 10, 10, 10], 0]],
97
+ [:move_to, [0, 25]], [:line_to, [210, 25]], [:stroke_path],
98
+ [:set_line_dash_pattern,
99
+ [[10, 50, 10, 20, 10, 10, 10, 20, 20, 10, 10, 30], 0]],
100
+ [:move_to, [0, 15]], [:line_to, [210, 15]], [:stroke_path],
101
+ [:set_line_dash_pattern,
102
+ [[70, 30, 20, 10, 10, 10, 10, 10, 30, 10], 0]],
103
+ [:move_to, [0, 5]], [:line_to, [210, 5]], [:stroke_path],
104
+ [:restore_graphics_state]])
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,71 @@
1
+ require 'test_helper'
2
+ require 'hexapdf'
3
+ require 'hexapdf/extras/layout/qr_code_box'
4
+
5
+ describe HexaPDF::Extras::Layout::QRCodeBox do
6
+ def create_box(**kwargs)
7
+ HexaPDF::Extras::Layout::QRCodeBox.new(**kwargs)
8
+ end
9
+
10
+ describe "initialize" do
11
+ it "can take the common box arguments" do
12
+ box = create_box(width: 10, height: 15)
13
+ assert_equal(10, box.width)
14
+ assert_equal(15, box.height)
15
+ end
16
+
17
+ it "creates the QRCode graphic object" do
18
+ box = create_box(data: 'test', level: :l)
19
+ assert_equal(:l, box.qr_code.level)
20
+ assert_equal('test', box.qr_code.data)
21
+ end
22
+ end
23
+
24
+ describe "fit" do
25
+ it "uses the smaller value of width/height for the dimensions if smaller than available_width/height" do
26
+ [{width: 10}, {width: 10, height: 50}, {height: 10}, {width: 50, height: 10}].each do |args|
27
+ box = create_box(**args)
28
+ assert(box.fit(100, 100, nil))
29
+ assert_equal(10, box.width)
30
+ assert_equal(10, box.height)
31
+ assert_equal(10, box.qr_code.size)
32
+ end
33
+ end
34
+
35
+ it "uses the smaller value of available_width/height for the dimensions" do
36
+ box = create_box
37
+ assert(box.fit(10, 20, nil))
38
+ assert_equal(10, box.width)
39
+ assert_equal(10, box.height)
40
+ assert_equal(10, box.qr_code.size)
41
+
42
+ assert(box.fit(20, 15, nil))
43
+ assert_equal(15, box.width)
44
+ assert_equal(15, box.height)
45
+ assert_equal(15, box.qr_code.size)
46
+ end
47
+
48
+ it "takes the border and padding into account for the QR code size" do
49
+ box = create_box(style: {padding: [1, 2], border: {width: [3, 4]}})
50
+ assert(box.fit(100, 100, nil))
51
+ assert_equal(88, box.qr_code.size)
52
+
53
+ box = create_box(style: {padding: [2, 1], border: {width: [4, 3]}})
54
+ assert(box.fit(100, 100, nil))
55
+ assert_equal(88, box.qr_code.size)
56
+ end
57
+ end
58
+
59
+ describe "draw" do
60
+ it "draws the qrcode" do
61
+ box = create_box(width: 10)
62
+ box.fit(100, 100, nil)
63
+
64
+ canvas = Minitest::Mock.new
65
+ canvas.expect(:draw, nil, [box.qr_code])
66
+ box.draw(canvas, 5, 7)
67
+ assert_equal([5, 7], box.qr_code.at)
68
+ canvas.verify
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,17 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ begin
4
+ require 'simplecov'
5
+ SimpleCov.start do
6
+ minimum_coverage line: 100
7
+ add_filter '/test/'
8
+ end
9
+ rescue LoadError
10
+ puts "No code coverage because simplecov is not installed"
11
+ end
12
+
13
+ gem 'minitest'
14
+ require 'minitest/autorun'
15
+ require 'hexapdf/test_utils'
16
+
17
+ Minitest::Test.make_my_diffs_pretty!
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hexapdf-extras
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Thomas Leitner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-08-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: hexapdf
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.24'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.24'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rqrcode_core
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.2'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.2'
41
+ description:
42
+ email: t_leitner@gmx.at
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - LICENSE
48
+ - README.rdoc
49
+ - Rakefile
50
+ - lib/hexapdf-extras.rb
51
+ - lib/hexapdf/extras.rb
52
+ - lib/hexapdf/extras/graphic_object.rb
53
+ - lib/hexapdf/extras/graphic_object/qr_code.rb
54
+ - lib/hexapdf/extras/layout.rb
55
+ - lib/hexapdf/extras/layout/qr_code_box.rb
56
+ - lib/hexapdf/extras/version.rb
57
+ - test/hexapdf/extras/graphic_object/test_qr_code.rb
58
+ - test/hexapdf/extras/layout/test_qr_code_box.rb
59
+ - test/test_helper.rb
60
+ homepage: https://hexapdf-extras.gettalong.org
61
+ licenses:
62
+ - MIT
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '2.5'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubygems_version: 3.1.6
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: Additional functionality for HexaPDF
83
+ test_files: []