@@ -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