@moralcode/qrcode-brightscript 0.1.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.
- package/LICENSE.txt +21 -0
- package/README.md +33 -0
- package/package.json +17 -0
- package/src/components/qrCode/qrCode.brs +201 -0
- package/src/components/qrCode/qrCode.draw.brs +126 -0
- package/src/components/qrCode/qrCode.help.brs +148 -0
- package/src/components/qrCode/qrCode.high.brs +20 -0
- package/src/components/qrCode/qrCode.low.brs +68 -0
- package/src/components/qrCode/qrCode.mask.brs +198 -0
- package/src/components/qrCode/qrCode.mid.brs +76 -0
- package/src/components/qrCode/qrCode.utils.brs +110 -0
- package/src/components/qrCode/qrCode.xml +25 -0
- package/src/components/qrCode/qrEcc.brs +23 -0
- package/src/components/qrCode/qrEcc.xml +10 -0
- package/src/components/qrCode/qrMode.brs +37 -0
- package/src/components/qrCode/qrMode.xml +11 -0
- package/src/components/qrCode/qrSegment.brs +226 -0
- package/src/images/focus_fhd.jpg +0 -0
- package/src/images/focus_hd.jpg +0 -0
- package/src/images/focus_sd.jpg +0 -0
- package/src/images/splash_fhd.jpg +0 -0
- package/src/images/splash_hd.jpg +0 -0
- package/src/images/splash_sd.jpg +0 -0
- package/src/manifest +17 -0
- package/src/source/main.brs +23 -0
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Paramount
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# QR-Code-generator-brightscript
|
|
2
|
+
|
|
3
|
+
## Introduction:
|
|
4
|
+
|
|
5
|
+
With this Library, adding a QR code to your Roku app is a simple as including this in your xml file:
|
|
6
|
+
|
|
7
|
+
\<qrCode text="https://www.paramountplus.com/" />
|
|
8
|
+
|
|
9
|
+
## License
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2022 Paramount (MIT License)
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
|
30
|
+
|
|
31
|
+
## Attribution
|
|
32
|
+
|
|
33
|
+
This work, ["QR-Code-generator-brightscript"](https://github.com/paramount-engineering/QR-Code-generator-brightscript), is a derivative of ["QR Code generator"](https://github.com/nayuki/QR-Code-generator) by [Project Nayuki](https://www.nayuki.io/page/qr-code-generator-library), used under [MIT](https://choosealicense.com/licenses/mit/). ["QR-Code-generator-brightscript"](https://github.com/paramount-engineering/QR-Code-generator-brightscript) is licensed under [MIT](https://choosealicense.com/licenses/mit/) BY [Paramount](https://www.paramount.com).
|
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@moralcode/qrcode-brightscript",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A Roku component that can generate QR codes",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ropm",
|
|
7
|
+
"roku",
|
|
8
|
+
"brightscript",
|
|
9
|
+
"brighterscript"
|
|
10
|
+
],
|
|
11
|
+
"files": [
|
|
12
|
+
"src/**/*"
|
|
13
|
+
],
|
|
14
|
+
"ropm": {
|
|
15
|
+
"rootDir": "src"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
'**************************************************************************************
|
|
2
|
+
' QR Code generator library (Brightscript)
|
|
3
|
+
' Copyright (c) Kevin Hoos.
|
|
4
|
+
'**************************************************************************************
|
|
5
|
+
' Ported from:
|
|
6
|
+
' Copyright (c) Project Nayuki. (MIT License)
|
|
7
|
+
' https://www.nayuki.io/page/qr-code-generator-library
|
|
8
|
+
'
|
|
9
|
+
' Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
10
|
+
' this software and associated documentation files (the "Software"), to deal in
|
|
11
|
+
' the Software without restriction, including without limitation the rights to
|
|
12
|
+
' use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
13
|
+
' the Software, and to permit persons to whom the Software is furnished to do so,
|
|
14
|
+
' subject to the following conditions:
|
|
15
|
+
' - The above copyright notice and this permission notice shall be included in
|
|
16
|
+
' all copies or substantial portions of the Software.
|
|
17
|
+
' - The Software is provided "as is", without warranty of any kind, express or
|
|
18
|
+
' implied, including but not limited to the warranties of merchantability,
|
|
19
|
+
' fitness for a particular purpose and noninfringement. In no event shall the
|
|
20
|
+
' authors or copyright holders be liable for any claim, damages or other
|
|
21
|
+
' liability, whether in an action of contract, tort or otherwise, arising from,
|
|
22
|
+
' out of or in connection with the Software or the use or other dealings in the
|
|
23
|
+
' Software.
|
|
24
|
+
'**************************************************************************************
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
'---- QR Code symbol class ----
|
|
28
|
+
|
|
29
|
+
'**************************************************************************************
|
|
30
|
+
' A QR Code symbol, which is a type of two-dimension barcode.
|
|
31
|
+
' Invented by Denso Wave and described in the ISO/IEC 18004 standard.
|
|
32
|
+
' Instances of this class represent an immutable square grid of dark and light cells.
|
|
33
|
+
' The class provides static factory functions to create a QR Code from text or binary data.
|
|
34
|
+
' The class covers the QR Code Model 2 specification, supporting all versions (sizes)
|
|
35
|
+
' from 1 to 40, all 4 error correction levels, and 4 character encoding modes.
|
|
36
|
+
'
|
|
37
|
+
' Ways to create a QR Code object:
|
|
38
|
+
' - High level: Take the payload data and call QrCode.encodeText() or QrCode.encodeBinary().
|
|
39
|
+
' - Mid level: Custom-make the list of segments and call QrCode.encodeSegments().
|
|
40
|
+
' - Low level: Custom-make the array of data codeword bytes (including
|
|
41
|
+
' segment headers and final padding, excluding error correction codewords),
|
|
42
|
+
' supply the appropriate version number, and call the QrCode() constructor.
|
|
43
|
+
' (Note that all ways require supplying the desired error correction level.)
|
|
44
|
+
'**************************************************************************************
|
|
45
|
+
function QrCode()
|
|
46
|
+
this = {}
|
|
47
|
+
'-- Static factory functions (high level) --
|
|
48
|
+
this.encodeText = _qrCode_high_encodeText
|
|
49
|
+
this.encodeBinary = _qrCode_high_encodeBinary
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
'-- Static factory functions (mid level) --
|
|
53
|
+
this.encodeSegments = _qrCode_mid_encodeSegments
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
'-- Fields --
|
|
57
|
+
|
|
58
|
+
' The width and height of this QR Code, measured in modules, between
|
|
59
|
+
' 21 and 177 (inclusive). This is equal to version * 4 + 17.
|
|
60
|
+
this.size = 0
|
|
61
|
+
|
|
62
|
+
' The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive).
|
|
63
|
+
' Even if a QR Code is created with automatic masking requested (mask = -1),
|
|
64
|
+
' the resulting object still has a mask value between 0 and 7.
|
|
65
|
+
this.mask = -1
|
|
66
|
+
|
|
67
|
+
' The modules of this QR Code (false = light, true = dark).
|
|
68
|
+
' Immutable after constructor finishes. Accessed through getModule().
|
|
69
|
+
this.modules = []
|
|
70
|
+
|
|
71
|
+
' Indicates function modules that are not subjected to masking. Discarded when constructor finishes.
|
|
72
|
+
this.isFunction = []
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
'-- Constructor (low level) and fields --
|
|
76
|
+
this.constructor = _qrCode_low_constructor
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
'-- Accessor methods --
|
|
80
|
+
this.getModule = _qrCode_low_getModule
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
'-- Private helper methods for constructor: Drawing function modules --
|
|
84
|
+
this.drawFunctionPatterns = _qrCode_draw_drawFunctionPatterns
|
|
85
|
+
this.drawFormatBits = _qrCode_draw_drawFormatBits
|
|
86
|
+
this.drawVersion = _qrCode_draw_drawVersion
|
|
87
|
+
this.drawFinderPattern = _qrCode_draw_drawFinderPattern
|
|
88
|
+
this.drawAlignmentPattern = _qrCode_draw_drawAlignmentPattern
|
|
89
|
+
this.setFunctionModule = _qrCode_draw_setFunctionModule
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
'-- Private helper methods for constructor: Codewords and masking --
|
|
93
|
+
this.addEccAndInterleave = _qrCode_mask_addEccAndInterleave
|
|
94
|
+
this.drawCodewords = _qrCode_mask_drawCodewords
|
|
95
|
+
this.applyMask = _qrCode_mask_applyMask
|
|
96
|
+
this.getPenaltyScore = _qrCode_mask_getPenaltyScore
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
'-- Private helper functions --
|
|
100
|
+
this.getAlignmentPatternPositions = _qrCode_help_getAlignmentPatternPositions
|
|
101
|
+
this.getNumRawDataModules = _qrCode_help_getNumRawDataModules
|
|
102
|
+
this.getNumDataCodewords = _qrCode_help_getNumDataCodewords
|
|
103
|
+
this.reedSolomonComputeDivisor = _qrCode_help_reedSolomonComputeDivisor
|
|
104
|
+
this.reedSolomonComputeRemainder = _qrCode_help_reedSolomonComputeRemainder
|
|
105
|
+
this.reedSolomonMultiply = _qrCode_help_reedSolomonMultiply
|
|
106
|
+
this.finderPenaltyCountPatterns = _qrCode_help_finderPenaltyCountPatterns
|
|
107
|
+
this.finderPenaltyTerminateAndCount = _qrCode_help_finderPenaltyTerminateAndCount
|
|
108
|
+
this.finderPenaltyAddHistory = _qrCode_help_finderPenaltyAddHistory
|
|
109
|
+
|
|
110
|
+
this.QrSegment = QrSegment()
|
|
111
|
+
this.Ecc = []
|
|
112
|
+
levels = ["LOW", "MEDIUM", "QUARTILE", "HIGH"]
|
|
113
|
+
for each level in levels
|
|
114
|
+
ecc = CreateObject("roSGNode", "QREcc")
|
|
115
|
+
ecc.level = level
|
|
116
|
+
this.Ecc.push(ecc)
|
|
117
|
+
next
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
'-- Constants and tables --
|
|
121
|
+
|
|
122
|
+
' The minimum version number supported in the QR Code Model 2 standard.
|
|
123
|
+
this.MIN_VERSION = 1
|
|
124
|
+
' The maximum version number supported in the QR Code Model 2 standard.
|
|
125
|
+
this.MAX_VERSION = 40
|
|
126
|
+
|
|
127
|
+
' For use in getPenaltyScore(), when evaluating which mask is best.
|
|
128
|
+
this.PENALTY_N1 = 3
|
|
129
|
+
this.PENALTY_N2 = 3
|
|
130
|
+
this.PENALTY_N3 = 40
|
|
131
|
+
this.PENALTY_N4 = 10
|
|
132
|
+
|
|
133
|
+
this.ECC_CODEWORDS_PER_BLOCK = [
|
|
134
|
+
' Version: (note that index 0 is for padding, and is set to an illegal value)
|
|
135
|
+
'0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
|
|
136
|
+
[-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30], ' Low
|
|
137
|
+
[-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28], ' Medium
|
|
138
|
+
[-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30], ' Quartile
|
|
139
|
+
[-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30], ' High
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
this.NUM_ERROR_CORRECTION_BLOCKS = [
|
|
143
|
+
' Version: (note that index 0 is for padding, and is set to an illegal value)
|
|
144
|
+
'0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
|
|
145
|
+
[-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25], ' Low
|
|
146
|
+
[-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49], ' Medium
|
|
147
|
+
[-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68], ' Quartile
|
|
148
|
+
[-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81], ' High
|
|
149
|
+
]
|
|
150
|
+
|
|
151
|
+
return this
|
|
152
|
+
end function
|
|
153
|
+
|
|
154
|
+
function onTextChanged(nodeEvent)
|
|
155
|
+
time = createObject("roTimespan")
|
|
156
|
+
text = nodeEvent.getData()
|
|
157
|
+
qr = QrCode()
|
|
158
|
+
ecl = getEcl()
|
|
159
|
+
qr.encodeText(text, ecl)
|
|
160
|
+
ba = CreateObject("roByteArray")
|
|
161
|
+
ba.FromAsciiString(text)
|
|
162
|
+
digest = CreateObject("roEVPDigest")
|
|
163
|
+
digest.Setup("sha1")
|
|
164
|
+
sha1 = digest.Process(ba)
|
|
165
|
+
renderCode(qr, "tmp:/" + sha1 + ".png")
|
|
166
|
+
?"Time:", time.totalMilliseconds(), text
|
|
167
|
+
end function
|
|
168
|
+
|
|
169
|
+
function getEcl()
|
|
170
|
+
ecl = CreateObject("roSGNode", "QREcc")
|
|
171
|
+
ecl.level = "LOW"
|
|
172
|
+
if not isNullOrEmpty(m.top.ecl) then
|
|
173
|
+
ecl.level = uCase(m.top.ecl)
|
|
174
|
+
end if
|
|
175
|
+
return ecl
|
|
176
|
+
end function
|
|
177
|
+
|
|
178
|
+
sub renderCode(qr as object, filename as string)
|
|
179
|
+
border = m.top.border
|
|
180
|
+
pixel = m.top.pixel
|
|
181
|
+
lightColor = m.top.lightColor
|
|
182
|
+
darkColor = m.top.darkColor
|
|
183
|
+
size = qr.size
|
|
184
|
+
imageSide = ((border * 2) + size) * pixel
|
|
185
|
+
|
|
186
|
+
bm = CreateObject("roBitmap", { width: imageSide, height: imageSide, AlphaEnable: true })
|
|
187
|
+
if bm <> invalid then
|
|
188
|
+
bm.DrawRect(0, 0, imageSide, imageSide, lightColor)
|
|
189
|
+
for y = 0 to size - 1
|
|
190
|
+
for x = 0 to size - 1
|
|
191
|
+
if qr.modules[y][x] = 1 then
|
|
192
|
+
bm.DrawRect((border + x) * pixel, (border + y) * pixel, pixel, pixel, darkColor)
|
|
193
|
+
end if
|
|
194
|
+
next
|
|
195
|
+
next
|
|
196
|
+
bm.Finish()
|
|
197
|
+
ba = bm.GetPng(0, 0, imageSide, imageSide)
|
|
198
|
+
ba.WriteFile(filename)
|
|
199
|
+
m.top.uri = filename
|
|
200
|
+
end if
|
|
201
|
+
end sub
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
'-- Private helper methods for constructor: Drawing function modules --
|
|
2
|
+
|
|
3
|
+
' Reads this object's version field, and draws and marks all function modules.
|
|
4
|
+
function _qrCode_draw_drawFunctionPatterns()
|
|
5
|
+
' Draw horizontal and vertical timing patterns
|
|
6
|
+
for i = 0 to m.size - 1
|
|
7
|
+
m.setFunctionModule(6, i, i MOD 2 = 0)
|
|
8
|
+
m.setFunctionModule(i, 6, i MOD 2 = 0)
|
|
9
|
+
next
|
|
10
|
+
|
|
11
|
+
' Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
|
|
12
|
+
m.drawFinderPattern(3, 3)
|
|
13
|
+
m.drawFinderPattern(m.size - 4, 3)
|
|
14
|
+
m.drawFinderPattern(3, m.size - 4)
|
|
15
|
+
|
|
16
|
+
' Draw numerous alignment patterns
|
|
17
|
+
alignPatPos = m.getAlignmentPatternPositions()
|
|
18
|
+
numAlign = alignPatPos.count()
|
|
19
|
+
for i = 0 to numAlign - 1
|
|
20
|
+
for j = 0 to numAlign - 1
|
|
21
|
+
' Don't draw on the three finder corners
|
|
22
|
+
if (not ((i = 0) and (j = 0) or (i = 0) and (j = numAlign - 1) or (i = numAlign - 1) and (j = 0))) then
|
|
23
|
+
m.drawAlignmentPattern(alignPatPos[i], alignPatPos[j])
|
|
24
|
+
end if
|
|
25
|
+
next
|
|
26
|
+
next
|
|
27
|
+
|
|
28
|
+
' Draw configuration data
|
|
29
|
+
m.drawFormatBits(0) ' Dummy mask value; overwritten later in the constructor
|
|
30
|
+
m.drawVersion()
|
|
31
|
+
end function
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
' Draws two copies of the format bits (with its own error correction code)
|
|
35
|
+
' based on the given mask and this object's error correction level field.
|
|
36
|
+
function _qrCode_draw_drawFormatBits(mask as integer)
|
|
37
|
+
' Calculate error correction code and pack bits
|
|
38
|
+
data = m.errorCorrectionLevel.formatBits << 3 or mask ' errCorrLvl is uint2, mask is uint3
|
|
39
|
+
remain = data
|
|
40
|
+
for i = 0 to 9
|
|
41
|
+
remain = xor((remain << 1), (remain >> 9) * &h537)
|
|
42
|
+
next
|
|
43
|
+
bits = xor((data << 10 or remain), &h5412) ' uint15
|
|
44
|
+
assert(bits >> 15 = 0)
|
|
45
|
+
|
|
46
|
+
' Draw first copy
|
|
47
|
+
for i = 0 to 5
|
|
48
|
+
m.setFunctionModule(8, i, getBit(bits, i))
|
|
49
|
+
next
|
|
50
|
+
m.setFunctionModule(8, 7, getBit(bits, 6))
|
|
51
|
+
m.setFunctionModule(8, 8, getBit(bits, 7))
|
|
52
|
+
m.setFunctionModule(7, 8, getBit(bits, 8))
|
|
53
|
+
for i = 9 to 14
|
|
54
|
+
m.setFunctionModule(14 - i, 8, getBit(bits, i))
|
|
55
|
+
next
|
|
56
|
+
|
|
57
|
+
' Draw second copy
|
|
58
|
+
for i = 0 to 7
|
|
59
|
+
m.setFunctionModule(m.size - 1 - i, 8, getBit(bits, i))
|
|
60
|
+
next
|
|
61
|
+
for i = 8 to 14
|
|
62
|
+
m.setFunctionModule(8, m.size - 15 + i, getBit(bits, i))
|
|
63
|
+
next
|
|
64
|
+
m.setFunctionModule(8, m.size - 8, true) ' Always dark
|
|
65
|
+
end function
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
' Draws two copies of the version bits (with its own error correction code),
|
|
69
|
+
' based on this object's version field, iff 7 <= version <= 40.
|
|
70
|
+
function _qrCode_draw_drawVersion()
|
|
71
|
+
if (m.version < 7) then
|
|
72
|
+
return false
|
|
73
|
+
end if
|
|
74
|
+
|
|
75
|
+
' Calculate error correction code and pack bits
|
|
76
|
+
remain = m.version ' version is uint6, in the range [7, 40]
|
|
77
|
+
for i = 0 to 11
|
|
78
|
+
remain = xor((remain << 1), (remain >> 11) * &h1F25)
|
|
79
|
+
next
|
|
80
|
+
bits = m.version << 12 or remain ' uint18
|
|
81
|
+
assert(bits >> 18 = 0)
|
|
82
|
+
|
|
83
|
+
' Draw two copies
|
|
84
|
+
for i = 0 to 17
|
|
85
|
+
color = getBit(bits, i)
|
|
86
|
+
a = m.size - 11 + i MOD 3
|
|
87
|
+
b = floor(i / 3)
|
|
88
|
+
m.setFunctionModule(a, b, color)
|
|
89
|
+
m.setFunctionModule(b, a, color)
|
|
90
|
+
next
|
|
91
|
+
end function
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
' Draws a 9*9 finder pattern including the border separator,
|
|
95
|
+
' with the center module at (x, y). Modules can be out of bounds.
|
|
96
|
+
function _qrCode_draw_drawFinderPattern(x as integer, y as integer)
|
|
97
|
+
for dy = -4 to 4
|
|
98
|
+
for dx = -4 to 4
|
|
99
|
+
dist = max(abs(dx), abs(dy)) ' Chebyshev/infinity norm
|
|
100
|
+
xx = x + dx
|
|
101
|
+
yy = y + dy
|
|
102
|
+
if ((0 <= xx) and (xx < m.size) and (0 <= yy) and (yy < m.size)) then
|
|
103
|
+
m.setFunctionModule(xx, yy, (dist <> 2) and (dist <> 4))
|
|
104
|
+
end if
|
|
105
|
+
next
|
|
106
|
+
next
|
|
107
|
+
end function
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
' Draws a 5*5 alignment pattern, with the center module
|
|
111
|
+
' at (x, y). All modules must be in bounds.
|
|
112
|
+
function _qrCode_draw_drawAlignmentPattern(x as integer, y as integer)
|
|
113
|
+
for dy = -2 to 2
|
|
114
|
+
for dx = -2 to 2
|
|
115
|
+
m.setFunctionModule(x + dx, y + dy, max(abs(dx), abs(dy)) <> 1)
|
|
116
|
+
next
|
|
117
|
+
next
|
|
118
|
+
end function
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
' Sets the color of a module and marks it as a function module.
|
|
122
|
+
' Only used by the constructor. Coordinates must be in bounds.
|
|
123
|
+
function _qrCode_draw_setFunctionModule(x as integer, y as integer, isDark as boolean)
|
|
124
|
+
m.modules[y][x] = iif(isDark, 1, 0)
|
|
125
|
+
m.isFunction[y][x] = true
|
|
126
|
+
end function
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
'-- Private helper functions --
|
|
2
|
+
|
|
3
|
+
' Returns an ascending list of positions of alignment patterns for this version number.
|
|
4
|
+
' Each position is in the range [0,177), and are used on both the x and y axes.
|
|
5
|
+
' This could be implemented as lookup table of 40 variable-length lists of integers.
|
|
6
|
+
function _qrCode_help_getAlignmentPatternPositions() as object
|
|
7
|
+
if (m.version = 1) then
|
|
8
|
+
return []
|
|
9
|
+
else
|
|
10
|
+
numAlign = floor(m.version / 7) + 2
|
|
11
|
+
stepSize = iif(m.version = 32, 26, ceil((m.version * 4 + 4) / (numAlign * 2 - 2)) * 2)
|
|
12
|
+
result = []
|
|
13
|
+
position = m.size - 7
|
|
14
|
+
while(result.count() < numAlign)
|
|
15
|
+
result.unshift(position)
|
|
16
|
+
position -= stepSize
|
|
17
|
+
end while
|
|
18
|
+
return result
|
|
19
|
+
end if
|
|
20
|
+
end function
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
' Returns the number of data bits that can be stored in a QR Code of the given version number, after
|
|
24
|
+
' all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
|
|
25
|
+
' The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
|
|
26
|
+
function _qrCode_help_getNumRawDataModules(ver as integer) as integer
|
|
27
|
+
if ((ver < m.MIN_VERSION) or (ver > m.MAX_VERSION)) then
|
|
28
|
+
throw("Version number out of range")
|
|
29
|
+
end if
|
|
30
|
+
result = (16 * ver + 128) * ver + 64
|
|
31
|
+
if (ver >= 2) then
|
|
32
|
+
numAlign = floor(ver / 7) + 2
|
|
33
|
+
result -= (25 * numAlign - 10) * numAlign - 55
|
|
34
|
+
if (ver >= 7) then
|
|
35
|
+
result -= 36
|
|
36
|
+
end if
|
|
37
|
+
end if
|
|
38
|
+
assert((208 <= result) and (result <= 29648))
|
|
39
|
+
return result
|
|
40
|
+
end function
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
' Returns the number of 8-bit data (i.e. not error correction) codewords contained in any
|
|
44
|
+
' QR Code of the given version number and error correction level, with remainder bits discarded.
|
|
45
|
+
' This stateless pure function could be implemented as a (40*4)-cell lookup table.
|
|
46
|
+
function _qrCode_help_getNumDataCodewords(ver as integer, ecl as object) as integer
|
|
47
|
+
return floor(m.getNumRawDataModules(ver) / 8) - m.ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver] * m.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver]
|
|
48
|
+
end function
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
' Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be
|
|
52
|
+
' implemented as a lookup table over all possible parameter values, instead of as an algorithm.
|
|
53
|
+
function _qrCode_help_reedSolomonComputeDivisor(degree as integer) as object
|
|
54
|
+
if ((degree < 1) or (degree > 255)) then
|
|
55
|
+
throw("Degree out of range")
|
|
56
|
+
end if
|
|
57
|
+
' Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1.
|
|
58
|
+
' For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array [255, 8, 93].
|
|
59
|
+
result = []
|
|
60
|
+
for i = 0 to degree - 2
|
|
61
|
+
result.push(0)
|
|
62
|
+
next
|
|
63
|
+
result.push(1) ' Start off with the monomial x^0
|
|
64
|
+
|
|
65
|
+
' Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
|
|
66
|
+
' and drop the highest monomial term which is always 1x^degree.
|
|
67
|
+
' Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
|
|
68
|
+
root = 1
|
|
69
|
+
for i = 0 to degree - 1
|
|
70
|
+
' Multiply the current product by (x - r^i)
|
|
71
|
+
for j = 0 to result.count() - 1
|
|
72
|
+
result[j] = m.reedSolomonMultiply(result[j], root)
|
|
73
|
+
if (j + 1 < result.count()) then
|
|
74
|
+
result[j] = xor(result[j], result[j + 1])
|
|
75
|
+
end if
|
|
76
|
+
next
|
|
77
|
+
root = m.reedSolomonMultiply(root, &h02)
|
|
78
|
+
next
|
|
79
|
+
return result
|
|
80
|
+
end function
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
' Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials.
|
|
84
|
+
function _qrCode_help_reedSolomonComputeRemainder(data as object, divisor as object) as object
|
|
85
|
+
result = []
|
|
86
|
+
for each _d in divisor ' Prefix d with underscore to avoid unused variable warning
|
|
87
|
+
result.push(0)
|
|
88
|
+
next
|
|
89
|
+
for each b in data ' Polynomial division
|
|
90
|
+
factor = xor(b, result.shift())
|
|
91
|
+
result.push(0)
|
|
92
|
+
for i = 0 to divisor.count() - 1
|
|
93
|
+
coef = divisor[i]
|
|
94
|
+
res = result[i]
|
|
95
|
+
result[i] = xor(res, m.reedSolomonMultiply(coef, factor))
|
|
96
|
+
next
|
|
97
|
+
next
|
|
98
|
+
return result
|
|
99
|
+
end function
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
' Returns the product of the two given field elements modulo GF(2^8/0x11D). The arguments and result
|
|
103
|
+
' are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8.
|
|
104
|
+
function _qrCode_help_reedSolomonMultiply(x as integer, y as integer) as integer
|
|
105
|
+
if ((x >> 8 <> 0) or (y >> 8 <> 0)) then
|
|
106
|
+
throw("Byte out of range")
|
|
107
|
+
end if
|
|
108
|
+
' Russian peasant multiplication
|
|
109
|
+
z = 0
|
|
110
|
+
for i = 7 to 0 step -1
|
|
111
|
+
z = xor((z << 1), ((z >> 7) * &h11D))
|
|
112
|
+
z = xor(z, ((y >> i) and 1) * x)
|
|
113
|
+
next
|
|
114
|
+
assert(z >> 8 = 0)
|
|
115
|
+
return z
|
|
116
|
+
end function
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
' Can only be called immediately after a light run is added, and
|
|
120
|
+
' returns either 0, 1, or 2. A helper function for getPenaltyScore().
|
|
121
|
+
function _qrCode_help_finderPenaltyCountPatterns(runHistory as object) as integer
|
|
122
|
+
n = runHistory[1]
|
|
123
|
+
assert(n <= m.size * 3)
|
|
124
|
+
core = iif((n > 0) and (runHistory[2] = n) and (runHistory[3] = n * 3) and (runHistory[4] = n) and (runHistory[5] = n), 1, 0)
|
|
125
|
+
return (core and iif(runHistory[0] >= n * 4, 1, 0) and iif(runHistory[6] >= n, 1, 0)) + (core and iif(runHistory[6] >= n * 4, 1, 0) and iif(runHistory[0] >= n, 1, 0))
|
|
126
|
+
end function
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
' Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore().
|
|
130
|
+
function _qrCode_help_finderPenaltyTerminateAndCount(currentRunColor as boolean, currentRunLength as integer, runHistory as object) as integer
|
|
131
|
+
if (currentRunColor) then ' Terminate dark run
|
|
132
|
+
m.finderPenaltyAddHistory(currentRunLength, runHistory)
|
|
133
|
+
currentRunLength = 0
|
|
134
|
+
end if
|
|
135
|
+
currentRunLength += m.size ' Add light border to final run
|
|
136
|
+
m.finderPenaltyAddHistory(currentRunLength, runHistory)
|
|
137
|
+
return m.finderPenaltyCountPatterns(runHistory)
|
|
138
|
+
end function
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
' Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore().
|
|
142
|
+
function _qrCode_help_finderPenaltyAddHistory(currentRunLength as integer, runHistory as object)
|
|
143
|
+
if (runHistory[0] = 0)
|
|
144
|
+
currentRunLength += m.size ' Add light border to initial run
|
|
145
|
+
end if
|
|
146
|
+
runHistory.pop()
|
|
147
|
+
runHistory.unshift(currentRunLength)
|
|
148
|
+
end function
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'-- Static factory functions (high level) --
|
|
2
|
+
|
|
3
|
+
' Returns a QR Code representing the given Unicode text string at the given error correction level.
|
|
4
|
+
' As a conservative upper bound, this function is guaranteed to succeed for strings that have 738 or fewer
|
|
5
|
+
' Unicode code points (not UTF-16 code units) if the low error correction level is used. The smallest possible
|
|
6
|
+
' QR Code version is automatically chosen for the output. The ECC level of the result may be higher than the
|
|
7
|
+
' ecl argument if it can be done without increasing the version.
|
|
8
|
+
function _qrCode_high_encodeText(text as string, ecl as object) as object
|
|
9
|
+
segs = m.QrSegment.makeSegments(text)
|
|
10
|
+
return m.encodeSegments(segs, ecl)
|
|
11
|
+
end function
|
|
12
|
+
|
|
13
|
+
' Returns a QR Code representing the given binary data at the given error correction level.
|
|
14
|
+
' This function always encodes using the binary segment mode, not any text mode. The maximum number of
|
|
15
|
+
' bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
|
|
16
|
+
' The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
|
|
17
|
+
function _qrCode_high_encodeBinary(data as object, ecl as object) as object
|
|
18
|
+
seg = m.QrSegment.makeBytes(data)
|
|
19
|
+
return m.encodeSegments([seg], ecl)
|
|
20
|
+
end function
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'-- Constructor (low level) and fields --
|
|
2
|
+
|
|
3
|
+
' Creates a new QR Code with the given version number,
|
|
4
|
+
' error correction level, data codeword bytes, and mask number.
|
|
5
|
+
' This is a low - level API that most users should not use directly.
|
|
6
|
+
' A mid - level API is the encodeSegments() function.
|
|
7
|
+
function _qrCode_low_constructor(version as integer, errorCorrectionLevel as object, dataCodewords as object, msk as integer)
|
|
8
|
+
' The version number of this QR Code, which is between 1 and 40 (inclusive).
|
|
9
|
+
' This determines the size of this barcode.
|
|
10
|
+
m.version = version
|
|
11
|
+
|
|
12
|
+
' The error correction level used in this QR Code.
|
|
13
|
+
m.errorCorrectionLevel = errorCorrectionLevel
|
|
14
|
+
|
|
15
|
+
' Check scalar arguments
|
|
16
|
+
if ((version < m.MIN_VERSION) or (version > m.MAX_VERSION)) then
|
|
17
|
+
throw("Version value out of range")
|
|
18
|
+
end if
|
|
19
|
+
if ((msk < -1) or (msk > 7)) then
|
|
20
|
+
throw("Mask value out of range")
|
|
21
|
+
end if
|
|
22
|
+
m.size = version * 4 + 17
|
|
23
|
+
|
|
24
|
+
' Initialize both grids to be size * size arrays of boolean false
|
|
25
|
+
for y = 0 to m.size - 1
|
|
26
|
+
m.modules[y] = []
|
|
27
|
+
m.isFunction[y] = []
|
|
28
|
+
for x = 0 to m.size - 1
|
|
29
|
+
m.modules[y][x] = 0 ' Initially all light
|
|
30
|
+
m.isFunction[y][x] = false
|
|
31
|
+
next
|
|
32
|
+
next
|
|
33
|
+
|
|
34
|
+
' Compute ECC, draw modules
|
|
35
|
+
m.drawFunctionPatterns()
|
|
36
|
+
allCodewords = m.addEccAndInterleave(dataCodewords)
|
|
37
|
+
m.drawCodewords(allCodewords)
|
|
38
|
+
|
|
39
|
+
' Do masking
|
|
40
|
+
if (msk = -1) then ' Automatically choose best mask
|
|
41
|
+
minPenalty = 1000000000
|
|
42
|
+
for i = 0 to 7
|
|
43
|
+
m.applyMask(i)
|
|
44
|
+
m.drawFormatBits(i)
|
|
45
|
+
penalty = m.getPenaltyScore()
|
|
46
|
+
if (penalty < minPenalty) then
|
|
47
|
+
msk = i
|
|
48
|
+
minPenalty = penalty
|
|
49
|
+
end if
|
|
50
|
+
m.applyMask(i) ' Undoes the mask due to XOR
|
|
51
|
+
next
|
|
52
|
+
end if
|
|
53
|
+
assert((0 <= msk) and (msk <= 7))
|
|
54
|
+
m.mask = msk
|
|
55
|
+
m.applyMask(msk) ' Apply the final choice of mask
|
|
56
|
+
m.drawFormatBits(msk) ' Overwrite old format bits
|
|
57
|
+
|
|
58
|
+
m.isFunction = []
|
|
59
|
+
end function
|
|
60
|
+
|
|
61
|
+
'-- Accessor methods --
|
|
62
|
+
|
|
63
|
+
' Returns the color of the module (pixel) at the given coordinates, which is false
|
|
64
|
+
' for light or true for dark. The top left corner has the coordinates (x = 0, y = 0).
|
|
65
|
+
' if the given coordinates are out of bounds, then false (light) is returned.
|
|
66
|
+
function _qrCode_low_getModule(x as integer, y as integer) as boolean
|
|
67
|
+
return (0 <= x) and (x < m.size) and (0 <= y) and (y < m.size) and m.modules[y][x]
|
|
68
|
+
end function
|