From 0f73f8658931299b97a4e9126622014e7d86e9ed Mon Sep 17 00:00:00 2001 From: Sam Lown Date: Mon, 17 May 2010 10:55:06 +0200 Subject: [PATCH] Added libzint as a barcode backend. Added libzint as a barcode backend. Currently only implements the GS1-128 barcode. --- configure.ac | 24 ++++ src/Makefile.am | 7 ++ src/bc-zint.c | 300 ++++++++++++++++++++++++++++++++++++++++++++++++ src/bc-zint.h | 49 ++++++++ src/bc.c | 8 ++ 5 files changed, 388 insertions(+) create mode 100644 src/bc-zint.c create mode 100644 src/bc-zint.h diff --git a/configure.ac b/configure.ac index 61d6f9ba..8193c77f 100644 --- a/configure.ac +++ b/configure.ac @@ -80,6 +80,7 @@ LIBEBOOK_REQUIRED=2.28.0 LIBBARCODE_REQUIRED=0.98 LIBQRENCODE_REQUIRED=3.1.0 LIBIEC16022_REQUIRED=0.2.4 +LIBZINT_REQUIRED=2.3.1 dnl Make above strings available for packaging files (e.g. rpm spec files) AC_SUBST(GLIB_REQUIRED) @@ -90,6 +91,7 @@ AC_SUBST(LIBEBOOK_REQUIRED) AC_SUBST(LIBBARCODE_REQUIRED) AC_SUBST(LIBQRENCODE_REQUIRED) AC_SUBST(LIBIEC16022_REQUIRED) +AC_SUBST(LIBZINT_REQUIRED) dnl --------------------------------------------------------------------------- @@ -158,6 +160,27 @@ else help_libbarcode="(See http://www.gnu.org/software/barcode/barcode.html)" fi +dnl --------------------------------------------------------------------------- +dnl - Check for optional Zint backend +dnl --------------------------------------------------------------------------- +AC_ARG_WITH(libzint, + [AS_HELP_STRING([--without-libzint],[build without Zint Barcode support])]) +have_libzint=no +if test "x$with_libzint" != xno; then + AC_CHECK_LIB(zint, ZBarcode_Create, + [have_libzint=yes], [have_libzint=no]) +fi + +if test "x$have_libzint" = "xyes"; then + AC_DEFINE(HAVE_LIBZINT,1,[Define to 1 for Zint Barcode support]) + LIBZINT_CFLAGS="" + LIBZINT_LIBS="-lzint" + AC_SUBST(LIBZINT_CFLAGS) + AC_SUBST(LIBZINT_LIBS) +else + help_libzint="(See http://www.zint.org.uk)" +fi + dnl --------------------------------------------------------------------------- dnl - Check for optional QRencode Barcode backend @@ -288,6 +311,7 @@ Optional barcode backends: GNU Barcode ............. ${have_libbarcode} ${help_libbarcode} QR Code ................. ${have_libqrencode} ${help_libqrencode} IEC 16022 ............... ${have_libiec16022} ${help_libiec16022} + Zint .................... ${have_libzint} ${help_libzint} " diff --git a/src/Makefile.am b/src/Makefile.am index d18b29e9..a002c69c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,6 +8,7 @@ INCLUDES = \ $(GLABELS_CFLAGS) \ $(LIBEBOOK_CFLAGS) \ $(LIBBARCODE_CFLAGS) \ + $(LIBZINT_CFLAGS) \ $(LIBQRENCODE_CFLAGS) \ $(LIBIEC16022_CFLAGS) \ $(DISABLE_DEPRECATED_CFLAGS) \ @@ -24,6 +25,7 @@ glabels_3_LDADD = \ ../libglabels/$(LIBGLABELS_BRANCH).la \ $(LIBEBOOK_LIBS) \ $(LIBBARCODE_LIBS) \ + $(LIBZINT_LIBS) \ $(LIBQRENCODE_LIBS) \ $(LIBIEC16022_LIBS) @@ -34,6 +36,7 @@ glabels_3_batch_LDADD = \ ../libglabels/$(LIBGLABELS_BRANCH).la \ $(LIBEBOOK_LIBS) \ $(LIBBARCODE_LIBS) \ + $(LIBZINT_LIBS) \ $(LIBQRENCODE_LIBS) \ $(LIBIEC16022_LIBS) @@ -118,6 +121,8 @@ glabels_3_SOURCES = \ bc.h \ bc-gnubarcode.c \ bc-gnubarcode.h \ + bc-zint.c \ + bc-zint.h \ bc-postnet.c \ bc-postnet.h \ bc-iec16022.c \ @@ -239,6 +244,8 @@ glabels_3_batch_SOURCES = \ bc.h \ bc-gnubarcode.c \ bc-gnubarcode.h \ + bc-zint.c \ + bc-zint.h \ bc-postnet.c \ bc-postnet.h \ bc-iec16022.c \ diff --git a/src/bc-zint.c b/src/bc-zint.c new file mode 100644 index 00000000..e938c717 --- /dev/null +++ b/src/bc-zint.c @@ -0,0 +1,300 @@ +/* + * bc-zint.c + * Copyright (C) 2001-2009 Jim Evins . + * + * This file is part of gLabels. + * + * gLabels is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * gLabels 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with gLabels. If not, see . + */ + +#include + +#ifdef HAVE_LIBZINT + +#include "bc-zint.h" + +#include +#include +#include +#include /* Zint */ + +#include "debug.h" + + +/*========================================================*/ +/* Private macros and constants. */ +/*========================================================*/ +#define SHRINK_AMOUNT 0.15 /* shrink bars to account for ink spreading */ +#define FONT_SCALE 0.95 /* Shrink fonts just a hair */ + + +/*===========================================*/ +/* Local function prototypes */ +/*===========================================*/ +static glBarcode *render_zint (struct zint_symbol *symbol, gboolean text_flag); +gint module_is_set(struct zint_symbol *symbol, gint y_coord, gint x_coord); + + + +/*****************************************************************************/ +/* Generate intermediate representation of barcode. */ +/*****************************************************************************/ +glBarcode * +gl_barcode_zint_new (const gchar *id, + gboolean text_flag, + gboolean checksum_flag, + gdouble w, + gdouble h, + const gchar *digits) +{ + glBarcode *gbc; + struct zint_symbol *symbol; + gint type; + gint result; + + symbol = ZBarcode_Create(); + + /* Assign type flag. Pre-filter by length for subtypes. */ + if (g_ascii_strcasecmp (id, "GS1-128") == 0) { + symbol->symbology = BARCODE_EAN128; + } else { + g_message( "Illegal barcode id %s", id ); + ZBarcode_Delete (symbol); + return NULL; + } + + /* Checksum not supported yet!! + if (!checksum_flag) { + flags |= BARCODE_NO_CHECKSUM; + } + */ + + // g_message ("Zint Requested Dimensions: %f x %f", w, h); + + result = ZBarcode_Encode(symbol, (unsigned char *)digits, 0); + if (result) { + ZBarcode_Delete (symbol); + g_message ("Zint Error: %s", symbol->errtxt); + return NULL; + } + + /* Scale calculated after height, always maintain aspect ratio */ + // symbol->height = (h > 0.0 ? (gint)h : 50); + symbol->scale = (w / symbol->width); + symbol->height = h / symbol->scale; // height always in standard size + + + /* Convert Sums provided by zint encode */ + gbc = render_zint(symbol, text_flag); + + // g_message ("Zint Barcode Dimensions: %f x %f", gbc->width, gbc->height); + + ZBarcode_Delete(symbol); + + return gbc; +} + + +/*-------------------------------------------------------------------------- + * PRIVATE. Render to glBarcode the provided Zint symbol. + * + * Based on the SVG output from Zint library, handles lots of otherwise + * internal Zint code to convert directly to glBarcode representation. + * + *--------------------------------------------------------------------------*/ +static glBarcode *render_zint(struct zint_symbol *symbol, gboolean text_flag) { + + glBarcode *gbc; + glBarcodeLine *line; + glBarcodeChar *bchar; + + gint i, r, block_width, latch, this_row; + gfloat textpos, large_bar_height, preset_height, row_height, row_posn = 0.0; + gint error_number = 0; + gint textoffset, textheight, xoffset, yoffset, textdone, main_width; + gchar textpart[10], addon[6]; + gint large_bar_count, comp_offset; + gfloat addon_text_posn; + gfloat default_text_posn; + gfloat scaler = symbol->scale; + gchar *p; + + gbc = g_new0(glBarcode, 1); + + row_height = 0; + textdone = 0; + main_width = symbol->width; + strcpy(addon, ""); + comp_offset = 0; + addon_text_posn = 0.0; + + if (symbol->height < 15) { + symbol->height = 15; + } + // symbol->height = 50; + + if(text_flag && strlen(symbol->text) != 0) { + textheight = 9.0; + textoffset = 2.0; + } else { + textheight = textoffset = 0.0; + } + // Update height for texts + symbol->height -= textheight + textoffset; + + large_bar_count = 0; + preset_height = 0.0; + for(i = 0; i < symbol->rows; i++) { + preset_height += symbol->row_height[i]; + if(symbol->row_height[i] == 0) { + large_bar_count++; + } + } + large_bar_height = (symbol->height - preset_height) / large_bar_count; + + if (large_bar_count == 0) { + symbol->height = preset_height; + } + + while(!(module_is_set(symbol, symbol->rows - 1, comp_offset))) { + comp_offset++; + } + + xoffset = symbol->border_width + symbol->whitespace_width; + yoffset = symbol->border_width; + + gbc->width = (gdouble) (symbol->width + xoffset + xoffset) * scaler; + gbc->height = (gdouble) (symbol->height + textheight + textoffset + yoffset + yoffset) * scaler; + + default_text_posn = (symbol->height + textoffset + symbol->border_width) * scaler; + + if(symbol->symbology != BARCODE_MAXICODE) { + /* everything else uses rectangles (or squares) */ + /* Works from the bottom of the symbol up */ + int addon_latch = 0; + + for(r = 0; r < symbol->rows; r++) { + this_row = r; + if(symbol->row_height[this_row] == 0) { + row_height = large_bar_height; + } else { + row_height = symbol->row_height[this_row]; + } + row_posn = 0; + for(i = 0; i < r; i++) { + if(symbol->row_height[i] == 0) { + row_posn += large_bar_height; + } else { + row_posn += symbol->row_height[i]; + } + } + row_posn += yoffset; + + i = 0; + if(module_is_set(symbol, this_row, 0)) { + latch = 1; + } else { + latch = 0; + } + + do { + block_width = 0; + do { + block_width++; + } while (module_is_set(symbol, this_row, i + block_width) == module_is_set(symbol, this_row, i)); + if((addon_latch == 0) && (r == (symbol->rows - 1)) && (i > main_width)) { + addon_text_posn = (row_posn + 8.0) * scaler; + addon_latch = 1; + } + if(latch == 1) { + /* a bar */ + line = g_new0 (glBarcodeLine, 1); + + line->width = block_width * scaler; + /* glBarcodeLine centers based on width, counter-act!!! */ + line->x = ((i + xoffset) + (block_width / 2.0)) * scaler; + + if(addon_latch == 0) { + line->y = row_posn * scaler; + line->length = row_height * scaler; + } else { + line->y = (row_posn + 10.0) * scaler; + line->length = (row_height - 5.0) * scaler; + } + latch = 0; + // g_message ("Zint Adding Line at: %f x %f dim: %f x %f", line->x, line->y, line->width, line->length); + gbc->lines = g_list_append (gbc->lines, line); + } else { + /* a space */ + latch = 1; + } + i += block_width; + + } while (i < symbol->width); + } + } + /* That's done the actual data area, everything else is human-friendly */ + + + + + + /* Add the text */ + xoffset -= comp_offset; + + if (text_flag) { + // caculate start xoffset to center text + xoffset = symbol->width / 2.0; + xoffset -= (strlen(symbol->text) / 2) * 5.0; + + for (p = symbol->text; *p != 0; p++) { + if (p != symbol->text && *p == '(') xoffset += 3.0; + bchar = g_new0 (glBarcodeChar, 1); + bchar->x = (textpos + xoffset) * scaler; + bchar->y = default_text_posn; + bchar->fsize = 8.0 * scaler; + bchar->c = (gchar) *p; + gbc->chars = g_list_append (gbc->chars, bchar); + // Poor mans kerning + if (*p == '(') { + xoffset += 3.0; + } else if (*p == ')') { + xoffset += 3.0; + } else { + xoffset += 5.0; + } + } + } + + return gbc; +} + +/* + * Stolen from Zint common.c + */ +gint module_is_set(struct zint_symbol *symbol, gint y_coord, gint x_coord) +{ + return (symbol->encoded_data[y_coord][x_coord / 7] & (1 << (x_coord % 7))) ? 1 : 0; +} + +#endif /* HAVE_LIBZINT */ + +/* + * Local Variables: -- emacs + * mode: C -- emacs + * c-basic-offset: 8 -- emacs + * tab-width: 8 -- emacs + * indent-tabs-mode: nil -- emacs + * End: -- emacs + */ diff --git a/src/bc-zint.h b/src/bc-zint.h new file mode 100644 index 00000000..c0a797d6 --- /dev/null +++ b/src/bc-zint.h @@ -0,0 +1,49 @@ +/* + * bc-zint.h + * Copyright (C) 2010 Sam Lown . + * Copyright (C) 2001-2009 Jim Evins . + * + * This file is part of gLabels. + * + * gLabels is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * gLabels 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with gLabels. If not, see . + */ + +#ifndef __BC_ZINT_H__ +#define __BC_ZINT_H__ + +#include "bc.h" + +G_BEGIN_DECLS + +glBarcode *gl_barcode_zint_new (const gchar *id, + gboolean text_flag, + gboolean checksum_flag, + gdouble w, + gdouble h, + const gchar *digits); + +G_END_DECLS + +#endif /* __BC_ZINT_H__ */ + + + +/* + * Local Variables: -- emacs + * mode: C -- emacs + * c-basic-offset: 8 -- emacs + * tab-width: 8 -- emacs + * indent-tabs-mode: nil -- emacs + * End: -- emacs + */ diff --git a/src/bc.c b/src/bc.c index 5a1d6bc2..3c3d1dc1 100644 --- a/src/bc.c +++ b/src/bc.c @@ -27,6 +27,7 @@ #include "bc-postnet.h" #include "bc-gnubarcode.h" +#include "bc-zint.h" #include "bc-iec16022.h" #include "bc-iec18004.h" @@ -156,6 +157,13 @@ static const Backend backends[] = { #endif /* HAVE_LIBBARCODE */ +#ifdef HAVE_LIBZINT + + { "GS1-128", N_("GS1-128"), gl_barcode_zint_new, + TRUE, TRUE, FALSE, FALSE, "[00]001234560000000018", TRUE, 16}, + +#endif /* HAVE_LIBZINT */ + #ifdef HAVE_LIBIEC16022 { "IEC16022", N_("IEC16022 (DataMatrix)"), gl_barcode_iec16022_new, -- 2.39.5