Wrote an EAN13 barcode program

I decided to write a barcode generator in Java “for no apparent reason”, that can currently generator EAN13 barcodes. It’s available here in this post, but if you want the latest code then I suggest you check it out on github.

Github repo:
https://github.com/jra89/barcode

Usage:

java -jar barcode.jar numbers path barwidth barheight

Example:

java -jar barcode.jar 999990000020 /home/user/Desktop/EAN_IMG.png 2 60

Main.java

package barcode;

public class Main
{
	public static void main(String[] args)
	{
		String code;
		String path;
		int barWidth;
		int barHeight;

		if(args.length <= 1)
		{
			System.out.println("Not enough parameters");
		}
		
		try
		{
			code = args[0]; 
		}
		catch(NullPointerException e)
		{
			code = "9999900000207";
		}
		
		try
		{
			path = args[1];
		}
		catch(NullPointerException e)
		{
			path = "/tmp/barcode.png";
		}
		
		try
		{
			barWidth = Integer.parseInt(args[2]);
		}
		catch(NullPointerException e)
		{
			barWidth = 1;
		}
		
		try
		{
			barHeight = Integer.parseInt(args[3]);
		}
		catch(NullPointerException e)
		{
			barHeight = 100;
		}

		Ean13 ean = new Ean13(code, path, barWidth, barHeight);
		ean.createBarcodePNG();

	}
}

Ean13.java

package barcode;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class Ean13 
{
	/**
	 * -=Structure=-
	 * 
	 * Fist, First Six, Last Six
	 * LGR = 012
	 * 0 	LLLLLL 	RRRRRR
	 * 1 	LLGLGG 	RRRRRR
	 * 2 	LLGGLG 	RRRRRR
	 * 3 	LLGGGL 	RRRRRR
	 * 4 	LGLLGG 	RRRRRR
	 * 5 	LGGLLG 	RRRRRR
	 * 6 	LGGGLL 	RRRRRR
	 * 7 	LGLGLG 	RRRRRR
	 * 8 	LGLGGL 	RRRRRR
	 * 9 	LGGLGL 	RRRRRR
	 *
	 * -=Encodings=-
	 *
	 * Digit 	L-code 	G-code 	R-code
	 * 0 	0001101 	0100111 	1110010
	 * 1 	0011001 	0110011 	1100110
	 * 2 	0010011 	0011011 	1101100
	 * 3 	0111101 	0100001 	1000010
	 * 4 	0100011 	0011101 	1011100
	 * 5 	0110001 	0111001 	1001110
	 * 6 	0101111 	0000101 	1010000
	 * 7 	0111011 	0010001 	1000100
	 * 8 	0110111 	0001001 	1001000
	 * 9 	0001011 	0010111 	1110100
	**/
	
	private String code;
	private String path;
	private BufferedImage bi;
    private Graphics2D ig2;
    private int barPos;
    private int barPosBin;
    private int imgPixelPos;
    private int barWidth;
	private int barHeight;
	private int imgWidth;
	private int imgHeight;
    private int[][] barcodeBinary;
	
	private int[][] firstSix = {
			{0,0,0,0,0,0}, //LLLLLL
			{0,0,1,0,1,1}, //LLGLGG
			{0,0,1,1,0,1}, //LLGGLG
			{0,0,1,1,1,0}, //LLGGGL
			{0,1,0,0,1,1}, //LGLLGG
			{0,1,1,0,0,1}, //LGGLLG
			{0,1,1,1,0,0}, //LGGGLL
			{0,1,0,1,0,1}, //LGLGLG
			{0,1,0,1,1,0}, //LGLGGL
			{0,1,1,0,1,0}  //LGGLGL
	};
	
	private int[] lastSix = {2, 2, 2, 2, 2, 2};
	
	private int[][][] encodings = {
			{
				{0,0,0,1,1,0,1}, 
				{0,1,0,0,1,1,1}, 
				{1,1,1,0,0,1,0}
			},
			{
				{0,0,1,1,0,0,1},
				{0,1,1,0,0,1,1},
				{1,1,0,0,1,1,0}
			},
			{
				{0,0,1,0,0,1,1},
				{0,0,1,1,0,1,1}, 	
				{1,1,0,1,1,0,0}
			},
			{
				{0,1,1,1,1,0,1},
				{0,1,0,0,0,0,1},
				{1,0,0,0,0,1,0}
			},
			{
				{0,1,0,0,0,1,1},
				{0,0,1,1,1,0,1},
				{1,0,1,1,1,0,0}
			},
			{
				{0,1,1,0,0,0,1},
				{0,1,1,1,0,0,1},
				{1,0,0,1,1,1,0}
			},
			{
				{0,1,0,1,1,1,1},
				{0,0,0,0,1,0,1},
				{1,0,1,0,0,0,0}
			},
			{
				{0,1,1,1,0,1,1},
				{0,0,1,0,0,0,1},
				{1,0,0,0,1,0,0}
			},
			{
				{0,1,1,0,1,1,1},
				{0,0,0,1,0,0,1},
				{1,0,0,1,0,0,0}
			},
			{
				{0,0,0,1,0,1,1},
				{0,0,1,0,1,1,1},
				{1,1,1,0,1,0,0}
			}
	};
	
	Ean13(String code, String path,int barWidth, int barHeight)
	{
		this.code = code;
		this.path = path;
		this.barPos = 12;
		this.barPosBin = 7;
		this.imgPixelPos = 0;
		this.barcodeBinary = new int[barPos][barPosBin];
		this.barWidth = barWidth;
		this.barHeight = barHeight;
		this.imgWidth = ((12*7) + (2*9) + (2*3) + (1*5)) * this.barWidth;
		this.imgHeight = this.barHeight;
	}
    
	public void createBarcodePNG()
	{
		this.code += Integer.toString(calculateControlDigit(this.code));
		generateBinaryMap();
		generateBarcodePNG();
	}
	
	private void generateBinaryMap()
	{
		int first = Integer.parseInt(String.valueOf(this.code.charAt(0)));
				
		//i = 1, first digit is not welcome to the bar
		for(int i = 1; i < 13; ++i)
		{
			int current = Integer.parseInt(String.valueOf(this.code.charAt(i)));
			
			if(i < 7)
				this.barcodeBinary[i-1] = this.encodings[current][this.firstSix[first][i-1]];
			else
				this.barcodeBinary[i-1] = this.encodings[current][this.lastSix[i-7]];
		}
	}
	
	private void generateBarcodePNG()
	{
		try {
		      // TYPE_INT_ARGB specifies the image format: 8-bit RGBA packed
		      // into integer pixels
		      bi = new BufferedImage(this.imgWidth, this.imgHeight, BufferedImage.TYPE_INT_ARGB);
		      ig2 = bi.createGraphics();
		      
		      ig2.setPaint(Color.white);
		      ig2.fillRect ( 0, 0, bi.getWidth(), bi.getHeight() );

		      //Draw quiet zone
		      drawSpecial(0);
		      
		      //Draw lead
		      drawSpecial(1);
		      
		      //Draw first group
		      drawGroup(1);
		      
		      //Draw separator
		      drawSpecial(2);
		      
		      //Draw second group
		      drawGroup(2);
		      
		      //Draw lead
		      drawSpecial(1);
		      
		      //Draw quiet zone
		      drawSpecial(0);

		      ImageIO.write(bi, "PNG", new File(path));
		      
		    } catch (IOException ie) {
		      ie.printStackTrace();
		    }
	}
	
	private void drawGroup(int groupPart)
	{
		int i = 0, length = 0;
		if(groupPart == 1)
		{
			i = 0;
			length = (this.barcodeBinary.length/2);
		}
		else if(groupPart == 2)
		{
			i = 6;
			length = this.barcodeBinary.length;
		}
			
		for(; i < length; ++i)
		{
			for(int n = 0; n < this.barcodeBinary[i].length; ++n)
			{
				if(this.barcodeBinary[i][n] == 0)
				{
					ig2.setPaint(Color.white);
				    ig2.setStroke(new BasicStroke(this.barWidth));
				}
				else
				{
					ig2.setPaint(Color.black);
					ig2.setStroke(new BasicStroke(this.barWidth));
				}
				  		  
				int pos = this.imgPixelPos;
				ig2.drawLine(pos,0,pos,this.barHeight);
				this.imgPixelPos += this.barWidth;
			}
		}
	}
	
	private void drawSpecial(int type)
	{
		
		/*
		Special Symbol Pattern
		Quite Zone 	000000000
		Lead / Trailer 	101
		Separator 	01010
		 */
		
		int[] quiteZone = {0,0,0,0,0,0,0,0,0};
		int[] leadtrail = {1,0,1};
		int[] separator = {0,1,0,1,0};
		int binaryArrLength = 0;
		int[] arr;
		
		if(type == 0)
		{
			binaryArrLength = quiteZone.length;
			arr = quiteZone;
		}
		else if(type == 1)
		{
			binaryArrLength = leadtrail.length;
			arr = leadtrail;
		}
		else
		{
			binaryArrLength = separator.length;
			arr = separator;
		}

		for(int n = 0; n < binaryArrLength; ++n)
		{
			if(arr[n] == 0)
				ig2.setPaint(Color.white);
			else
				ig2.setPaint(Color.black);
			  		  
			int pos = this.imgPixelPos;
			ig2.drawLine(pos,0,pos,this.barHeight);
			this.imgPixelPos += this.barWidth;
		}
	}
	
	public int calculateControlDigit(String ean)
	{
		int sum = 0;
		for(int i = 0; i < 12; ++i)
		{
			int val = charToInt(ean.charAt(i));
			if((i+1)%2 == 0)
				sum += val*3;
			else
				sum += val*1;	
		}

		return (10 - (sum % 10));
	}
	
	private int charToInt(char c)
	{
		return Integer.parseInt(String.valueOf(c));
	}
}

4 thoughts on “Wrote an EAN13 barcode program

  1. Pingback: Reverse vending machines, wrapping it up | Alcor blog

    • Well it’s a very limited application with no options really. So if you wanted more extended features then the code would grow rather fast 🙂

      Like

  2. Pingback: Reverse vending machines, wrapping it up | Alcor

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.