/** Generates barcodes as Frink graphics. You can use this like: UPCA["000999420690"].show[] */ /** Generates a UPC-A label from a string of 11 or 12 digits. If this has 12 digits or more, it verifies that the last "check" digit is correct and corrects it (printing a warning) if it's incorrect. TODO: Check for right number of digits otherwise arguments: [str, xdim, h] where str is a string of digits to encode (should be 11 or 12 chars long.) xdim is the width of the smallest bar (defaults to 0.33 mm per standard) h is the height of the normal bars (the start/end/middle bars will be 5 xdim taller than this per spec.) returns: a graphics object */ UPCA[str, xdim=0.33 mm, h=25.9 mm] := { str = calculateCheckDigitUPCA[str] x = 0 xdim // Make units of measure work out right g = new graphics g.font["Monospaced", h/8] g.antialiased[false] x = drawBarsUPCA[g, "000000000", x, xdim, h] // Quiet zone left x = drawBarsUPCA[g, "101", x, xdim, h + 5 xdim] // Start x = drawCharsUPCA[g, left[str, 6], x, xdim, h] // Left 6 chars xl = x // Used for aligning text characters x = drawBarsUPCA[g, "01010", x, xdim, h + 5 xdim] // Middle xr = x // Used for aligning text characters x = drawCharsUPCA[g, right[str, 6], x, xdim, h, true] // Right 6 chars, reversed x = drawBarsUPCA[g, "101", x, xdim, h + 5 xdim] // End x = drawBarsUPCA[g, "000000000", x, xdim, h] // Quiet zone right // Draw text characters g.color[0,0,0] g.text[substrLen[str, 0, 1], 8 xdim, h, "right", "center"] // Left g.text[substrLen[str, 1, 5] + " ", xl, h - 2 xdim, "right", "top"] // Left 5 g.text[" " + substrLen[str, 6, 5], xr, h - 2 xdim, "left", "top"] // Right 5 g.text[substrLen[str, 11, 1], x - 8 xdim, h, "left", "center"] // Check digit return g } /** Draw a sequence of characters. Returns the new x position. */ drawCharsUPCA[g is graphics, bits, x, xdim, h, reverse=false] := { CHAR: for c = charList[bits] { if c == "0" x = drawBarsUPCA[g, "0001101", x, xdim, h, reverse] if c == "1" x = drawBarsUPCA[g, "0011001", x, xdim, h, reverse] if c == "2" x = drawBarsUPCA[g, "0010011", x, xdim, h, reverse] if c == "3" x = drawBarsUPCA[g, "0111101", x, xdim, h, reverse] if c == "4" x = drawBarsUPCA[g, "0100011", x, xdim, h, reverse] if c == "5" x = drawBarsUPCA[g, "0110001", x, xdim, h, reverse] if c == "6" x = drawBarsUPCA[g, "0101111", x, xdim, h, reverse] if c == "7" x = drawBarsUPCA[g, "0111011", x, xdim, h, reverse] if c == "8" x = drawBarsUPCA[g, "0110111", x, xdim, h, reverse] if c == "9" x = drawBarsUPCA[g, "0001011", x, xdim, h, reverse] } return x } /** Draws a sequence of bars. Returns the new x position. */ drawBarsUPCA[g is graphics, bits, x, xdim, h, reverse=false] := { if isString[bits] bitArray = eval[charList[bits]] for b = bitArray { if reverse b = 1 - b if b == 0 g.color[1,1,1] else g.color[0,0,0] g.fillRectSides[x, 0 h, x+xdim, h] x = x + xdim } return x } /** Calculates the check digit of the string, which should be 11 or 12 digits, and returns the string with the correct digit as the last character. */ calculateCheckDigitUPCA[str] := { c = eval[charList[str]] sum = (3 c@0 + c@1 + 3c@2 + c@3 + 3 c@4 + c@5 + 3c@6 + c@7 + 3 c@8 + c@9 + 3c@10) mod 10 digit = toString[(10-sum) mod 10] ret = left[str, 11] + digit if length[str] > 11 if digit != substrLen[str,11,1] println["Warning: $str had incorrect last check digit, should be $ret"] return ret }