summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbanana <delgadillo.tyler@gmail.com>2024-03-22 13:52:05 -0700
committerbanana <delgadillo.tyler@gmail.com>2024-03-22 13:52:05 -0700
commitf401289e371a76ff0dbaea40f7f94f7b85c4b2bd (patch)
tree30b66628375b55e2be46cc19b1290c78eed0269d
Initial commitHEADmaster
-rw-r--r--Makefile23
-rw-r--r--inc/num.h160
-rw-r--r--inc/tga.h1
-rw-r--r--inc/upc.h2
-rw-r--r--obj/.gitignore2
-rw-r--r--readme11
-rw-r--r--src/main.c137
-rw-r--r--src/tga.c55
-rw-r--r--src/upc.c113
9 files changed, 504 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..c859442
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,23 @@
+.RECIPEPREFIX = >
+
+CC = gcc
+
+CFLAGS = -I$(INCDIR)
+
+INCDIR = inc
+OBJDIR = obj
+SRCDIR = src
+
+DEP = $(INCDIR)/tga.h $(INCDIR)/upc.h $(INCDIR)/num.h
+OBJ = $(OBJDIR)/main.o $(OBJDIR)/tga.o $(OBJDIR)/upc.o # $(OBJDIR)/cli.o
+
+$(OBJDIR)/%.o: $(SRCDIR)/%.c $(DEPS)
+> $(CC) -c -o $@ $< $(CFLAGS)
+
+upc: $(OBJ)
+> $(CC) -o $@ $^ $(CFLAGS)
+
+.PHONY: clean
+
+clean:
+> rm -f $(OBJDIR)/*.o ./*.tga upc
diff --git a/inc/num.h b/inc/num.h
new file mode 100644
index 0000000..7cd93d8
--- /dev/null
+++ b/inc/num.h
@@ -0,0 +1,160 @@
+const char NUMBER[10][16][8] = { 0, 0, 0, 0, 0, 0, 0, 0, // NUMBER 0
+ 0, 0, 1, 1, 1, 1, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 1, 1, 0,
+ 0, 1, 1, 0, 1, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 1, 0, 1, 1, 0,
+ 0, 1, 1, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 1, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, // NUMBER 1
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 1, 1, 1, 1, 0, 0, 0,
+ 0, 1, 1, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, // NUMBER 2
+ 0, 0, 1, 1, 1, 1, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, // NUMBER 3
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 1, 1, 1, 0,
+ 0, 0, 0, 1, 1, 1, 0, 0,
+ 0, 0, 1, 1, 1, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 1, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, // NUMBER 4
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, // NUMBER 5
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 1, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, // NUMBER 6
+ 0, 0, 1, 1, 1, 1, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 1, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, // NUMBER 7
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, // NUMBER 8
+ 0, 0, 1, 1, 1, 1, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 1, 1, 1, 1, 0, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 1, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, // NUMBER 9
+ 0, 0, 1, 1, 1, 1, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 1, 1 ,0, 0, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 1, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 };
diff --git a/inc/tga.h b/inc/tga.h
new file mode 100644
index 0000000..4b449f4
--- /dev/null
+++ b/inc/tga.h
@@ -0,0 +1 @@
+void CreateTGA( char *filename, short width, short height, void *image );
diff --git a/inc/upc.h b/inc/upc.h
new file mode 100644
index 0000000..fd0cf01
--- /dev/null
+++ b/inc/upc.h
@@ -0,0 +1,2 @@
+const char* create_upc_a( char *input );
+char upc_a_calculate_check_digit( char *digits );
diff --git a/obj/.gitignore b/obj/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/obj/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/readme b/readme
new file mode 100644
index 0000000..74f8710
--- /dev/null
+++ b/readme
@@ -0,0 +1,11 @@
+ UPC-A Barcode Image Generator Program "upc", by Tyler Delgadillo
+
+ This program converts an 11-digit number into a TGA image file representing a UPC-A barcode.
+
+ Invoke at the command line. This program expects an argument in the form of an 11-digit number.
+You may include spaces to delimit the number system digit, manufacturer code, and product code.
+Additionally, the check digit is calculated automatically.
+
+ Command Line Options:
+ -o : specify output filename, defaults to "img.tga"
+ -n : include human-readable numeric digits in the image
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..b5e115e
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,137 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "./num.h"
+#include "./tga.h"
+#include "./upc.h"
+
+#define UPC_A_WIDTH 113
+#define UPC_A_HEIGHT 79
+
+typedef struct {
+ int eflag;
+ int nflag;
+ char *ovalue;
+} opts;
+
+char *getInput( int index, char *argv[] );
+opts parseOpts( int argc, char *argv[] );
+
+void DrawBarcode( char *dst, const char *src );
+void DrawNumbers( char *dst, const char *src );
+
+int main(int argc, char *argv[]) {
+
+ // Parse CLI options
+ opts options = parseOpts( argc, argv );
+
+ // Parse CLI input
+ char *input = getInput( optind, argv );
+
+ // Set final element of input array to the appropriate check digit
+ input[11] = upc_a_calculate_check_digit( input );
+
+ // Create array of chars to represent 1D barcode
+ const char *barcode = create_upc_a( input );
+
+ // Allocate memory to hold image data
+ char *image = malloc( UPC_A_WIDTH * UPC_A_HEIGHT );
+
+ // Draw barcode to image data
+ DrawBarcode( image, barcode );
+
+ // Draw human-readable interpretation if '-e' is used
+ if( options.nflag ) {
+ DrawNumbers( image, input );
+ }
+
+ free( input );
+
+ // Create a .tga image file using image data
+ CreateTGA( options.ovalue, UPC_A_WIDTH, UPC_A_HEIGHT, image );
+
+ free( image );
+
+ return 0;
+}
+
+
+char *getInput( int index, char *argv[] ) {
+
+ char *result = malloc( 12 );
+
+ int k = 0;
+
+ for( int i = index; argv[i] != NULL; ++i ) {
+ for( int j = 0; j < strlen(argv[i]); ++j ) {
+ if( argv[i][j] < 58 && argv[i][j] > 47 ) {
+ result[k] = argv[i][j];
+ result[k] -= 48;
+ ++k;
+ }
+ }
+ }
+ if( k != 11 ) {
+ printf( "Inappropriate input detected!\nPlease provide an 11-digit number.\n" );
+ }
+
+ return result;
+}
+
+opts parseOpts( int argc, char *argv[] ) {
+
+ opts options = { 0, 0, NULL };
+ int c;
+ while( ( c = getopt(argc, argv, "eno:")) != -1 ) {
+ switch( c ) {
+ case 'e':
+ options.eflag = 1;
+ break;
+ case 'n':
+ options.nflag = 1;
+ break;
+ case 'o':
+ options.ovalue = optarg;
+ break;
+ }
+ }
+ return options;
+}
+
+void DrawBarcode( char *dst, const char *src ) {
+
+ const char UPC_A_QUIET_ZONE[9] = {0};
+
+ for(int i = 0; i < UPC_A_HEIGHT; ++i) {
+ memcpy( dst + (i * UPC_A_WIDTH), &UPC_A_QUIET_ZONE, sizeof(UPC_A_QUIET_ZONE) );
+ memcpy( dst + 9 + (i * UPC_A_WIDTH), src, 95 );
+ memcpy( dst + 104 + (i * UPC_A_WIDTH), &UPC_A_QUIET_ZONE, sizeof(UPC_A_QUIET_ZONE) );
+ }
+
+}
+
+void DrawNumbers( char *dst, const char *src ) {
+ const int POSITION_0 = UPC_A_WIDTH * (UPC_A_HEIGHT - 16) + 1;
+ const int POSITION_1 = UPC_A_WIDTH * (UPC_A_HEIGHT - 16) + 14;
+ const int POSITION_2 = UPC_A_WIDTH * (UPC_A_HEIGHT - 16) + 59;
+ const int POSITION_3 = UPC_A_WIDTH * (UPC_A_HEIGHT - 16) + 104;
+
+ for(int i = 0; i < 16; ++i) {
+ memcpy( dst + POSITION_0 + (i * UPC_A_WIDTH), NUMBER[src[0]][i], sizeof(NUMBER[0][i]) );
+ }
+ for( int i = 0; i < 5; ++i ) {
+ for(int j = 0; j < 16; ++j) {
+ memcpy( dst + POSITION_1 + (j * UPC_A_WIDTH) + (i * 8), NUMBER[src[i + 1]][j], sizeof(NUMBER[0][j]) );
+ }
+ }
+ for( int i = 0; i < 5; ++i ) {
+ for(int j = 0; j < 16; ++j) {
+ memcpy( dst + POSITION_2 + (j * UPC_A_WIDTH) + (i * 8), NUMBER[src[i + 6]][j], sizeof(NUMBER[0][j]) );
+ }
+ }
+ for(int i = 0; i < 16; ++i) {
+ memcpy( dst + POSITION_3 + (i * UPC_A_WIDTH), NUMBER[src[11]][i], sizeof(NUMBER[0][i]) );
+ }
+}
diff --git a/src/tga.c b/src/tga.c
new file mode 100644
index 0000000..95a82d6
--- /dev/null
+++ b/src/tga.c
@@ -0,0 +1,55 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void CreateTGA( char *filename, short width, short height, void *image ) {
+
+ // create file pointer to write to
+ FILE *tga = NULL;
+
+ // write filename from func arg to buffer
+ char buffer[256];
+ if( filename ) {
+ strncpy( buffer, filename, sizeof(buffer) );
+ }
+ // if no filename is provided, set default
+ else {
+ strcpy( buffer, "img.tga" );
+ }
+
+ // open the named file for binary writing
+ tga = fopen( buffer, "wb" );
+
+ // set 'id length' field of tga header
+ fputc( 0, tga );
+
+
+ // set 'color map type' field of tga header
+ fputc( 1, tga ); // color map present
+
+ // set 'image type' field of tga header
+ fputc( 1, tga ); // uncompressed color mapped image
+
+ // set 'color map specification' field of tga header
+ fputc( 0, tga ); fputc( 0, tga ); // 2 byte 'first entry index' subfield, index 0
+ fputc( 2, tga ); fputc( 0, tga ); // 2 byte 'color map length' subfield, 2 entries
+ fputc( 24, tga ); // 'color map entry size' subfield, 24-bit color
+
+ // set 'image specification' field of tga header
+ fputc( 0, tga ); fputc( 0, tga ); // 2 byte 'x-origin' subfield, origin 0
+ fputc( 0, tga ); fputc( 0, tga ); // 2 byte 'y-origin' subfield, origin 0
+ fputc( width & 0xff, tga ); fputc( width >> 8, tga ); // 2 byte 'width' subfield, set by function argument 'w'
+ fputc( height & 0xff, tga ); fputc( height >> 8, tga ); // 2 byte 'height' subfield, set by function argument 'h'
+ fputc( 8, tga ); // 'pixel depth' subfield, 8 bits per pixel
+ fputc( 0x20, tga ); // 'image descriptor' subfield, bit 5 set, indicating top-to-bottom, left-to-right order
+
+ // set 'image and color map data' field
+ fputc( 0xff, tga ); fputc( 0xff, tga ); fputc( 0xff, tga ); // set first color map entry, 0xffffff
+ fputc( 0x00, tga ); fputc( 0x00, tga ); fputc( 0x00, tga ); // set second color map entry, 0x000000
+
+ // write image data
+ fwrite( image, 1, (width * height), tga );
+
+ fclose( tga );
+}
diff --git a/src/upc.c b/src/upc.c
new file mode 100644
index 0000000..a81979b
--- /dev/null
+++ b/src/upc.c
@@ -0,0 +1,113 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UPC_A_WIDTH 95
+#define UPC_A_NUMDIGITS 12
+
+const char UPC_A_GUARD_PATTERN_SE[3] = { 1, 0, 1 };
+const char UPC_A_GUARD_PATTERN_M[5] = { 0, 1, 0, 1, 0 };
+
+const char UPC_DIGIT[10][7] = { { 0, 0, 0, 1, 1, 0, 1 },
+ { 0, 0, 1, 1, 0, 0, 1 },
+ { 0, 0, 1, 0, 0, 1, 1 },
+ { 0, 1, 1, 1, 1, 0, 1 },
+ { 0, 1, 0, 0, 0, 1, 1 },
+ { 0, 1, 1, 0, 0, 0, 1 },
+ { 0, 1, 0, 1, 1, 1, 1 },
+ { 0, 1, 1, 1, 0, 1, 1 },
+ { 0, 1, 1, 0, 1, 1, 1 },
+ { 0, 0, 0, 1, 0, 1, 1 } };
+
+static char upc_calculate_check_digit( char *digits );
+static void upc_draw_pattern( char buffer[], int *index, const char *pattern, int pattern_size );
+static void upc_draw_digits( char *buffer, int *index, char *digits, char isLeft );
+
+const char* create_upc_a( char *input ) {
+
+ // allocate 95 bytes of memory for resultant data
+ char *result = malloc(UPC_A_WIDTH);
+ // create a char array to store the GTIN-12 number
+ char digits[UPC_A_NUMDIGITS];
+
+ int index = 0;
+
+ // copy digits from function param to local array
+ memcpy( digits, input, UPC_A_NUMDIGITS );
+
+ // set the final digit to the appropriate check digit
+ // digits[11] = upc_calculate_check_digit( digits );
+
+ // draw start guard pattern
+ upc_draw_pattern( result, &index, UPC_A_GUARD_PATTERN_SE, sizeof(UPC_A_GUARD_PATTERN_SE) );
+
+ // draw LLLLLL digits
+ upc_draw_digits( result, &index, digits, 1 );
+
+ // draw middle guard pattern
+ upc_draw_pattern( result, &index, UPC_A_GUARD_PATTERN_M, sizeof(UPC_A_GUARD_PATTERN_M) );
+
+ // draw RRRRRR digits
+ upc_draw_digits( result, &index, digits, 0 );
+
+ // draw end guard pattern
+ upc_draw_pattern( result, &index, UPC_A_GUARD_PATTERN_SE, sizeof(UPC_A_GUARD_PATTERN_SE) );
+
+ return result;
+}
+
+char upc_a_calculate_check_digit( char *digits ) {
+
+ char result = 0;
+ int M;
+
+ // 1. Sum digits at odd-numbered positions
+ for( int i = 0; i < UPC_A_NUMDIGITS; ++i ) {
+ if( i % 2 == 0 ) { result += digits[i]; }
+ }
+ // 2. Multiply result by 3
+ result *= 3;
+ // 3. Add digits at even-numbered positions to the result
+ for( int i = 0; i < UPC_A_NUMDIGITS; ++i ) {
+ if( i % 2 != 0 ) { result += digits[i]; }
+ }
+ // 4. Find the result mod 10 and call it "M"
+ M = result % 10;
+ // 5. If M is zero, the check digit is 0,
+ if( M == 0 ) { result = M; }
+ // otherwise the check digit is 10 - M
+ else {
+ result = 10 - M;
+ }
+
+ return result;
+}
+
+static void upc_draw_pattern( char buffer[], int *index, const char *pattern, int pattern_size ) {
+
+ for( int i = 0; i < pattern_size; ++i ) {
+ buffer[*index] = pattern[i];
+ ++*index;
+ }
+}
+
+static void upc_draw_digits( char *buffer, int *index, char *digits, char isLeft ) {
+
+ char temp[6][7];
+ if ( isLeft ) {
+ for( int i = 0; i < 6; ++i ) {
+ memcpy(temp[i], UPC_DIGIT[digits[i]], sizeof( *UPC_DIGIT ) );
+ upc_draw_pattern( buffer, index, temp[i], sizeof( *UPC_DIGIT ) );
+ }
+ }
+ else {
+ for( int i = 0; i < 6; ++i ) {
+ memcpy(temp[i], UPC_DIGIT[digits[i + 6]], sizeof( *UPC_DIGIT ) );
+ //invert values of RRRRRR digits
+ for( int j = 0; j < sizeof( *UPC_DIGIT ); ++j ) {
+ temp[i][j] = !temp[i][j];
+ }
+ upc_draw_pattern( buffer, index, temp[i], sizeof( *UPC_DIGIT ) );
+ }
+ }
+}