visual-qrcode 0.1.2 → 1.O.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +54 -15
- data/docs/basic_to_visual_sample.png +0 -0
- data/lib/visual_qrcode/module_filler.rb +2 -2
- data/lib/visual_qrcode/pixels_handler.rb +35 -0
- data/lib/visual_qrcode/qrcode.rb +18 -17
- data/lib/visual_qrcode/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e1d5268c5f404484b75afcee3fa4dc74fe7d6f709a9cfc2405608ac37ce6ca5e
|
4
|
+
data.tar.gz: 5a17c764d5369a18de46ac7fa8b22e7b873eca29912a20dbcc76b27352883d71
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 839b3876084aa3528b23ca0bd31aded4783ac835c1b4bd76adae190a8c34f987a6aa0746a97f9f233d8a9cdeed141c27880f128d583dd8f98d7f1807175cfa18
|
7
|
+
data.tar.gz: 0ccc5234545ed305ca8a23587da3d7a49200d253c526039dbabccd585bf89e5413fa348966bc09cd112077c2f73f4a21461809ab4481aea71ec480056f9c5a47
|
data/README.md
CHANGED
@@ -1,10 +1,16 @@
|
|
1
|
-
#
|
1
|
+
# VisualQrcode
|
2
2
|
|
3
|
-
`
|
3
|
+
`VisualQrcode` gives you various tools to generate working QR codes with images in their backgrounds, based on [this research](https://cgv.cs.nthu.edu.tw/Projects/Recreational_Graphics/Halftone_QRCodes/).
|
4
4
|
|
5
|
-
Example of
|
5
|
+
Example of some `VisualQrcode` generated by the tests :
|
6
6
|
|
7
|
+
![image](/spec/images/ruby_visual_qrcode.png)
|
7
8
|
![image](/spec/images/marianne_visual_qrcode.png)
|
9
|
+
![image](/spec/images/zidane_visual_qrcode.png)
|
10
|
+
|
11
|
+
Basically, each QR Code module is transformed into 9 pixels. The central pixel is the QR Code data, and the 8 other pixels around are used to display the background image.
|
12
|
+
|
13
|
+
![image](/docs/basic_to_visual_sample.png)
|
8
14
|
|
9
15
|
## Installation
|
10
16
|
|
@@ -30,10 +36,13 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
30
36
|
## Usage
|
31
37
|
|
32
38
|
The basic usage requires a string for the QRCode content and an `image_path` (or `image_url`).
|
33
|
-
**Default size** : 3x the basic QRCode size generated with a high level of error correction.
|
34
39
|
|
35
40
|
```ruby
|
36
|
-
visual_qr_code = VisualQrcode::Qrcode.new(
|
41
|
+
visual_qr_code = VisualQrcode::Qrcode.new(
|
42
|
+
"This is the sentence that will read in the QR Code",
|
43
|
+
"spec/images/marianne.png",
|
44
|
+
size: 260
|
45
|
+
)
|
37
46
|
|
38
47
|
# Returns a MiniMagick::Image
|
39
48
|
image = visual_qr_code.as_png
|
@@ -42,26 +51,56 @@ image = visual_qr_code.as_png
|
|
42
51
|
image.write("./marianne_visual_qrcode.png")
|
43
52
|
```
|
44
53
|
|
45
|
-
|
54
|
+
> **Default size** : Because we need 9 pixels in each QR Code module, the **minimum size** is **3x the minimum basic QRCode size** (with a `:high` level of [error correction](https://github.com/whomwah/rqrcode_core/tree/master?tab=readme-ov-file#options)). It varies with the amount of content you want to encode in the QR Code.
|
55
|
+
>
|
56
|
+
> If you choose a size too small, you'll get an error informing you of the minimum size necessary for your content.
|
46
57
|
|
47
|
-
```ruby
|
48
|
-
visual_qr_code = VisualQrcode::Qrcode.new("bonjour by 280", "spec/images/marianne.png", size: 280)
|
49
|
-
|
50
|
-
visual_qrcode.as_png.write("./marianne_visual_qrcode_280x280.png")
|
51
|
-
```
|
52
58
|
|
53
59
|
## Design choices
|
54
60
|
|
61
|
+
### Resize method
|
62
|
+
|
63
|
+
The Visual QRCode will be generated at a mutiple of the **minimum size**, and then reduced to the expected size to maintain a good background image quality.
|
64
|
+
|
65
|
+
> For example, if the minimum size is 140px, and you want a 230px image, it will generate a 280px Visual QRCode and then reduce it to 230px.
|
66
|
+
|
67
|
+
Because of that, it is recommended to provide an image bigger than the expected size, to not be made blurry by the resize. You can't go wrong with an image twice as big as the size of the wanted result.
|
68
|
+
|
55
69
|
### Padding
|
56
70
|
|
57
|
-
In order to have a nice visual, a padding is added on the image to keep it inside of the QRCode
|
71
|
+
In order to have a nice visual, a padding is added on the image to keep it inside of the QRCode line patterns on top and on the left. Also it helps to reckognize that the image _is_ a scannable QRCode by keeping some of the well-known patterns of the QR Code in the padding.
|
58
72
|
|
59
|
-
|
73
|
+
**By default, the padding is equal to 7 modules.**
|
74
|
+
|
75
|
+
If your image has enough transparency to dodge the QRCode lines, you can remove the padding with the `padding_modules: 0` option.
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
visual_qr_code = VisualQrcode::Qrcode.new(
|
79
|
+
"https://en.wikipedia.org/wiki/Zinedine_Zidane",
|
80
|
+
"spec/images/zidane.png",
|
81
|
+
size: 260,
|
82
|
+
padding_modules: 0
|
83
|
+
)
|
84
|
+
```
|
60
85
|
|
61
|
-
|
86
|
+
You can also customize the padding if you want more or less modules than the default value.
|
62
87
|
|
63
|
-
|
88
|
+
### QRCode minimum Size
|
89
|
+
|
90
|
+
The minimum [size of RQRCodeCore](https://github.com/whomwah/rqrcode_core/tree/master?tab=readme-ov-file#options) used is 6 by default, to get enough space for the image to be visible inside the Visual QRCode.
|
91
|
+
|
92
|
+
You can increase the amount of modules with the `minimum_qr_size` parameter. It corresponds to the [size option of RQRCodeCore](https://github.com/whomwah/rqrcode_core/tree/master?tab=readme-ov-file#options)
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
visual_qr_code = VisualQrcode::Qrcode.new(
|
96
|
+
"small content",
|
97
|
+
"spec/images/zidane.png",
|
98
|
+
size: 260,
|
99
|
+
minimum_qr_size: 15
|
100
|
+
)
|
101
|
+
```
|
64
102
|
|
103
|
+
You can also force it to a lower value if you want. But it will always be incremented until finding a suitable value for your content size.
|
65
104
|
|
66
105
|
## Development
|
67
106
|
|
Binary file
|
@@ -16,7 +16,7 @@ module ModuleFiller
|
|
16
16
|
|
17
17
|
def fill_vqr_module_with_basic_qrcode(x_index, y_index)
|
18
18
|
multiplied_range_each(x_index, y_index) do |new_x, new_y, x_offset, y_offset|
|
19
|
-
if central_pixel?(x_offset, y_offset) || @
|
19
|
+
if central_pixel?(x_offset, y_offset) || @pixels_handler.pixels[new_x][new_y][3].zero?
|
20
20
|
value = @basic_qrcode.modules[x_index][y_index]
|
21
21
|
@vqr_pixels[new_x][new_y] = pixel_of(value)
|
22
22
|
end
|
@@ -27,7 +27,7 @@ module ModuleFiller
|
|
27
27
|
multiplied_range_each(x_index, y_index) do |new_x, new_y, x_offset, y_offset|
|
28
28
|
next if central_pixel?(x_offset, y_offset)
|
29
29
|
|
30
|
-
pixel = @
|
30
|
+
pixel = @pixels_handler.pixels[new_x][new_y]
|
31
31
|
@vqr_pixels[new_x][new_y] = pixel
|
32
32
|
end
|
33
33
|
end
|
@@ -35,6 +35,7 @@ module VisualQrcode
|
|
35
35
|
def resize(new_size)
|
36
36
|
image.resize "#{new_size}x#{new_size}"
|
37
37
|
set_pixels_from_image
|
38
|
+
make_square
|
38
39
|
end
|
39
40
|
|
40
41
|
def add_margin(margin, color: :transparent)
|
@@ -49,8 +50,42 @@ module VisualQrcode
|
|
49
50
|
@pixels = col_margin + margined_rows + col_margin
|
50
51
|
end
|
51
52
|
|
53
|
+
def make_square
|
54
|
+
max_size = [@pixels.length, @pixels.first.length].max
|
55
|
+
|
56
|
+
if @pixels.length < max_size
|
57
|
+
add_transparent_columns_to_size(max_size)
|
58
|
+
elsif @pixels.first.length < max_size
|
59
|
+
add_transparent_rows_to_size(max_size)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
52
63
|
private
|
53
64
|
|
65
|
+
def add_transparent_columns_to_size(max_size)
|
66
|
+
size_difference = max_size - @pixels.length
|
67
|
+
margin = size_difference / 2
|
68
|
+
rest_of_margin = size_difference % 2
|
69
|
+
|
70
|
+
left_col_margin = [Array.new(max_size, transparent_pixel)] * margin
|
71
|
+
right_col_margin = [Array.new(max_size, transparent_pixel)] * (margin + rest_of_margin)
|
72
|
+
|
73
|
+
@pixels = left_col_margin + @pixels + right_col_margin
|
74
|
+
end
|
75
|
+
|
76
|
+
def add_transparent_rows_to_size(max_size)
|
77
|
+
size_difference = max_size - @pixels.first.length
|
78
|
+
margin = size_difference / 2
|
79
|
+
rest_of_margin = size_difference % 2
|
80
|
+
|
81
|
+
left_row_margin = [transparent_pixel] * margin
|
82
|
+
right_row_margin = [transparent_pixel] * (margin + rest_of_margin)
|
83
|
+
|
84
|
+
@pixels = @pixels.map do |row|
|
85
|
+
left_row_margin + row + right_row_margin
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
54
89
|
def set_pixels_from_image
|
55
90
|
@pixels = @image.get_pixels("RGBA")
|
56
91
|
end
|
data/lib/visual_qrcode/qrcode.rb
CHANGED
@@ -11,16 +11,18 @@ module VisualQrcode
|
|
11
11
|
include PixelTools
|
12
12
|
include ModuleFiller
|
13
13
|
|
14
|
-
|
14
|
+
DEFAULT_PADDING_MODULES = 7
|
15
15
|
|
16
|
-
attr_reader :content, :basic_qrcode, :
|
16
|
+
attr_reader :content, :basic_qrcode, :pixels_handler, :vqr_pixels
|
17
17
|
|
18
|
-
def initialize(content, image_path, size: nil)
|
18
|
+
def initialize(content, image_path, size: nil, padding_modules: nil, minimum_qr_size: nil)
|
19
19
|
@content = content
|
20
20
|
@size = size
|
21
|
+
@padding_modules = padding_modules || DEFAULT_PADDING_MODULES
|
22
|
+
@minimum_qr_size = minimum_qr_size || 6
|
21
23
|
|
22
|
-
|
23
|
-
@
|
24
|
+
initialize_basic_qr_code_and_minimum_qr_size(content)
|
25
|
+
@pixels_handler = VisualQrcode::PixelsHandler.new(image_path: image_path)
|
24
26
|
@common_patterns = @basic_qrcode.instance_variable_get(:@common_patterns)
|
25
27
|
end
|
26
28
|
|
@@ -29,16 +31,6 @@ module VisualQrcode
|
|
29
31
|
VisualQrcode::Export.new(@vqr_pixels).as_png(size: @size, margin: margin)
|
30
32
|
end
|
31
33
|
|
32
|
-
def basic_qrcode_as_png(margin: default_margin)
|
33
|
-
make
|
34
|
-
basic_qrcode_pixels = @basic_qrcode.modules.map do |module_row|
|
35
|
-
pixels_row = module_row.map { |value| [pixel_of(value)] * PIXELS_PER_MODULE }.flatten
|
36
|
-
([pixels_row] * PIXELS_PER_MODULE)
|
37
|
-
end.flatten(1)
|
38
|
-
|
39
|
-
VisualQrcode::Export.new(basic_qrcode_pixels).as_png(size: @size, margin: margin)
|
40
|
-
end
|
41
|
-
|
42
34
|
def make
|
43
35
|
intit_vqr_pixels
|
44
36
|
resize_image
|
@@ -51,8 +43,8 @@ module VisualQrcode
|
|
51
43
|
end
|
52
44
|
|
53
45
|
def resize_image
|
54
|
-
padding_size =
|
55
|
-
@
|
46
|
+
padding_size = @padding_modules * module_size
|
47
|
+
@pixels_handler.resize_with_padding(@vqr_length, padding_size)
|
56
48
|
end
|
57
49
|
|
58
50
|
def fill_vqr_pixels
|
@@ -65,6 +57,15 @@ module VisualQrcode
|
|
65
57
|
|
66
58
|
private
|
67
59
|
|
60
|
+
def initialize_basic_qr_code_and_minimum_qr_size(content)
|
61
|
+
@basic_qrcode = RQRCodeCore::QRCode.new(content, level: :h, size: @minimum_qr_size)
|
62
|
+
rescue RQRCodeCore::QRCodeRunTimeError => e
|
63
|
+
raise e unless e.message =~ /^code length overflow./
|
64
|
+
|
65
|
+
@minimum_qr_size += 1
|
66
|
+
initialize_basic_qr_code_and_minimum_qr_size(content)
|
67
|
+
end
|
68
|
+
|
68
69
|
def default_margin
|
69
70
|
module_size * 2
|
70
71
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: visual-qrcode
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.O.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Caillou
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-07-
|
11
|
+
date: 2024-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mini_magick
|
@@ -53,6 +53,7 @@ files:
|
|
53
53
|
- LICENSE.txt
|
54
54
|
- README.md
|
55
55
|
- Rakefile
|
56
|
+
- docs/basic_to_visual_sample.png
|
56
57
|
- lib/visual_qrcode.rb
|
57
58
|
- lib/visual_qrcode/export.rb
|
58
59
|
- lib/visual_qrcode/module_filler.rb
|