@@ -890,32 +890,50 @@ begin
890890 } def
891891
892892 /enct {
893-
894893 /in exch def
895894
896895 %
897- % Each char adds 1 codeword, latches add up to 2
896+ % Codeword sequences are held as persistent chains of segments.
897+ % Each chain head is null or a node [parent_node, segment_array];
898+ % the final sequence is materialised once by walking the chain.
898899 %
899- /maxseqlen in length 3 mul 4 add def
900-
901- /seq0 [ 4 { maxseqlen array } repeat ] def
902- /seq1 [ 4 { maxseqlen array } repeat ] def
903- /len0 4 array def len0 0 0 put len0 1 0 put len0 2 0 put len0 3 0 put
904- /len1 4 array def
905-
906- /curseq seq0 def /curseqlen len0 def
907- /nxtseq seq1 def /nxtseqlen len1 def
900+ /curseqhd [ //micropdf417.textsubmodes length { null } repeat ] def
901+ /nxtseqhd [ //micropdf417.textsubmodes length { null } repeat ] def
902+ /curseqlen [ //micropdf417.textsubmodes length { 0 } repeat ] def
903+ /nxtseqlen [ //micropdf417.textsubmodes length { 0 } repeat ] def
908904
909905 /curlen [ //micropdf417.e //micropdf417.e //micropdf417.e //micropdf417.e ] def
910906 curlen submode 0 put
911907
912- % Derive the optimal sequences ending in each submode
908+ %
909+ % Flatten a chain of [parent, segment] cons cells of total length L
910+ % into a fresh array. The chain's deepest node holds the prefix, so
911+ % we walk head-to-root and write each segment into the tail of the
912+ % output, advancing pos backwards.
913+ %
914+ /flatten { % hd len -> array
915+
916+ dup array 3 1 roll % pos = len; out = array(len)
917+
918+ { % out hd pos
919+ 1 index null eq { exit } if % done when hd is null
920+ 1 index 1 get % ... seg = hd[1]
921+ exch 1 index length sub % ... pos -= length(seg)
922+ 3 index 1 index 3 index putinterval % out[pos..] = seg
923+ exch pop % drop seg
924+ exch 0 get exch % hd = hd[0]
925+ } loop
926+
927+ pop pop % return out
928+
929+ } def
930+
913931 in {
914932
915933 /char exch def
916934
917- % Check for optimisations in the current sequences by latching from x to y
918- { % loop
935+ % Phase 1: relax curlen[*] via the static latch graph
936+ {
919937 /imp false def
920938 //micropdf417.textsubmodes {
921939 /x exch def
@@ -924,28 +942,24 @@ begin
924942 /cost curlen x get //micropdf417.latlen x get y get add def
925943 cost curlen y get lt {
926944 curlen y cost put
927- % Copy curseq[x] to curseq[y] and append latseq codes
928- /srclen curseqlen x get def
929- srclen 0 gt {
930- curseq y get 0 curseq x get 0 srclen getinterval putinterval
931- } if
932- //micropdf417.latseq x get y get {
933- curseq y get srclen 3 -1 roll put
934- /srclen srclen 1 add def
935- } forall
936- curseqlen y srclen put
945+ /latyseg //micropdf417.latseq x get y get def
946+ curseqhd y
947+ latyseg length 0 eq
948+ { curseqhd x get }
949+ { [ curseqhd x get latyseg ] }
950+ ifelse
951+ put
952+ curseqlen y curseqlen x get latyseg length add put
937953 /imp true def
938954 } if
939955 } forall
940956 } forall
941- imp not {exit} if % Repeat unless no improvement
957+ imp not {exit} if
942958 } loop
943959
944- %
945- % Determine optimal next sequences for each valid encoding
946- %
947960 /nxtlen [ //micropdf417.e //micropdf417.e //micropdf417.e //micropdf417.e ] def
948- nxtseqlen 0 0 put nxtseqlen 1 0 put nxtseqlen 2 0 put nxtseqlen 3 0 put
961+ //micropdf417.textsubmodes { nxtseqhd exch null put } forall
962+ //micropdf417.textsubmodes { nxtseqlen exch 0 put } forall
949963
950964 //micropdf417.textsubmodes {
951965 /x exch def
@@ -954,37 +968,26 @@ begin
954968
955969 charvals x get char known not {exit} if
956970
957- %
958- % Extend directly: copy curseq[x] + char to nxtseq[x]
959- %
971+ % Phase 2: nxtseq[x] := curseq[x] + [char]
960972 /cost curlen x get 1 add def
961973 cost nxtlen x get lt {
962974 nxtlen x cost put
963- /srclen curseqlen x get def
964- srclen 0 gt {
965- nxtseq x get 0 curseq x get 0 srclen getinterval putinterval
966- } if
967- nxtseq x get srclen char put
968- nxtseqlen x srclen 1 add put
975+ nxtseqhd x [ curseqhd x get [ char ] ] put
976+ nxtseqlen x curseqlen x get 1 add put
969977 } if
970978
971- %
972- % Optimise for direct shifts from y to x
973- %
979+ % Phase 3: shift y -> x for one char (y != x; stays in y)
974980 //micropdf417.textsubmodes {
975981 /y exch def
976982 x y ne {
977983 /cost curlen y get //micropdf417.shftlen y get x get add 1 add def
978984 cost nxtlen y get lt {
979985 nxtlen y cost put
980- % Copy curseq[y] + shift + char to nxtseq[y]
981- /srclen curseqlen y get def
982- srclen 0 gt {
983- nxtseq y get 0 curseq y get 0 srclen getinterval putinterval
984- } if
985- nxtseq y get srclen x //micropdf417.a eq {//micropdf417.as} {//micropdf417.ps} ifelse put
986- nxtseq y get srclen 1 add char put
987- nxtseqlen y srclen 2 add put
986+ nxtseqhd y [
987+ curseqhd y get
988+ [ x //micropdf417.a eq {//micropdf417.as} {//micropdf417.ps} ifelse char ]
989+ ] put
990+ nxtseqlen y curseqlen y get 2 add put
988991 } if
989992 } if
990993 } forall
@@ -995,23 +998,26 @@ begin
995998 } forall
996999
9971000 /curlen nxtlen def
998- % Swap cur and nxt buffers
999- curseq nxtseq /curseq exch def /nxtseq exch def
1000- curseqlen nxtseqlen /curseqlen exch def /nxtseqlen exch def
1001+ curseqhd nxtseqhd /curseqhd exch def /nxtseqhd exch def
1002+ curseqlen nxtseqlen /curseqlen exch def /nxtseqlen exch def
10011003
10021004 } forall
10031005
10041006 %
10051007 % Select the optimal sequence
10061008 %
10071009 /minseq //micropdf417.e def
1010+ /bestsm -1 def
10081011 //micropdf417.textsubmodes {
10091012 /k exch def
10101013 curlen k get minseq lt {
10111014 /minseq curlen k get def
1012- /txtseq curseq k get 0 curseqlen k get getinterval def
1015+ /bestsm k def
10131016 } if
10141017 } forall
1018+ bestsm -1 ne {
1019+ /txtseq curseqhd bestsm get curseqlen bestsm get flatten def
1020+ } if
10151021
10161022 %
10171023 % Encode the sequence
0 commit comments