/* * lgl-barcode-postnet.c * Copyright (C) 2001-2010 Jim Evins . * * This file is part of libglbarcode. * * libglbarcode is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * libglbarcode is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with libglbarcode. If not, see . */ /* * This module implements the POSTNET barcode specified in the USPS * publication 25, Mar 2001. */ #include #include "lgl-barcode-postnet.h" #include #include /*========================================================*/ /* Private macros and constants. */ /*========================================================*/ #define PTS_PER_INCH 72.0 #define POSTNET_BAR_WIDTH ( 0.02 * PTS_PER_INCH ) #define POSTNET_FULLBAR_HEIGHT ( 0.125 * PTS_PER_INCH ) #define POSTNET_HALFBAR_HEIGHT ( 0.05 * PTS_PER_INCH ) #define POSTNET_BAR_PITCH ( 0.04545 * PTS_PER_INCH ) #define POSTNET_HORIZ_MARGIN ( 0.125 * PTS_PER_INCH ) #define POSTNET_VERT_MARGIN ( 0.04 * PTS_PER_INCH ) /*===========================================*/ /* Private globals */ /*===========================================*/ static gchar *symbols[] = { /* 0 */ "11000", /* 1 */ "00011", /* 2 */ "00101", /* 3 */ "00110", /* 4 */ "01001", /* 5 */ "01010", /* 6 */ "01100", /* 7 */ "10001", /* 8 */ "10010", /* 9 */ "10100", }; static gchar *frame_symbol = "1"; /*===========================================*/ /* Local function prototypes */ /*===========================================*/ static gint postnet_validate_data (const gchar *data); static gchar *postnet_encode (const gchar *digits); static lglBarcode *postnet_vectorize (const gchar *code); /****************************************************************************/ /* Generate new Postnet barcode structure from data. */ /****************************************************************************/ lglBarcode * lgl_barcode_postnet_new (lglBarcodeType type, gboolean text_flag, gboolean checksum_flag, gdouble w, gdouble h, const gchar *data) { gint n_digits; gchar *code; lglBarcode *bc; /* Validate data and length for all subtypes. */ n_digits = postnet_validate_data (data); switch (type) { case LGL_BARCODE_TYPE_POSTNET: if ( (n_digits != 5) && (n_digits != 9) && (n_digits != 11) ) { return NULL; } break; case LGL_BARCODE_TYPE_POSTNET_5: if ( n_digits != 5 ) { return NULL; } break; case LGL_BARCODE_TYPE_POSTNET_9: if ( n_digits != 9 ) { return NULL; } break; case LGL_BARCODE_TYPE_POSTNET_11: if ( n_digits != 11 ) { return NULL; } break; case LGL_BARCODE_TYPE_CEPNET: if ( n_digits != 8 ) { return NULL; } break; default: g_message ("Invalid barcode type for POSTNET backend."); return NULL; } /* First get code string */ code = postnet_encode (data); if (code == NULL) { return NULL; } /* Now vectorize encoded data */ bc = postnet_vectorize (code); g_free (code); return bc; } /*--------------------------------------------------------------------------*/ /* PRIVATE. Validate data, returning number of digits if valid. */ /*--------------------------------------------------------------------------*/ static gint postnet_validate_data (const gchar *data) { gchar *p; gint i; if (!data) { return 0; } for ( p = (gchar *)data, i=0; *p != 0; p++ ) { if (g_ascii_isdigit (*p)) { i++; } else if ( (*p != '-') && (*p != ' ') ) { /* Only allow digits, dashes, and spaces. */ return 0; } } return i; } /*--------------------------------------------------------------------------*/ /* PRIVATE. Generate string of symbols, representing barcode. */ /*--------------------------------------------------------------------------*/ static gchar * postnet_encode (const gchar *data) { gchar *p; gint len; gint d, sum; GString *code; /* Left frame bar */ code = g_string_new (frame_symbol); sum = 0; for ( p = (gchar *)data, len = 0; (*p != 0) && (len < 11); p++ ) { if (g_ascii_isdigit (*p)) { /* Only translate the digits (0-9) */ d = (*p) - '0'; sum += d; code = g_string_append (code, symbols[d]); len++; } } /* Create correction character */ d = (10 - (sum % 10)) % 10; code = g_string_append (code, symbols[d]); /* Right frame bar */ code = g_string_append (code, frame_symbol); return g_string_free (code, FALSE); } /*--------------------------------------------------------------------------*/ /* PRIVATE. Vectorize encoded barcode. */ /*--------------------------------------------------------------------------*/ static lglBarcode * postnet_vectorize (const gchar *code) { lglBarcode *bc; gchar *p; gdouble x, y, length, width; bc = lgl_barcode_new (); /* Now traverse the code string and create a list of lines */ x = POSTNET_HORIZ_MARGIN; for ( p = (gchar *)code; *p != 0; p++ ) { y = POSTNET_VERT_MARGIN; switch (*p) { case '0': y += POSTNET_FULLBAR_HEIGHT - POSTNET_HALFBAR_HEIGHT; length = POSTNET_HALFBAR_HEIGHT; break; case '1': length = POSTNET_FULLBAR_HEIGHT; break; default: break; } width = POSTNET_BAR_WIDTH; lgl_barcode_add_box (bc, x, y, width, length); x += POSTNET_BAR_PITCH; } bc->width = x + POSTNET_HORIZ_MARGIN; bc->height = POSTNET_FULLBAR_HEIGHT + 2 * POSTNET_VERT_MARGIN; return bc; } /* * Local Variables: -- emacs * mode: C -- emacs * c-basic-offset: 8 -- emacs * tab-width: 8 -- emacs * indent-tabs-mode: nil -- emacs * End: -- emacs */