rqrcode 1.2.0 → 2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d8b2f0f6e33a545c3f0e5414b53eb5cffdc99138238d06118fbfec70d968c2e
4
- data.tar.gz: 05df172d996fde577a4ce32504f243cd7d8feb440d70167d633c03956fa8d6e6
3
+ metadata.gz: 9dad1e83dc97d564e2ec828cb8ba389c222fa4ae7662d6feaaed36fbfea194ba
4
+ data.tar.gz: e3d901e23ba8dfb7cc6b300ae47bc11dcbc6913d2fce1a66824bffa670ca5cf5
5
5
  SHA512:
6
- metadata.gz: 73398ff5d4c89b362c850b6a293dace00e415738ec9944f4471d0d473dbbb7e0f8a9adec5026167a51535b619950487a556c126919045d1b289e949b82f2e171
7
- data.tar.gz: 80c7718c260969fa52138620cd547d9c8564f9610dc951b1d06f4f4a2e20ac6979fca861b4ad6de22ef07e18daca15b86b187c5c963f47edeba24c99aa3fed5d
6
+ metadata.gz: 317ff35bc49042e5a7a0d9390c82051b9552bd5d2a4c7a56e99e2ea75e7d2d4cf9071516f1fb800e5fd1af3c964976c6354db675c33928a0fee99f54cf588a7c
7
+ data.tar.gz: 167fc518c536b3bf32699dc09952fc5068db81d44040b0b768a4a220186438076992a8a3deb5eb85537c651d1d47ddabe7d4b2a29fbc490027a157b8265e3f77
@@ -4,28 +4,25 @@ on:
4
4
  push:
5
5
  branches:
6
6
  - master
7
- - release/*
8
7
  pull_request:
9
8
  branches:
10
9
  - master
11
10
 
12
11
  jobs:
13
- build:
14
- name: Test Ruby ${{ matrix.ruby_version }} on ${{ matrix.os }}
15
- runs-on: ${{ matrix.os }}
12
+ Build:
16
13
  strategy:
14
+ fail-fast: false
17
15
  matrix:
18
- ruby_version: [2.5.x, 2.6.x]
19
- os: [ubuntu-latest]
20
-
16
+ os: [ubuntu-latest, macos-latest]
17
+ ruby: [2.5, 2.6, 2.7, 3.0]
18
+ runs-on: ${{ matrix.os }}
21
19
  steps:
22
20
  - uses: actions/checkout@v1
23
- - name: Use Ruby ${{ matrix.ruby_version }}
24
- uses: actions/setup-ruby@v1
21
+ - uses: ruby/setup-ruby@v1
25
22
  with:
26
- ruby-version: ${{ matrix.ruby_version }}
27
- - name: Gem install and test
28
- run: |
29
- gem install bundler
30
- bundle install --jobs 4 --retry 3
31
- bundle exec rspec
23
+ ruby-version: ${{ matrix.ruby }}
24
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
25
+ - name: Run Tests for Ruby ${{ matrix.ruby }} on ${{ matrix.os }}
26
+ run: bundle exec rake spec
27
+ - name: StandardRB check for Ruby ${{ matrix.ruby }} on ${{ matrix.os }}
28
+ run: bundle exec standardrb --format progress
data/.gitignore CHANGED
@@ -10,4 +10,4 @@
10
10
  .rvmrc
11
11
  *.sublime-project
12
12
  *.sublime-workspace
13
- Gemfile.lock
13
+ *.gem
data/CHANGELOG.md ADDED
@@ -0,0 +1,39 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [2.0.0] - 2021-05-06
11
+
12
+ ### Added
13
+
14
+ - A new `use_path:` option on `.to_svg`. This uses a `<path>` node to greatly reduce the final SVG size. [#108]
15
+ - A new `viewbox:` option on `.to_svg`. Replaces the `svg.width` and `svg.height` attribute with `svg.viewBox` to allow CSS scaling. [#112]
16
+ - A new `svg_attributes:` option on `.to_svg`. Allows you to pass in custom SVG attributes to be used in the `<svg>` tag. [#113]
17
+
18
+ ### Changed
19
+
20
+ - README updated
21
+ - Rakefile cleaned up. You can now just run `rake` which will run specs and fix linting using `standardrb`
22
+ - Small documentation clarification [@smnscp](https://github.com/smnscp)
23
+ - Bump `rqrcode_core` to `~> 1.0`
24
+
25
+ ### Breaking Change
26
+
27
+ - The dependency `rqrcode_core-1.0.0` has a tiny breaking change to the `to_s` public method. https://github.com/whomwah/rqrcode_core/blob/master/CHANGELOG.md#breaking-changes
28
+
29
+ ## [1.2.0] - 2020-12-26
30
+
31
+ ### Changed
32
+
33
+ - README updated
34
+ - bump dependencies
35
+ - fix `required_ruby_version` for Ruby 3 support
36
+
37
+ [unreleased]: https://github.com/whomwah/rqrcode/compare/v2.0.0...HEAD
38
+ [2.0.0]: https://github.com/whomwah/rqrcode/compare/v1.2.0...v2.0.0
39
+ [1.2.0]: https://github.com/whomwah/rqrcode/compare/v1.1.1...v1.2.0
data/Gemfile.lock ADDED
@@ -0,0 +1,68 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rqrcode (2.0.0)
5
+ chunky_png (~> 1.0)
6
+ rqrcode_core (~> 1.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ ast (2.4.2)
12
+ chunky_png (1.4.0)
13
+ diff-lcs (1.4.4)
14
+ parallel (1.20.1)
15
+ parser (3.0.1.0)
16
+ ast (~> 2.4.1)
17
+ rainbow (3.0.0)
18
+ rake (13.0.3)
19
+ regexp_parser (2.1.1)
20
+ rexml (3.2.5)
21
+ rqrcode_core (1.0.0)
22
+ rspec (3.10.0)
23
+ rspec-core (~> 3.10.0)
24
+ rspec-expectations (~> 3.10.0)
25
+ rspec-mocks (~> 3.10.0)
26
+ rspec-core (3.10.1)
27
+ rspec-support (~> 3.10.0)
28
+ rspec-expectations (3.10.1)
29
+ diff-lcs (>= 1.2.0, < 2.0)
30
+ rspec-support (~> 3.10.0)
31
+ rspec-mocks (3.10.2)
32
+ diff-lcs (>= 1.2.0, < 2.0)
33
+ rspec-support (~> 3.10.0)
34
+ rspec-support (3.10.2)
35
+ rubocop (1.12.1)
36
+ parallel (~> 1.10)
37
+ parser (>= 3.0.0.0)
38
+ rainbow (>= 2.2.2, < 4.0)
39
+ regexp_parser (>= 1.8, < 3.0)
40
+ rexml
41
+ rubocop-ast (>= 1.2.0, < 2.0)
42
+ ruby-progressbar (~> 1.7)
43
+ unicode-display_width (>= 1.4.0, < 3.0)
44
+ rubocop-ast (1.4.1)
45
+ parser (>= 2.7.1.5)
46
+ rubocop-performance (1.10.1)
47
+ rubocop (>= 0.90.0, < 2.0)
48
+ rubocop-ast (>= 0.4.0)
49
+ ruby-progressbar (1.11.0)
50
+ standard (1.0.5)
51
+ rubocop (= 1.12.1)
52
+ rubocop-performance (= 1.10.1)
53
+ standardrb (1.0.0)
54
+ standard
55
+ unicode-display_width (2.0.0)
56
+
57
+ PLATFORMS
58
+ ruby
59
+
60
+ DEPENDENCIES
61
+ bundler (~> 2.0)
62
+ rake (~> 13.0)
63
+ rqrcode!
64
+ rspec (~> 3.5)
65
+ standardrb (~> 1.0)
66
+
67
+ BUNDLED WITH
68
+ 2.2.15
data/README.md CHANGED
@@ -1,20 +1,21 @@
1
1
  # RQRCode
2
2
 
3
- ![](https://github.com/whomwah/rqrcode/workflows/rqrcode/badge.svg)
3
+ ![](https://github.com/whomwah/rqrcode/actions/workflows/ruby.yml/badge.svg)
4
4
 
5
5
 
6
6
  [RQRCode](https://github.com/whomwah/rqrcode) is a library for creating and rendering QR codes into various formats. It has a simple interface with all the standard QR code options. It was adapted from the Javascript library by Kazuhiko Arase.
7
7
 
8
8
  * QR code is trademarked by Denso Wave inc
9
9
  * Minimum Ruby version is `>= 2.3`
10
- * For `rqrcode` releases `< 1.0.0` please use [this README](https://github.com/whomwah/rqrcode/blob/cd2732a68434e6197c219e6c8cbdadfce0c4c4f3/README.md)
10
+ * For `rqrcode` releases `< 2.0.0` please use [this README](https://github.com/whomwah/rqrcode/blob/v1.2.0/README.md)
11
+ * For `rqrcode` releases `< 1.0.0` please use [this README](https://github.com/whomwah/rqrcode/blob/v0.9.0/README.md)
11
12
 
12
13
  ## Installing
13
14
 
14
15
  Add this line to your application's `Gemfile`:
15
16
 
16
17
  ```ruby
17
- gem 'rqrcode'
18
+ gem "rqrcode", "~> 2.0"
18
19
  ```
19
20
 
20
21
  or install manually:
@@ -26,20 +27,19 @@ gem install rqrcode
26
27
  ## Basic usage example
27
28
 
28
29
  ```ruby
29
- require 'rqrcode'
30
+ require "rqrcode"
30
31
 
31
- qr = RQRCode::QRCode.new('http://github.com')
32
- result = ''
32
+ qr = RQRCode::QRCode.new("https://kyan.com")
33
33
 
34
- qr.qrcode.modules.each do |row|
35
- row.each do |col|
36
- result << (col ? 'X' : 'O')
37
- end
38
-
39
- result << "\n"
40
- end
34
+ puts qr.to_s
41
35
 
42
- puts result
36
+ xxxxxxx xxxxxxx xxx xxxxxxx
37
+ x x x xxx xx x x
38
+ x xxx x xx x x xx x xxx x
39
+ x xxx x xx xx xx x xxx x
40
+ x xxx x x x xxx x xxx x
41
+ x x xxx x xx x x x x
42
+ ...
43
43
  ```
44
44
 
45
45
  ### Advanced Options
@@ -49,7 +49,7 @@ These are the various QR Code generation options provided by [rqrqcode_core](htt
49
49
  ```
50
50
  string - the string you wish to encode
51
51
 
52
- size - the size of the qrcode (default 4)
52
+ size - the size (Integer) of the qrcode (defaults to smallest size needed to encode the string)
53
53
 
54
54
  level - the error correction level, can be:
55
55
  * Level :l 7% of code can be restored
@@ -72,54 +72,108 @@ qrcode = RQRCodeCore::QRCode.new('hello world', size: 1, level: :m, mode: :alpha
72
72
 
73
73
  ## Render types
74
74
 
75
- You can output your QR code in various forms. These are detailed below:
75
+ You probably want to output your QR code in a specific format. We make this easy by providing a bunch of formats to choose from below, each with their own set of options:
76
76
 
77
- ### as SVG
77
+ ### `as_svg`
78
78
 
79
79
  The SVG renderer will produce a stand-alone SVG as a `String`
80
80
 
81
+ ```
82
+ Options:
83
+
84
+ offset - Padding around the QR Code in pixels
85
+ (default 0)
86
+ fill - Background color e.g "ffffff" or :white
87
+ (default none)
88
+ color - Foreground color e.g "000" or :black
89
+ (default "000")
90
+ module_size - The Pixel size of each module
91
+ (defaults 11)
92
+ shape_rendering - SVG Attribute: auto | optimizeSpeed | crispEdges | geometricPrecision
93
+ (defaults crispEdges)
94
+ standalone - Whether to make this a full SVG file, or only an svg to embed in other svg
95
+ (default true)
96
+ use_path - Use <path> to render SVG rather than <rect> to significantly reduce size
97
+ and quality. This will become the default in future versions.
98
+ (default false)
99
+ viewbox - Replace the `svg.width` and `svg.height` attribute with `svg.viewBox` to
100
+ allow CSS scaling
101
+ (default false)
102
+ svg_attributes - A optional hash of custom <svg> attributes. Existing attributes will remain.
103
+ (default {})
104
+ ```
105
+ Example
81
106
  ```ruby
82
- require 'rqrcode'
107
+ require "rqrcode"
83
108
 
84
109
  qrcode = RQRCode::QRCode.new("http://github.com/")
85
110
 
86
111
  # NOTE: showing with default options specified explicitly
87
112
  svg = qrcode.as_svg(
88
- offset: 0,
89
- color: '000',
90
- shape_rendering: 'crispEdges',
91
- module_size: 6,
92
- standalone: true
113
+ color: "000",
114
+ shape_rendering: "crispEdges",
115
+ module_size: 11,
116
+ standalone: true,
117
+ use_path: true,
118
+ svg_attributes: {
119
+ id: "myUniqueId"
120
+ }
93
121
  )
94
122
  ```
95
123
 
96
124
  ![QR code with github url](./images/github-qrcode.svg)
97
125
 
98
- ### as ANSI
126
+ ### `as_png`
99
127
 
100
- The ANSI renderer will produce as a string with ANSI color codes.
128
+ The will produce a PNG using the [ChunkyPNG gem](https://github.com/wvanbergen/chunky_png). The result will be a `ChunkyPNG::Image` instance.
101
129
 
102
- ```ruby
103
- require 'rqrcode'
130
+ ```
131
+ Options:
104
132
 
105
- qrcode = RQRCode::QRCode.new("http://github.com/")
133
+ fill - Background ChunkyPNG::Color, defaults to 'white'
134
+ color - Foreground ChunkyPNG::Color, defaults to 'black'
106
135
 
107
- # NOTE: showing with default options specified explicitly
108
- svg = qrcode.as_ansi(
109
- light: "\033[47m", dark: "\033[40m",
110
- fill_character: ' ',
111
- quiet_zone_size: 4
112
- )
113
- ```
136
+ When option :file is supplied you can use the following ChunkyPNG constraints:
114
137
 
115
- ![QR code with github url](./images/ansi-screen-shot.png)
138
+ color_mode - The color mode to use. Use one of the ChunkyPNG::COLOR_* constants.
139
+ (defaults to 'ChunkyPNG::COLOR_GRAYSCALE')
140
+ bit_depth - The bit depth to use. This option is only used for indexed images.
141
+ (defaults to 1 bit)
142
+ interlace - Whether to use interlacing (true or false).
143
+ (defaults to ChunkyPNG default)
144
+ compression - The compression level for Zlib. This can be a value between 0 and 9, or a
145
+ Zlib constant like Zlib::BEST_COMPRESSION
146
+ (defaults to ChunkyPNG default)
147
+
148
+ There are two sizing algorithms.
149
+
150
+ * Original that can result in blurry and hard to scan images
151
+ * Google's Chart API inspired sizing that resizes the module size to fit within the given image size.
152
+
153
+ The Google one will be used when no options are given or when the new size option is used.
154
+
155
+ *Google Sizing*
116
156
 
117
- ### as PNG
157
+ size - Total size of PNG in pixels. The module size is calculated so it fits.
158
+ (defaults to 120)
159
+ border_modules - Width of white border around the modules.
160
+ (defaults to 4).
118
161
 
119
- The library can produce a PNG. Result will be a `ChunkyPNG::Image` instance.
162
+ -- DONT USE border_modules OPTION UNLESS YOU KNOW ABOUT THE QUIET ZONE NEEDS OF QR CODES --
163
+
164
+ *Original Sizing*
165
+
166
+ module_px_size - Image size, in pixels.
167
+ border - Border thickness, in pixels
168
+
169
+ It first creates an image where 1px = 1 module, then resizes.
170
+ Defaults to 120x120 pixels, customizable by option.
171
+ ```
172
+
173
+ Example
120
174
 
121
175
  ```ruby
122
- require 'rqrcode'
176
+ require "rqrcode"
123
177
 
124
178
  qrcode = RQRCode::QRCode.new("http://github.com/")
125
179
 
@@ -128,9 +182,9 @@ png = qrcode.as_png(
128
182
  bit_depth: 1,
129
183
  border_modules: 4,
130
184
  color_mode: ChunkyPNG::COLOR_GRAYSCALE,
131
- color: 'black',
185
+ color: "black",
132
186
  file: nil,
133
- fill: 'white',
187
+ fill: "white",
134
188
  module_px_size: 6,
135
189
  resize_exactly_to: false,
136
190
  resize_gte_to: false,
@@ -142,27 +196,39 @@ IO.binwrite("/tmp/github-qrcode.png", png.to_s)
142
196
 
143
197
  ![QR code with github url](./images/github-qrcode.png)
144
198
 
145
- ### On the console ( just because you can )
146
199
 
147
- ```ruby
148
- require 'rqrcode'
200
+ ### `as_ansi`
149
201
 
150
- qr = RQRCode::QRCode.new('http://kyan.com', size: 4, level: :h)
202
+ The ANSI renderer will produce as a string with ANSI color codes.
151
203
 
152
- puts qr.to_s
153
204
  ```
205
+ Options:
206
+
207
+ light - Foreground ANSI code
208
+ (default "\033[47m")
209
+ dark - Background ANSI code
210
+ (default "\033[40m")
211
+ fill_character - The written character
212
+ (default ' ')
213
+ quiet_zone_size - Padding around the edge
214
+ (default 4)
215
+ ```
216
+ Example
217
+ ```ruby
218
+ require "rqrcode"
154
219
 
155
- Output:
220
+ qrcode = RQRCode::QRCode.new("http://github.com/")
156
221
 
157
- ```
158
- xxxxxxx x x xxx xxxxxxx
159
- x x xxxxx x x x x
160
- x xxx x x x x x xxx x
161
- x xxx x xxx x xxx x xxx x
162
- x xxx x xxx x x x x xxx x
163
- ... etc
222
+ # NOTE: showing with default options specified explicitly
223
+ svg = qrcode.as_ansi(
224
+ light: "\033[47m", dark: "\033[40m",
225
+ fill_character: " ",
226
+ quiet_zone_size: 4
227
+ )
164
228
  ```
165
229
 
230
+ ![QR code with github url](./images/ansi-screen-shot.png)
231
+
166
232
  ## API Documentation
167
233
 
168
234
  [http://www.rubydoc.info/gems/rqrcode](http://www.rubydoc.info/gems/rqrcode)
@@ -173,7 +239,8 @@ You can run the test suite using:
173
239
 
174
240
  ```
175
241
  $ ./bin/setup
176
- $ bundle exec rspec
242
+ $ rake # runs specs and standard:fix
243
+ $ rake spec # just runs the specs
177
244
  ```
178
245
 
179
246
  or try the lib from the console with:
@@ -182,11 +249,30 @@ or try the lib from the console with:
182
249
  $ ./bin/console
183
250
  ```
184
251
 
252
+ ## Linting
253
+
254
+ The project uses [standardrb](https://github.com/testdouble/standard) and can be used with:
255
+
256
+ ```
257
+ $ ./bin/setup
258
+ $ rake standard # checks
259
+ $ rake standard:fix # fixes
260
+ ```
261
+
185
262
  ## Contributing
263
+
264
+ I am not currently accepting any new renderers as the current `as_png`, `as_svg` and `as_ansi` work for most cases. If you need something different from what's available, the [`rqrcode_core`](https://github.com/whomwah/rqrcode_core) gem gives you access to all the QR Code information you will need so makes it simple to generate your own.
265
+
266
+ The motivation for the above is because the rendering side of this gem takes up the most time. It seems that many people want a slightly different version of a QR Code so supporting all the variations would be hard. The easiest way is to empower people to create their own versions which they can manage and share. This is what `rqrcode_core` does.
267
+
268
+ Any contribution PR's will be greatly accepted. It's important that they are well tested and backwards compatible.
269
+
186
270
  * Fork the project
187
271
  * Send a pull request
188
272
  * Don't touch the .gemspec, I'll do that when I release a new version
189
273
 
274
+ Thanks D.
275
+
190
276
  ## Authors
191
277
 
192
278
  Original RQRCode author: Duncan Robertson
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ begin
2
+ require "standard/rake"
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task default: [:spec, "standard:fix"]
8
+ rescue LoadError
9
+ # no standard/rspec available
10
+ end
data/lib/rqrcode.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RQRCode
4
- require 'rqrcode_core'
5
- require 'rqrcode/qrcode'
6
- require 'rqrcode/export'
7
- require 'rqrcode/version'
4
+ require "rqrcode_core"
5
+ require "rqrcode/qrcode"
6
+ require "rqrcode/export"
7
+ require "rqrcode/version"
8
8
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rqrcode/export/ansi'
4
- require 'rqrcode/export/html'
5
- require 'rqrcode/export/png'
6
- require 'rqrcode/export/svg'
3
+ require "rqrcode/export/ansi"
4
+ require "rqrcode/export/html"
5
+ require "rqrcode/export/png"
6
+ require "rqrcode/export/svg"
@@ -9,15 +9,15 @@ module RQRCode
9
9
  #
10
10
  # Options:
11
11
  # light: Foreground ("\033[47m")
12
- # dark: Background ANSI code. ("\033[47m")
12
+ # dark: Background ANSI code. ("\033[40m")
13
13
  # fill_character: The written character. (' ')
14
14
  # quiet_zone_size: (4)
15
15
  #
16
- def as_ansi(options={})
16
+ def as_ansi(options = {})
17
17
  options = {
18
18
  light: "\033[47m",
19
19
  dark: "\033[40m",
20
- fill_character: ' ',
20
+ fill_character: " ",
21
21
  quiet_zone_size: 4
22
22
  }.merge(options)
23
23
 
@@ -39,15 +39,13 @@ module RQRCode
39
39
  row << dark
40
40
  previous_dark = true
41
41
  end
42
- row << fill_character
43
- else
42
+ elsif previous_dark != false
44
43
  # light
45
- if previous_dark != false
46
- row << light
47
- previous_dark = false
48
- end
49
- row << fill_character
44
+ row << light
45
+ previous_dark = false
50
46
  end
47
+
48
+ row << fill_character
51
49
  end
52
50
 
53
51
  # add quiet zone
@@ -68,7 +66,7 @@ module RQRCode
68
66
  quiet_row = light + fill_character * width + normal
69
67
  quiet_rows = quiet_row * quiet_zone_size
70
68
 
71
- return quiet_rows + output.join + quiet_rows
69
+ quiet_rows + output.join + quiet_rows
72
70
  end
73
71
  end
74
72
  end
@@ -6,7 +6,7 @@ module RQRCode
6
6
  #
7
7
  # Use this module to HTML-ify the QR code if you just want the default HTML
8
8
  def as_html
9
- ['<table>', rows.as_html, '</table>'].join
9
+ ["<table>", rows.as_html, "</table>"].join
10
10
  end
11
11
 
12
12
  private
@@ -27,7 +27,7 @@ module RQRCode
27
27
 
28
28
  class Row < Struct.new(:qr, :qr_module, :row_index)
29
29
  def as_html
30
- ['<tr>', cells.map(&:as_html).join, '</tr>'].join
30
+ ["<tr>", cells.map(&:as_html).join, "</tr>"].join
31
31
  end
32
32
 
33
33
  def cells
@@ -41,7 +41,7 @@ module RQRCode
41
41
  end
42
42
 
43
43
  def html_class
44
- qr.checked?(row_index, col_index) ? 'black' : 'white'
44
+ qr.checked?(row_index, col_index) ? "black" : "white"
45
45
  end
46
46
  end
47
47
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
- require 'chunky_png'
2
+
3
+ require "chunky_png"
3
4
 
4
5
  # This class creates PNG files.
5
6
  # Code from: https://github.com/DCarper/rqrcode
@@ -8,54 +9,61 @@ module RQRCode
8
9
  module PNG
9
10
  # Render the PNG from the QR Code.
10
11
  #
11
- # There are two sizing algoritams.
12
- #
13
- # - Original that can result in blurry and hard to scan images
14
- # - Google's Chart API inspired sizing that resizes the module size to fit within the given image size.
15
- #
16
- # The Googleis one will be used when no options are given or when the new size option is used.
17
- #
18
12
  # Options:
19
13
  # fill - Background ChunkyPNG::Color, defaults to 'white'
20
14
  # color - Foreground ChunkyPNG::Color, defaults to 'black'
21
15
  #
22
16
  # When option :file is supplied you can use the following ChunkyPNG constraints
23
- # color_mode - The color mode to use. Use one of the ChunkyPNG::COLOR_* constants. defaults to 'ChunkyPNG::COLOR_GRAYSCALE'
24
- # bit_depth - The bit depth to use. This option is only used for indexed images. defaults to '1' bit
25
- # interlace - Whether to use interlacing (true or false). defaults to ChunkyPNG default
26
- # compression - The compression level for Zlib. This can be a value between 0 and 9, or a Zlib constant like Zlib::BEST_COMPRESSION, defaults to ChunkyPNG defaults
17
+ # color_mode - The color mode to use. Use one of the ChunkyPNG::COLOR_* constants.
18
+ # (defaults to 'ChunkyPNG::COLOR_GRAYSCALE')
19
+ # bit_depth - The bit depth to use. This option is only used for indexed images.
20
+ # (defaults to 1 bit)
21
+ # interlace - Whether to use interlacing (true or false).
22
+ # (defaults to ChunkyPNG default)
23
+ # compression - The compression level for Zlib. This can be a value between 0 and 9, or a
24
+ # Zlib constant like Zlib::BEST_COMPRESSION
25
+ # (defaults to ChunkyPNG default)
26
+ #
27
+ # There are two sizing algorithms.
28
+ #
29
+ # - Original that can result in blurry and hard to scan images
30
+ # - Google's Chart API inspired sizing that resizes the module size to fit within the given image size.
31
+ #
32
+ # The Googleis one will be used when no options are given or when the new size option is used.
27
33
  #
28
- # *Googleis*
29
- # size - Total size of PNG in pixels. The module size is calculated so it fits. (defaults to 90)
30
- # border_modules - Width of white border around in modules. (defaults to 4).
34
+ # *Google*
35
+ # size - Total size of PNG in pixels. The module size is calculated so it fits.
36
+ # (defaults to 120)
37
+ # border_modules - Width of white border around in modules.
38
+ # (defaults to 4).
31
39
  #
32
40
  # -- DONT USE border_modules OPTION UNLESS YOU KNOW ABOUT THE QUIET ZONE NEEDS OF QR CODES --
33
41
  #
34
42
  # *Original*
35
43
  # module_px_size - Image size, in pixels.
36
- # border - Border thickness, in pixels
44
+ # border - Border thickness, in pixels
37
45
  #
38
46
  # It first creates an image where 1px = 1 module, then resizes.
39
- # Defaults to 90x90 pixels, customizable by option.
47
+ # Defaults to 120x120 pixels, customizable by option.
40
48
  #
41
49
  def as_png(options = {})
42
50
  default_img_options = {
43
51
  bit_depth: 1,
44
52
  border_modules: 4,
45
53
  color_mode: ChunkyPNG::COLOR_GRAYSCALE,
46
- color: 'black',
54
+ color: "black",
47
55
  file: false,
48
- fill: 'white',
56
+ fill: "white",
49
57
  module_px_size: 6,
50
58
  resize_exactly_to: false,
51
59
  resize_gte_to: false,
52
60
  size: 120
53
61
  }
54
62
 
55
- googleis = options.length == 0 || (options[:size] != nil)
63
+ googleis = options.length == 0 || !options[:size].nil?
56
64
  options = default_img_options.merge(options) # reverse_merge
57
- fill = ChunkyPNG::Color(options[:fill])
58
- color = ChunkyPNG::Color(options[:color])
65
+ fill = ChunkyPNG::Color(options[:fill])
66
+ color = ChunkyPNG::Color(options[:color])
59
67
  output_file = options[:file]
60
68
  module_px_size = nil
61
69
  border_px = nil
@@ -81,7 +89,7 @@ module RQRCode
81
89
  else
82
90
  options[:module_px_size]
83
91
  end
84
- border_px = border * module_px_size
92
+ border_px = border * module_px_size
85
93
  total_border_px = border_px * 2
86
94
  resize_to = options[:resize_exactly_to]
87
95
 
@@ -96,7 +104,7 @@ module RQRCode
96
104
  if @qrcode.checked?(x, y)
97
105
  (0...module_px_size).each do |i|
98
106
  (0...module_px_size).each do |j|
99
- png[(y * module_px_size) + border_px + j , (x * module_px_size) + border_px + i] = color
107
+ png[(y * module_px_size) + border_px + j, (x * module_px_size) + border_px + i] = color
100
108
  end
101
109
  end
102
110
  end
@@ -112,7 +120,7 @@ module RQRCode
112
120
  color_mode: options[:color_mode],
113
121
  bit_depth: options[:bit_depth]
114
122
  }
115
- constraints[:interlace] = options[:interlace] if options.has_key?(:interlace)
123
+ constraints[:interlace] = options[:interlace] if options.has_key?(:interlace)
116
124
  constraints[:compression] = options[:compression] if options.has_key?(:compression)
117
125
  png.save(output_file, constraints)
118
126
  end
@@ -1,59 +1,198 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # This class creates a SVG files.
4
- # Code from: https://github.com/samvincent/rqrcode-rails3
4
+ # Initial code from: https://github.com/samvincent/rqrcode-rails3
5
5
  module RQRCode
6
6
  module Export
7
7
  module SVG
8
+ class BaseOutputSVG
9
+ attr_reader :result
10
+
11
+ def initialize(qrcode)
12
+ @qrcode = qrcode
13
+ @result = []
14
+ end
15
+ end
16
+
17
+ class Path < BaseOutputSVG
18
+ def build(module_size, offset, color)
19
+ modules_array = @qrcode.modules
20
+ matrix_width = matrix_height = modules_array.length + 1
21
+ empty_row = [Array.new(matrix_width - 1, false)]
22
+ edge_matrix = Array.new(matrix_height) { Array.new(matrix_width) }
23
+
24
+ (empty_row + modules_array + empty_row).each_cons(2).with_index do |row_pair, row_index|
25
+ first_row, second_row = row_pair
26
+
27
+ # horizontal edges
28
+ first_row.zip(second_row).each_with_index do |cell_pair, column_index|
29
+ edge = case cell_pair
30
+ when [true, false] then Edge.new column_index + 1, row_index, :left
31
+ when [false, true] then Edge.new column_index, row_index, :right
32
+ end
33
+
34
+ (edge_matrix[edge.start_y][edge.start_x] ||= []) << edge if edge
35
+ end
36
+
37
+ # vertical edges
38
+ ([false] + second_row + [false]).each_cons(2).each_with_index do |cell_pair, column_index|
39
+ edge = case cell_pair
40
+ when [true, false] then Edge.new column_index, row_index, :down
41
+ when [false, true] then Edge.new column_index, row_index + 1, :up
42
+ end
43
+
44
+ (edge_matrix[edge.start_y][edge.start_x] ||= []) << edge if edge
45
+ end
46
+ end
47
+
48
+ edge_count = edge_matrix.flatten.compact.count
49
+ path = []
50
+
51
+ while edge_count > 0
52
+ edge_loop = []
53
+ next_matrix_cell = edge_matrix.find(&:any?).find { |cell| cell&.any? }
54
+ edge = next_matrix_cell.first
55
+
56
+ while edge
57
+ edge_loop << edge
58
+ matrix_cell = edge_matrix[edge.start_y][edge.start_x]
59
+ matrix_cell.delete edge
60
+ edge_matrix[edge.start_y][edge.start_x] = nil if matrix_cell.empty?
61
+ edge_count -= 1
62
+
63
+ # try to find an edge continuing the current edge
64
+ edge = edge_matrix[edge.end_y][edge.end_x]&.first
65
+ end
66
+
67
+ first_edge = edge_loop.first
68
+ edge_loop_string = SVG_PATH_COMMANDS[:move]
69
+ edge_loop_string += "#{first_edge.start_x} #{first_edge.start_y}"
70
+
71
+ edge_loop.chunk(&:direction).to_a[0...-1].each do |direction, edges|
72
+ edge_loop_string << "#{SVG_PATH_COMMANDS[direction]}#{edges.length}"
73
+ end
74
+ edge_loop_string << SVG_PATH_COMMANDS[:close]
75
+
76
+ path << edge_loop_string
77
+ end
78
+
79
+ @result << %{<path d="#{path.join}" style="fill:##{color}" transform="translate(#{offset},#{offset}) scale(#{module_size})"/>}
80
+ end
81
+ end
82
+
83
+ class Rect < BaseOutputSVG
84
+ def build(module_size, offset, color)
85
+ @qrcode.modules.each_index do |c|
86
+ tmp = []
87
+ @qrcode.modules.each_index do |r|
88
+ y = c * module_size + offset
89
+ x = r * module_size + offset
90
+
91
+ next unless @qrcode.checked?(c, r)
92
+ tmp << %(<rect width="#{module_size}" height="#{module_size}" x="#{x}" y="#{y}" style="fill:##{color}"/>)
93
+ end
94
+
95
+ @result << tmp.join
96
+ end
97
+ end
98
+ end
99
+
100
+ class Edge < Struct.new(:start_x, :start_y, :direction)
101
+ def end_x
102
+ case direction
103
+ when :right then start_x + 1
104
+ when :left then start_x - 1
105
+ else start_x
106
+ end
107
+ end
108
+
109
+ def end_y
110
+ case direction
111
+ when :down then start_y + 1
112
+ when :up then start_y - 1
113
+ else start_y
114
+ end
115
+ end
116
+ end
117
+
118
+ DEFAULT_SVG_ATTRIBUTES = [
119
+ %(version="1.1"),
120
+ %(xmlns="http://www.w3.org/2000/svg"),
121
+ %(xmlns:xlink="http://www.w3.org/1999/xlink"),
122
+ %(xmlns:ev="http://www.w3.org/2001/xml-events")
123
+ ]
124
+
125
+ SVG_PATH_COMMANDS = {
126
+ move: "M",
127
+ up: "v-",
128
+ down: "v",
129
+ left: "h-",
130
+ right: "h",
131
+ close: "z"
132
+ }
133
+
8
134
  #
9
135
  # Render the SVG from the Qrcode.
10
136
  #
11
137
  # Options:
12
- # offset - Padding around the QR Code (e.g. 10)
13
- # fill - Background color (e.g "ffffff" or :white)
14
- # color - Foreground color for the code (e.g. "000000" or :black)
15
- # module_size - The Pixel size of each module (e.g. 11)
16
- # shape_rendering - Defaults to crispEdges
17
- # standalone - wether to make this a full SVG file, or only svg to embed
18
- # in other svg.
138
+ # offset - Padding around the QR Code in pixels
139
+ # (default 0)
140
+ # fill - Background color e.g "ffffff"
141
+ # (default none)
142
+ # color - Foreground color e.g "000"
143
+ # (default "000")
144
+ # module_size - The Pixel size of each module
145
+ # (defaults 11)
146
+ # shape_rendering - SVG Attribute: auto | optimizeSpeed | crispEdges | geometricPrecision
147
+ # (defaults crispEdges)
148
+ # standalone - Whether to make this a full SVG file, or only an svg to embed in other svg
149
+ # (default true)
150
+ # use_path - Use <path> to render SVG rather than <rect> to significantly reduce size
151
+ # and quality. This will become the default in future versions.
152
+ # (default false)
153
+ # viewbox - replace `width` and `height` in <svg> with a viewBox, allows CSS scaling
154
+ # (default false)
155
+ # svg_attributes - A optional hash of custom <svg> attributes. Existing attributes will remain.
156
+ # (default {})
19
157
  #
20
- def as_svg(options={})
158
+ def as_svg(options = {})
159
+ fill = options[:fill]
160
+ use_path = options[:use_path]
21
161
  offset = options[:offset].to_i || 0
22
162
  color = options[:color] || "000"
23
163
  shape_rendering = options[:shape_rendering] || "crispEdges"
24
164
  module_size = options[:module_size] || 11
25
165
  standalone = options[:standalone].nil? ? true : options[:standalone]
166
+ viewbox = options[:viewbox].nil? ? false : options[:viewbox]
167
+ svg_attributes = options[:svg_attributes] || {}
26
168
 
27
169
  # height and width dependent on offset and QR complexity
28
- dimension = (@qrcode.module_count*module_size) + (2*offset)
170
+ dimension = (@qrcode.module_count * module_size) + (2 * offset)
171
+ # use dimensions differently if we are using a viewBox
172
+ dimensions_attr = viewbox ? %(viewBox="0 0 #{dimension} #{dimension}") : %(width="#{dimension}" height="#{dimension}")
29
173
 
30
- xml_tag = %{<?xml version="1.0" standalone="yes"?>}
31
- open_tag = %{<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events" width="#{dimension}" height="#{dimension}" shape-rendering="#{shape_rendering}">}
32
- close_tag = "</svg>"
174
+ svg_tag_attributes = (DEFAULT_SVG_ATTRIBUTES + [
175
+ dimensions_attr,
176
+ %(shape-rendering="#{shape_rendering}")
177
+ ] + svg_attributes.map { |k, v| %(#{k}="#{v}") }).join(" ")
33
178
 
34
- result = []
35
- @qrcode.modules.each_index do |c|
36
- tmp = []
37
- @qrcode.modules.each_index do |r|
38
- y = c*module_size + offset
39
- x = r*module_size + offset
179
+ xml_tag = %(<?xml version="1.0" standalone="yes"?>)
180
+ open_tag = %(<svg #{svg_tag_attributes}>)
181
+ close_tag = "</svg>"
40
182
 
41
- next unless @qrcode.checked?(c, r)
42
- tmp << %{<rect width="#{module_size}" height="#{module_size}" x="#{x}" y="#{y}" style="fill:##{color}"/>}
43
- end
44
- result << tmp.join
45
- end
183
+ output_tag = (use_path ? Path : Rect).new(@qrcode)
184
+ output_tag.build(module_size, offset, color)
46
185
 
47
- if options[:fill]
48
- result.unshift %{<rect width="#{dimension}" height="#{dimension}" x="0" y="0" style="fill:##{options[:fill]}"/>}
186
+ if fill
187
+ output_tag.result.unshift %(<rect width="#{dimension}" height="#{dimension}" x="0" y="0" style="fill:##{fill}"/>)
49
188
  end
50
189
 
51
190
  if standalone
52
- result.unshift(xml_tag, open_tag)
53
- result << close_tag
191
+ output_tag.result.unshift(xml_tag, open_tag)
192
+ output_tag.result << close_tag
54
193
  end
55
194
 
56
- result.join("\n")
195
+ output_tag.result.join
57
196
  end
58
197
  end
59
198
  end
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rqrcode/qrcode/qrcode'
3
+ require "rqrcode/qrcode/qrcode"
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'forwardable'
3
+ require "forwardable"
4
4
 
5
5
  module RQRCode #:nodoc:
6
6
  class QRCode
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RQRCode
4
- VERSION = "1.2.0"
4
+ VERSION = "2.0.0"
5
5
  end
data/rqrcode.gemspec CHANGED
@@ -1,36 +1,35 @@
1
- # -*- encoding: utf-8 -*-
2
-
3
1
  lib = File.expand_path("../lib", __FILE__)
4
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
3
  require "rqrcode/version"
6
4
 
7
5
  Gem::Specification.new do |spec|
8
- spec.name = "rqrcode"
9
- spec.version = RQRCode::VERSION
10
- spec.platform = Gem::Platform::RUBY
11
- spec.authors = ["Duncan Robertson"]
12
- spec.email = ["duncan@whomwah.com"]
6
+ spec.name = "rqrcode"
7
+ spec.version = RQRCode::VERSION
8
+ spec.platform = Gem::Platform::RUBY
9
+ spec.authors = ["Duncan Robertson"]
10
+ spec.email = ["duncan@whomwah.com"]
13
11
 
14
- spec.summary = %q{A library to encode QR Codes}
15
- spec.description = <<EOF
16
- rqrcode is a library for encoding QR Codes. The simple
17
- interface allows you to create QR Code data structures
18
- and then render them in the way you choose.
19
- EOF
20
- spec.homepage = "https://github.com/whomwah/rqrcode"
21
- spec.license = "MIT"
12
+ spec.summary = "A library to encode QR Codes"
13
+ spec.description = <<~EOF
14
+ rqrcode is a library for encoding QR Codes. The simple
15
+ interface allows you to create QR Code data structures
16
+ and then render them in the way you choose.
17
+ EOF
18
+ spec.homepage = "https://github.com/whomwah/rqrcode"
19
+ spec.license = "MIT"
22
20
 
23
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
21
+ spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
24
22
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
23
  end
26
- spec.bindir = "exe"
27
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.bindir = "exe"
25
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
26
  spec.require_paths = ["lib"]
29
27
 
30
- spec.required_ruby_version = '>= 2.3'
31
- spec.add_dependency 'rqrcode_core', '~> 0.2'
32
- spec.add_dependency 'chunky_png', '~> 1.0'
33
- spec.add_development_dependency 'bundler', '>= 2.0'
34
- spec.add_development_dependency 'rake', '~> 13.0'
35
- spec.add_development_dependency 'rspec', '~> 3.5'
28
+ spec.required_ruby_version = ">= 2.3"
29
+ spec.add_dependency "rqrcode_core", "~> 1.0"
30
+ spec.add_dependency "chunky_png", "~> 1.0"
31
+ spec.add_development_dependency "bundler", "~> 2.0"
32
+ spec.add_development_dependency "rake", "~> 13.0"
33
+ spec.add_development_dependency "rspec", "~> 3.5"
34
+ spec.add_development_dependency "standardrb", "~> 1.0"
36
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rqrcode
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Duncan Robertson
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-12-26 00:00:00.000000000 Z
11
+ date: 2021-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rqrcode_core
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.2'
19
+ version: '1.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.2'
26
+ version: '1.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: chunky_png
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -42,14 +42,14 @@ dependencies:
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '2.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '2.0'
55
55
  - !ruby/object:Gem::Dependency
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '3.5'
83
+ - !ruby/object:Gem::Dependency
84
+ name: standardrb
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.0'
83
97
  description: |
84
98
  rqrcode is a library for encoding QR Codes. The simple
85
99
  interface allows you to create QR Code data structures
@@ -93,9 +107,12 @@ files:
93
107
  - ".github/workflows/ruby.yml"
94
108
  - ".gitignore"
95
109
  - ".rspec"
110
+ - CHANGELOG.md
96
111
  - Gemfile
112
+ - Gemfile.lock
97
113
  - LICENSE.txt
98
114
  - README.md
115
+ - Rakefile
99
116
  - _config.yml
100
117
  - bin/console
101
118
  - bin/setup
@@ -131,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
131
148
  - !ruby/object:Gem::Version
132
149
  version: '0'
133
150
  requirements: []
134
- rubygems_version: 3.2.3
151
+ rubygems_version: 3.2.15
135
152
  signing_key:
136
153
  specification_version: 4
137
154
  summary: A library to encode QR Codes