Google Groups Home
Help | Sign in
Recent pages and files
Renderer Code Commentary    

 

Renderer

The procedure labelled barcode is known as the renderer, which we now consider. Its purpose is to accept as input an instance of the dictionary-based data structure described in section 2.1 that represents a barcode in some arbitrary symbology and produce a visual rendering of this at the current point.

The variables that we use in this procedure are confined to local scope by declaring the procedure as follows:

/barcode {

0 begin

...

end

} bind def
/barcode load 0 1 dict put

We then immediately read the dictionary-based data structure which is passed as a single argument to this procedure by an encoder.

From this we extract and initialise each entry including the space bar succession, bar height succession, bar base succession, human readable text and any encoder specific default options.

Just as with the encoders, we read and tokenise the user supplied options allowing the default rendering options to be overridden.

    /args exch def   % We are given some arguments

% Default options
/sbs [] def
/bhs [] def
/bbs [] def
/txt [] def
/barcolor (unset) def
/textcolor (unset) def
/bordercolor (unset) def
/backgroundcolor (unset) def
/inkspread 0.15 def

...

% Apply the renderer options
args {exch cvlit exch def} forall

% Parse the user options
opt {
token false eq {exit} if dup length string cvs (=) search
true eq {cvlit exch pop exch def} {cvlit true def} ifelse
} loop

/barcolor barcolor cvlit def
/textcolor textcolor cvlit def
/bordercolor bordercolor cvlit def
/backgroundcolor backgroundcolor cvlit def
/inkspread inkspread cvr def

...

We have extracted or derived all of the necessary information from the input, and now use the space bar succession, bar height succession and bar base succession in calculations that create a single array containing elements that give coordinates for each of the bars in the barcode.

We start by creating a bars array that is half the length of the space bar succession. We build this by repeatedly adding array elements that contain the height, x-coordinate, y-coordinate and width of single bars. The height and y-coordinates are read from the bar height succession and the bar base succession, respectively, whilst the x-coordinate and the width are made from a calculation of the total indent, based on the space bar succession and a compensating factor that accounts for ink spread.

    % Create bar elements and put them into the bars array
/bars sbs length 1 add 2 idiv array def
/x 0.00 def /maxh 0 def
0 1 sbs length 1 add 2 idiv 2 mul 2 sub {
/i exch def
i 2 mod 0 eq { % i is even
/d sbs i get barratio mul barratio sub 1 add def % d=digit*r-r+1
/h bhs i 2 idiv get 72 mul def % Height from bhs
/c d 2 div x add def % Centre of the bar = x + d/2
/y bbs i 2 idiv get 72 mul def % Baseline from bbs
/w d inkspread sub def % bar width = digit - inkspread
bars i 2 idiv [h c y w] put % Add the bar entry
h maxh gt {/maxh h def} if
} {
/d sbs i get spaceratio mul spaceratio sub 1 add def % d=digit*r-r+1
} ifelse
/x x d add def % x+=d
} for

Now we perform the actual rendering in seperate phases.

The graphics state is preserved accross calls by wrapping the actual rendering in a gsave/grestore pair in order to prevent unexpected interference with the user's environment.

    gsave

...

grestore

We ensure that we are rendering the symbol from the "current point" by translating the coordinate system so that the current point temporarily becomes the origin.

Also, since we know the total width of the symbol from the above processes we are able to horizonally scale the symbol so that it exactly to a user specified width, when supplied.

    currentpoint translate

% Force symbol to given width
width 0 ne {
width 72 mul x div 1 scale
} if

We plot the border and fill the background setting each componants color only when supplied.

    % Display the border and background
newpath
borderleft neg borderbottom neg moveto
x borderleft add borderright add 0 rlineto
0 maxh borderbottom add bordertop add rlineto
x borderleft add borderright add neg 0 rlineto
0 maxh borderbottom add bordertop add neg rlineto
closepath
backgroundcolor (unset) ne {
gsave
(< >) dup 1 backgroundcolor putinterval cvx exec {255 div} forall setrgbcolor
fill
grestore
} if
showborder {
gsave
bordercolor (unset) ne {
(< >) dup 1 bordercolor putinterval cvx exec {255 div} forall setrgbcolor
} if
borderwidth setlinewidth stroke
grestore
} if

We iterated over the bars array to display each bar, setting the color only when requested.

    % Display the bars for elements in the bars array
gsave
barcolor (unset) ne {
(< >) dup 1 barcolor putinterval cvx exec {255 div} forall setrgbcolor
} if
bars {
{} forall
newpath setlinewidth moveto 0 exch rlineto stroke
} forall
grestore

We iterate over the txt array to render the text, setting its color when requested.

    % Display the text for elements in the text array
textcolor (unset) ne {
(< >) dup 1 textcolor putinterval cvx exec {255 div} forall setrgbcolor
} if
/s 0 def /f () def
txt {
{} forall
2 copy s ne exch f ne or {
2 copy /s exch def /f exch def
exch findfont exch scalefont setfont
} {
pop pop
} ifelse
moveto show
} forall

The whitespace guard symbols are plotted where required.

    % Display the guard elements
guardwhitespace {
0.75 setlinewidth
guardleftpos 0 ne {
newpath
guardleftpos neg guardwidth add guardleftypos guardwidth 2 div add moveto
guardwidth neg guardheight -2 div rlineto
guardwidth guardheight -2 div rlineto
stroke
} if
guardrightpos 0 ne {
newpath
guardrightpos x add guardwidth sub guardrightypos guardheight 2 div add moveto
guardwidth guardheight -2 div rlineto
guardwidth neg guardheight -2 div rlineto
stroke
} if
} if
Version: 
Create a group - Google Groups - Google Home - Terms of Service - Privacy Policy
©2008 Google