rqrcode 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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