]> git.sur5r.net Git - glabels/blobdiff - libglbarcode/lgl-barcode-postnet.c
Imported Upstream version 3.0.0
[glabels] / libglbarcode / lgl-barcode-postnet.c
diff --git a/libglbarcode/lgl-barcode-postnet.c b/libglbarcode/lgl-barcode-postnet.c
new file mode 100644 (file)
index 0000000..6308483
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ *  lgl-barcode-postnet.c
+ *  Copyright (C) 2001-2010  Jim Evins <evins@snaught.com>.
+ *
+ *  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 <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This module implements the POSTNET barcode specified in the USPS
+ * publication 25, Mar 2001.
+ */
+
+#include <config.h>
+
+#include "lgl-barcode-postnet.h"
+
+#include <glib.h>
+#include <ctype.h>
+
+
+/*========================================================*/
+/* 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
+ */