Skip to content

Commit a31821f

Browse files
committed
dotcode: Derive each mask's ECC from the unmasked message ECC
Reed-Solomon codes are linear over GF(113) and the DotCode mask is an additive combination of the mask codeword and a scaled ramp, so the ECC of each masked message is the ECC of the unmasked message plus scaled geometry-dependent mask component ECCs, which are kept in a FIFO cache. This replaces the per-mask Reed-Solomon passes with a single pass over the unmasked message and one cheap combine per mask.
1 parent 0bb649f commit a31821f

1 file changed

Lines changed: 115 additions & 29 deletions

File tree

src/dotcode.ps.src

Lines changed: 115 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,64 @@ begin
247247
//dotcode.coeffscache /fetch get exec
248248
} bind def
249249

250+
%
251+
% Generate the ECC codewords of the mask components for a given data capacity.
252+
% Reed-Solomon codes are linear over GF(113), so the ECC of a masked message
253+
% is the ECC of the unmasked message plus the ECC of the mask codeword and of
254+
% the mask ramp, scaled by the mask parameters. Both component vectors depend
255+
% only on the symbol geometry, which is fully derived from the data capacity.
256+
%
257+
/dotcode.genmaskecc {
258+
16 dict begin
259+
/nd exch def
260+
/nc nd 2 idiv 3 add def
261+
/nw nd nc add def
262+
/step nw 112 idiv 1 add def
263+
/e0vals nc array def
264+
/rampvals nc array def
265+
/k 0 def
266+
0 1 step 1 sub {
267+
/start exch def
268+
/ND nd 1 add start sub step add 1 sub step idiv def
269+
/NW nw 1 add start sub step add 1 sub step idiv def
270+
/NC NW ND sub def
271+
/coeffs NC //dotcode.coeffscachefetch exec def
272+
/lfsr NC array def
273+
{step mul start add 0 eq {1} {0} ifelse} ND coeffs lfsr 113 //rsecprime exec
274+
/lfsrramp NC array def
275+
{step mul start add dup 2 lt {pop 0} {1 sub 113 mod} ifelse} ND coeffs lfsrramp 113 //rsecprime exec
276+
0 1 NC 1 sub {
277+
/j exch def
278+
e0vals k j add lfsr j get put
279+
rampvals k j add lfsrramp j get put
280+
} for
281+
/k k NC add def
282+
} for
283+
[ e0vals readonly rampvals readonly ] readonly
284+
end
285+
} bind def
286+
287+
%
288+
% FIFO cache for mask component ECC codewords
289+
%
290+
/dotcode.maskecccachemax 10 def % Override with global_ctx.dotcode.maskecccachemax
291+
/dotcode.maskecccachelimit 10000 def % Override with global_ctx.dotcode.maskecccachelimit
292+
/uk.co.terryburton.bwipp.global_ctx dup where {
293+
exch get
294+
dup /dotcode.maskecccachemax 2 copy known {get /dotcode.maskecccachemax exch def} {pop pop} ifelse
295+
/dotcode.maskecccachelimit 2 copy known {get /dotcode.maskecccachelimit exch def} {pop pop} ifelse
296+
} {pop} ifelse
297+
298+
/dotcode.maskecccache dotcode.maskecccachemax dotcode.maskecccachelimit //fifocache exec def
299+
300+
/dotcode.maskecccachefetch {
301+
/nd exch def
302+
nd
303+
{ nd //dotcode.genmaskecc exec }
304+
{ aload pop length exch length add }
305+
//dotcode.maskecccache /fetch get exec
306+
} bind def
307+
250308
/dotcode {
251309

252310
128 dict begin
@@ -1185,46 +1243,74 @@ begin
11851243
scratch posx posy dmv 0 put
11861244
} for
11871245
(matrix.layout.walk) //dotcode.after exec
1246+
1247+
%
1248+
% Calculate the error correction codewords of the unmasked message once;
1249+
% each mask's ECC is later derived from these by adding the cached mask
1250+
% component ECC codewords, scaled by the mask parameters
1251+
%
1252+
(ecc.masks) //dotcode.before exec
1253+
/maskecc nd //dotcode.maskecccachefetch exec def
1254+
/e0vals maskecc 0 get def
1255+
/rampvals maskecc 1 get def
1256+
(ecc.masks) //dotcode.after exec
1257+
1258+
/rscws [ 0 cws aload pop nc {0} repeat ] def
1259+
/eccposs nc array def
1260+
/eccbase nc array def
1261+
/k 0 def
1262+
0 1 step 1 sub {
1263+
/start exch def
1264+
/ND nd 1 add start sub step add 1 sub step idiv def
1265+
/NW nw 1 add start sub step add 1 sub step idiv def
1266+
/NC NW ND sub def
1267+
1268+
(ecc.coeffs) //dotcode.before exec
1269+
/coeffs NC //dotcode.coeffscachefetch exec def
1270+
(ecc.coeffs) //dotcode.after exec
1271+
1272+
(ecc.cws) //dotcode.before exec
1273+
1274+
%
1275+
% Compute ECC via the shared rsecprime helper. Data lives at
1276+
% interleaved positions rscws[offset(0..ND-1)]. The helper leaves
1277+
% codewords in the spec's negated form in lfsr[0..NC), so no
1278+
% post-pass is needed.
1279+
%
1280+
/lfsr NC array def
1281+
{step mul start add rscws exch get} ND coeffs lfsr 113 //rsecprime exec
1282+
0 1 NC 1 sub {
1283+
/j exch def
1284+
eccposs k j add ND j add offset put
1285+
eccbase k j add lfsr j get put
1286+
} for
1287+
/k k NC add def
1288+
1289+
(ecc.cws) //dotcode.after exec
1290+
1291+
} for
11881292
masks { % For each mask pattern
11891293

11901294
/mask exch def
11911295

11921296
%
1193-
% Calculate the error correction codewords for each block
1297+
% Mask the message and combine the unmasked message ECC with the
1298+
% scaled mask component ECC codewords
11941299
%
1300+
(ecc.cws) //dotcode.before exec
1301+
/mv //dotcode.maskvals mask get def
11951302
/rscws [
11961303
mask
1197-
//dotcode.maskvals mask get 0 cws {1 index add 113 mod exch 2 index add exch 3 1 roll} forall pop pop
1304+
mv 0 cws {1 index add 113 mod exch 2 index add exch 3 1 roll} forall pop pop
11981305
nc {0} repeat
11991306
] def
1200-
0 1 step 1 sub {
1201-
/start exch def
1202-
/ND nd 1 add start sub step add 1 sub step idiv def
1203-
/NW nw 1 add start sub step add 1 sub step idiv def
1204-
/NC NW ND sub def
1205-
1206-
(ecc.coeffs) //dotcode.before exec
1207-
/coeffs NC //dotcode.coeffscachefetch exec def
1208-
(ecc.coeffs) //dotcode.after exec
1209-
1210-
(ecc.cws) //dotcode.before exec
1211-
1212-
%
1213-
% Compute ECC via the shared rsecprime helper. Data lives at
1214-
% interleaved positions rscws[offset(0..ND-1)]; ECC goes back to
1215-
% rscws[offset(ND..NW-1)]. The helper leaves codewords in the
1216-
% spec's negated form in lfsr[0..NC), so no post-pass is needed.
1217-
%
1218-
/lfsr NC array def
1219-
{step mul start add rscws exch get} ND coeffs lfsr 113 //rsecprime exec
1220-
0 1 NC 1 sub {
1221-
/j exch def
1222-
rscws ND j add offset lfsr j get put
1223-
} for
1224-
1225-
(ecc.cws) //dotcode.after exec
1226-
1307+
0 1 nc 1 sub {
1308+
/j exch def
1309+
rscws eccposs j get
1310+
eccbase j get mask e0vals j get mul add mv rampvals j get mul add 113 mod
1311+
put
12271312
} for
1313+
(ecc.cws) //dotcode.after exec
12281314

12291315
options /debugecc known
12301316
/uk.co.terryburton.bwipp.global_ctx dup where {exch get /enabledebug known} {pop false} ifelse

0 commit comments

Comments
 (0)