oshpark-rqrcode 0.10.1
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 +7 -0
- data/CHANGELOG +97 -0
- data/LICENSE +19 -0
- data/README.md +230 -0
- data/lib/rqrcode.rb +20 -0
- data/lib/rqrcode/core_ext.rb +5 -0
- data/lib/rqrcode/core_ext/array.rb +5 -0
- data/lib/rqrcode/core_ext/array/behavior.rb +12 -0
- data/lib/rqrcode/core_ext/integer.rb +5 -0
- data/lib/rqrcode/core_ext/integer/bitwise.rb +13 -0
- data/lib/rqrcode/export/ansi.rb +78 -0
- data/lib/rqrcode/export/gerber.rb +93 -0
- data/lib/rqrcode/export/html.rb +53 -0
- data/lib/rqrcode/export/png.rb +117 -0
- data/lib/rqrcode/export/svg.rb +53 -0
- data/lib/rqrcode/qrcode.rb +4 -0
- data/lib/rqrcode/qrcode/qr_8bit_byte.rb +36 -0
- data/lib/rqrcode/qrcode/qr_alphanumeric.rb +47 -0
- data/lib/rqrcode/qrcode/qr_bit_buffer.rb +99 -0
- data/lib/rqrcode/qrcode/qr_code.rb +585 -0
- data/lib/rqrcode/qrcode/qr_math.rb +63 -0
- data/lib/rqrcode/qrcode/qr_numeric.rb +57 -0
- data/lib/rqrcode/qrcode/qr_polynomial.rb +78 -0
- data/lib/rqrcode/qrcode/qr_rs_block.rb +314 -0
- data/lib/rqrcode/qrcode/qr_util.rb +272 -0
- data/lib/rqrcode/version.rb +3 -0
- data/test/data.rb +25 -0
- data/test/test_helper.rb +5 -0
- data/test/test_regresions.rb +10 -0
- data/test/test_rqrcode.rb +155 -0
- data/test/test_rqrcode_export.rb +27 -0
- metadata +128 -0
@@ -0,0 +1,93 @@
|
|
1
|
+
module RQRCode
|
2
|
+
module Export
|
3
|
+
module Gerber
|
4
|
+
attr_accessor :positive, :precision, :pixel_width, :x_origin, :y_origin, :quiet_zone_size, :mirrored
|
5
|
+
##
|
6
|
+
# Returns a string of the QR code as
|
7
|
+
# characters writen with ANSI background set.
|
8
|
+
#
|
9
|
+
# Options:
|
10
|
+
# light: Foreground ("\033[47m")
|
11
|
+
# dark: Background ANSI code. ("\033[47m")
|
12
|
+
# fill_character: The written character. (' ')
|
13
|
+
# quiet_zone_size: (4)
|
14
|
+
#
|
15
|
+
def flash(x,y)
|
16
|
+
top_y = (@y_origin + @module_count + (@quiet_zone_size *2 )) * @pixel_width
|
17
|
+
y = top_y - (y * @pixel_width)
|
18
|
+
if @mirrored then
|
19
|
+
right_x = (@x_origin + @module_count + (@quiet_zone_size*2)) * @pixel_width
|
20
|
+
x = right_x - (x * @pixel_width)
|
21
|
+
else
|
22
|
+
x = @x_origin + x * @pixel_width
|
23
|
+
end
|
24
|
+
#puts "FLASH #{x} #{y}"
|
25
|
+
y = (y * @p_mult).to_i
|
26
|
+
x = (x * @p_mult).to_i
|
27
|
+
return "G01X#{x}Y#{y}D03*\n"
|
28
|
+
end
|
29
|
+
|
30
|
+
def is_light(x,y)
|
31
|
+
! is_dark(x,y)
|
32
|
+
end
|
33
|
+
|
34
|
+
def as_gerber(options={})
|
35
|
+
options = {
|
36
|
+
precision: 6,
|
37
|
+
pixel_width: 0.010, # inches
|
38
|
+
x_origin: 0.000, # inches
|
39
|
+
y_origin: 0.000, # inches
|
40
|
+
quiet_zone_size: 1,
|
41
|
+
mirrored: false
|
42
|
+
}.merge(options)
|
43
|
+
@x_origin = options.fetch(:x_origin)
|
44
|
+
@y_origin = options.fetch(:y_origin)
|
45
|
+
@precision = options.fetch(:precision)
|
46
|
+
@pixel_width = options.fetch(:pixel_width)
|
47
|
+
@quiet_zone_size = options.fetch(:quiet_zone_size)
|
48
|
+
@mirrored = options.fetch(:mirrored)
|
49
|
+
|
50
|
+
@p_mult = 10**options[:precision]
|
51
|
+
|
52
|
+
output=<<-EOF
|
53
|
+
G04 This is an RQRCode Generated gerber file.*
|
54
|
+
G04 --End of header info--*
|
55
|
+
%MOIN*%
|
56
|
+
%FSLAX3#{options[:precision]}Y3#{options[:precision]}*%
|
57
|
+
%IPPOS*%
|
58
|
+
%ADD10R,#{options[:pixel_width]}X#{options[:pixel_width]}*%
|
59
|
+
G04 --Start main section--*
|
60
|
+
G54D10*
|
61
|
+
EOF
|
62
|
+
|
63
|
+
quiet_zone_size = options.fetch(:quiet_zone_size)
|
64
|
+
|
65
|
+
width = quiet_zone_size + @module_count + quiet_zone_size
|
66
|
+
|
67
|
+
quiet_zone_size.times do |r|
|
68
|
+
width.times do |c|
|
69
|
+
output << flash(c,r) ## Top Quiet Zone
|
70
|
+
output << flash(r,c) ## Left Quiet Zone
|
71
|
+
output << flash(r+quiet_zone_size+@module_count,c)
|
72
|
+
output << flash(c,r+quiet_zone_size+@module_count)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
@modules.each_index do |r|
|
78
|
+
@modules[r].each_index do |c|
|
79
|
+
if is_light(r, c)
|
80
|
+
output << flash(quiet_zone_size+c,quiet_zone_size+r)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
output << "M02*\n"
|
86
|
+
|
87
|
+
return output
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
RQRCode::QRCode.send :include, RQRCode::Export::Gerber
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Use this module to HTML-ify the QR code if you just want the default HTML
|
2
|
+
module RQRCode
|
3
|
+
module Export
|
4
|
+
module HTML
|
5
|
+
|
6
|
+
def as_html
|
7
|
+
['<table>', rows.as_html, '</table>'].join
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def rows
|
13
|
+
Rows.new(self)
|
14
|
+
end
|
15
|
+
|
16
|
+
class Rows < Struct.new(:qr)
|
17
|
+
def as_html
|
18
|
+
rows.map(&:as_html).join
|
19
|
+
end
|
20
|
+
|
21
|
+
def rows
|
22
|
+
qr.modules.each_with_index.map { |qr_module, row_index| Row.new(qr, qr_module, row_index) }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Row < Struct.new(:qr, :qr_module, :row_index)
|
27
|
+
def as_html
|
28
|
+
['<tr>', cells.map(&:as_html).join, '</tr>'].join
|
29
|
+
end
|
30
|
+
|
31
|
+
def cells
|
32
|
+
qr.modules.each_with_index.map { |qr_module, col_index| Cell.new(qr, col_index, row_index) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Cell < Struct.new(:qr, :col_index, :row_index)
|
37
|
+
def as_html
|
38
|
+
"<td class=\"#{html_class}\"></td>"
|
39
|
+
end
|
40
|
+
|
41
|
+
def html_class
|
42
|
+
dark? ? 'black' : 'white'
|
43
|
+
end
|
44
|
+
|
45
|
+
def dark?
|
46
|
+
qr.dark?(row_index, col_index)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
RQRCode::QRCode.send :include, RQRCode::Export::HTML
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'chunky_png'
|
2
|
+
|
3
|
+
# This class creates PNG files.
|
4
|
+
# Code from: https://github.com/DCarper/rqrcode
|
5
|
+
module RQRCode
|
6
|
+
module Export
|
7
|
+
module PNG
|
8
|
+
|
9
|
+
# Render the PNG from the Qrcode.
|
10
|
+
#
|
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
|
+
# Options:
|
19
|
+
# fill - Background ChunkyPNG::Color, defaults to 'white'
|
20
|
+
# color - Foreground ChunkyPNG::Color, defaults to 'black'
|
21
|
+
#
|
22
|
+
# *Googleis*
|
23
|
+
# size - Total size of PNG in pixels. The module size is calculated so it fits. (defaults to 90)
|
24
|
+
# border_modules - Width of white border around in modules. (defaults to 4).
|
25
|
+
#
|
26
|
+
# -- DONT USE border_modules OPTION UNLESS YOU KNOW ABOUT THE QUIET ZONE NEEDS OF QR CODES --
|
27
|
+
#
|
28
|
+
# *Original*
|
29
|
+
# module_px_size - Image size, in pixels.
|
30
|
+
# border - Border thickness, in pixels
|
31
|
+
#
|
32
|
+
# It first creates an image where 1px = 1 module, then resizes.
|
33
|
+
# Defaults to 90x90 pixels, customizable by option.
|
34
|
+
#
|
35
|
+
def as_png(options = {})
|
36
|
+
|
37
|
+
default_img_options = {
|
38
|
+
:resize_gte_to => false,
|
39
|
+
:resize_exactly_to => false,
|
40
|
+
:fill => 'white',
|
41
|
+
:color => 'black',
|
42
|
+
:size => 120,
|
43
|
+
:border_modules => 4,
|
44
|
+
:file => false,
|
45
|
+
:module_px_size => 6
|
46
|
+
}
|
47
|
+
|
48
|
+
googleis = options.length == 0 || (options[:size] != nil)
|
49
|
+
|
50
|
+
options = default_img_options.merge(options) # reverse_merge
|
51
|
+
|
52
|
+
fill = ChunkyPNG::Color(options[:fill])
|
53
|
+
color = ChunkyPNG::Color(options[:color])
|
54
|
+
output_file = options[:file]
|
55
|
+
|
56
|
+
module_px_size = nil
|
57
|
+
border_px = nil
|
58
|
+
png = nil
|
59
|
+
|
60
|
+
if googleis
|
61
|
+
total_image_size = options[:size]
|
62
|
+
border_modules = options[:border_modules]
|
63
|
+
|
64
|
+
module_px_size = (total_image_size.to_f / (self.module_count + 2 * border_modules).to_f).floor.to_i
|
65
|
+
|
66
|
+
img_size = module_px_size * self.module_count
|
67
|
+
|
68
|
+
remaining = total_image_size - img_size
|
69
|
+
border_px = (remaining / 2.0).floor.to_i
|
70
|
+
|
71
|
+
png = ChunkyPNG::Image.new(total_image_size, total_image_size, fill)
|
72
|
+
else
|
73
|
+
border = options[:border_modules]
|
74
|
+
total_border = border * 2
|
75
|
+
module_px_size = if options[:resize_gte_to]
|
76
|
+
(options[:resize_gte_to].to_f / (self.module_count + total_border).to_f).ceil.to_i
|
77
|
+
else
|
78
|
+
options[:module_px_size]
|
79
|
+
end
|
80
|
+
border_px = border * module_px_size
|
81
|
+
total_border_px = border_px * 2
|
82
|
+
resize_to = options[:resize_exactly_to]
|
83
|
+
|
84
|
+
img_size = module_px_size * self.module_count
|
85
|
+
total_img_size = img_size + total_border_px
|
86
|
+
|
87
|
+
png = ChunkyPNG::Image.new(total_img_size, total_img_size, fill)
|
88
|
+
end
|
89
|
+
|
90
|
+
self.modules.each_index do |x|
|
91
|
+
self.modules.each_index do |y|
|
92
|
+
if self.dark?(x, y)
|
93
|
+
(0...module_px_size).each do |i|
|
94
|
+
(0...module_px_size).each do |j|
|
95
|
+
png[(y * module_px_size) + border_px + j , (x * module_px_size) + border_px + i] = color
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
if !googleis && resize_to
|
103
|
+
png = png.resize(resize_to, resize_to)
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
if output_file
|
108
|
+
png.save(output_file,{ :color_mode => ChunkyPNG::COLOR_GRAYSCALE, :bit_depth =>1})
|
109
|
+
end
|
110
|
+
png
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
RQRCode::QRCode.send :include, RQRCode::Export::PNG
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# This class creates a SVG files.
|
2
|
+
# Code from: https://github.com/samvincent/rqrcode-rails3
|
3
|
+
module RQRCode
|
4
|
+
module Export
|
5
|
+
|
6
|
+
module SVG
|
7
|
+
|
8
|
+
# Render the SVG from the Qrcode.
|
9
|
+
#
|
10
|
+
# Options:
|
11
|
+
# offset - Padding around the QR Code (e.g. 10)
|
12
|
+
# fill - Background color (e.g "ffffff" or :white)
|
13
|
+
# color - Foreground color for the code (e.g. "000000" or :black)
|
14
|
+
# module_size - The Pixel size of each module (e.g. 11)
|
15
|
+
# shape_rendering - Defaults to crispEdges
|
16
|
+
#
|
17
|
+
def as_svg(options={})
|
18
|
+
offset = options[:offset].to_i || 0
|
19
|
+
color = options[:color] || "000"
|
20
|
+
shape_rendering = options[:shape_rendering] || "crispEdges"
|
21
|
+
module_size = options[:module_size] || 11
|
22
|
+
|
23
|
+
# height and width dependent on offset and QR complexity
|
24
|
+
dimension = (self.module_count*module_size) + (2*offset)
|
25
|
+
|
26
|
+
xml_tag = %{<?xml version="1.0" standalone="yes"?>}
|
27
|
+
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}">}
|
28
|
+
close_tag = "</svg>"
|
29
|
+
|
30
|
+
result = []
|
31
|
+
self.modules.each_index do |c|
|
32
|
+
tmp = []
|
33
|
+
self.modules.each_index do |r|
|
34
|
+
y = c*module_size + offset
|
35
|
+
x = r*module_size + offset
|
36
|
+
|
37
|
+
next unless self.is_dark(c, r)
|
38
|
+
tmp << %{<rect width="#{module_size}" height="#{module_size}" x="#{x}" y="#{y}" style="fill:##{color}"/>}
|
39
|
+
end
|
40
|
+
result << tmp.join
|
41
|
+
end
|
42
|
+
|
43
|
+
if options[:fill]
|
44
|
+
result.unshift %{<rect width="#{dimension}" height="#{dimension}" x="0" y="0" style="fill:##{options[:fill]}"/>}
|
45
|
+
end
|
46
|
+
|
47
|
+
[xml_tag, open_tag, result, close_tag].flatten.join("\n")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
RQRCode::QRCode.send :include, RQRCode::Export::SVG
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Copyright 2004 by Duncan Robertson (duncan@whomwah.com).
|
5
|
+
# All rights reserved.
|
6
|
+
|
7
|
+
# Permission is granted for use, copying, modification, distribution,
|
8
|
+
# and distribution of modified versions of this work as long as the
|
9
|
+
# above copyright notice is included.
|
10
|
+
#++
|
11
|
+
|
12
|
+
module RQRCode
|
13
|
+
|
14
|
+
class QR8bitByte
|
15
|
+
attr_reader :mode
|
16
|
+
|
17
|
+
def initialize( data )
|
18
|
+
@mode = QRMODE[:mode_8bit_byte]
|
19
|
+
@data = data;
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def get_length
|
24
|
+
@data.bytesize
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def write( buffer)
|
29
|
+
buffer.byte_encoding_start(get_length)
|
30
|
+
@data.each_byte do |b|
|
31
|
+
buffer.put(b, 8)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module RQRCode
|
2
|
+
|
3
|
+
ALPHANUMERIC = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',' ','$','%','*','+','-','.','/',':']
|
4
|
+
|
5
|
+
class QRAlphanumeric
|
6
|
+
attr_reader :mode
|
7
|
+
|
8
|
+
def initialize( data )
|
9
|
+
@mode = QRMODE[:mode_alpha_numk]
|
10
|
+
|
11
|
+
raise QRCodeArgumentError, "Not a alpha numeric uppercase string `#{data}`" unless QRAlphanumeric.valid_data?(data)
|
12
|
+
|
13
|
+
@data = data;
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def get_length
|
18
|
+
@data.size
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.valid_data? data
|
22
|
+
data.each_char do |s|
|
23
|
+
return false if ALPHANUMERIC.index(s).nil?
|
24
|
+
end
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def write( buffer)
|
30
|
+
buffer.alphanumeric_encoding_start(get_length)
|
31
|
+
|
32
|
+
(@data.size).times do |i|
|
33
|
+
if i % 2 == 0
|
34
|
+
if i == (@data.size - 1)
|
35
|
+
value = ALPHANUMERIC.index(@data[i])
|
36
|
+
buffer.put( value, 6 )
|
37
|
+
else
|
38
|
+
value = (ALPHANUMERIC.index(@data[i]) * 45) + ALPHANUMERIC.index(@data[i+1])
|
39
|
+
buffer.put( value, 11 )
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Copyright 2004 by Duncan Robertson (duncan@whomwah.com).
|
5
|
+
# All rights reserved.
|
6
|
+
|
7
|
+
# Permission is granted for use, copying, modification, distribution,
|
8
|
+
# and distribution of modified versions of this work as long as the
|
9
|
+
# above copyright notice is included.
|
10
|
+
#++
|
11
|
+
|
12
|
+
module RQRCode
|
13
|
+
|
14
|
+
class QRBitBuffer
|
15
|
+
attr_reader :buffer
|
16
|
+
|
17
|
+
PAD0 = 0xEC
|
18
|
+
PAD1 = 0x11
|
19
|
+
|
20
|
+
def initialize(version)
|
21
|
+
@version = version
|
22
|
+
@buffer = []
|
23
|
+
@length = 0
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def get( index )
|
28
|
+
buf_index = (index / 8).floor
|
29
|
+
(( (@buffer[buf_index]).rszf(7 - index % 8)) & 1) == 1
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def put( num, length )
|
34
|
+
( 0...length ).each do |i|
|
35
|
+
put_bit((((num).rszf(length - i - 1)) & 1) == 1)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def get_length_in_bits
|
41
|
+
@length
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def put_bit( bit )
|
46
|
+
buf_index = ( @length / 8 ).floor
|
47
|
+
if @buffer.size <= buf_index
|
48
|
+
@buffer << 0
|
49
|
+
end
|
50
|
+
|
51
|
+
if bit
|
52
|
+
@buffer[buf_index] |= ((0x80).rszf(@length % 8))
|
53
|
+
end
|
54
|
+
|
55
|
+
@length += 1
|
56
|
+
end
|
57
|
+
|
58
|
+
def byte_encoding_start(length)
|
59
|
+
|
60
|
+
put( QRMODE[:mode_8bit_byte], 4 )
|
61
|
+
put(length, QRUtil.get_length_in_bits(QRMODE[:mode_8bit_byte], @version))
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
def alphanumeric_encoding_start(length)
|
66
|
+
|
67
|
+
put( QRMODE[:mode_alpha_numk], 4 )
|
68
|
+
put(length, QRUtil.get_length_in_bits(QRMODE[:mode_alpha_numk], @version))
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
def numeric_encoding_start(length)
|
73
|
+
|
74
|
+
put( QRMODE[:mode_number], 4 )
|
75
|
+
put(length, QRUtil.get_length_in_bits(QRMODE[:mode_number], @version))
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
def pad_until(prefered_size)
|
80
|
+
# Align on byte
|
81
|
+
while get_length_in_bits % 8 != 0
|
82
|
+
put_bit( false )
|
83
|
+
end
|
84
|
+
|
85
|
+
# Pad with padding code words
|
86
|
+
while get_length_in_bits < prefered_size
|
87
|
+
put( QRBitBuffer::PAD0, 8 )
|
88
|
+
put( QRBitBuffer::PAD1, 8 ) if get_length_in_bits < prefered_size
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def end_of_message(max_data_bits)
|
93
|
+
put( 0, 4 ) unless get_length_in_bits+4 > max_data_bits
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|