/*
* iDART: The Intelligent Dispensing of Antiretroviral Treatment
* Copyright (C) 2006 Cell-Life
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program 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 version
* 2 for more details.
*
* You should have received a copy of the GNU General Public License version 2
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package org.celllife.idart.print.barcode;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.io.File;
import java.util.Vector;
import javax.swing.JComponent;
import org.apache.log4j.Logger;
import org.celllife.idart.print.barcode.CompactCode128.CharacterCode;
import org.celllife.idart.print.label.PrintLayoutUtils;
/*
* Code128 Barcode representation, without barcode text Uses modes B and C to
* acheive compression Based on jbarcodebean,
* http://jbarcodebean.sourceforge.net/
*
*/
/**
*/
public class Barcode extends JComponent {
Logger log = Logger.getLogger(this.getClass());
/**
*
*/
private static final long serialVersionUID = -968438223363997017L;
private final EncodedBarcode encoded;
private int barcodeHeight = 40;
private double angleDegrees;
public String barcodeString;
public static final int windowsBarcodeLength = 35;
public static final int otherOSBarcodeLength = 23;
CharacterCode[] cc;
/**
* Constructor for Barcode.
* @param toEncode String
*/
public Barcode(String toEncode) {
barcodeString = toEncode;
// get the complex code128 string
cc = getComplexCode128String(toEncode);
encoded = getEncodedBarcode(cc);
setForeground(Color.black);
setFont(new Font("Monospaced", Font.PLAIN, 12));
setDoubleBuffered(false);
}
/*
* Get the CharacterCode array representing this string
*
*/
/**
* Method getComplexCode128String.
* @param toBeParsed String
* @return CharacterCode[]
*/
public CharacterCode[] getComplexCode128String(String toBeParsed) {
/*
* By default, produce the mode B encoding
*
*/
Vector<CharacterCode> charCodes = new Vector<CharacterCode>();
for (int k = 0; k < toBeParsed.length(); k++) {
String s = new String(new char[] { toBeParsed.charAt(k) });
charCodes.addElement(CompactCode128.get128BVal(s));
}
/*
* Check the string to see where we have opportunity to compress by
* switching to mode c
*/
for (int i = 0; i < charCodes.size() - 1; i++) {
char c = ((charCodes.elementAt(i)).character.charAt(0));
if (Character.isDigit(c)) {
int checkNext = 0;
for (int j = i + 1; j < charCodes.size(); j++) {
char nextC = ((charCodes.elementAt(j)).character.charAt(0));
if (Character.isDigit(nextC)) {
checkNext++;
} else {
break;
}
}
/*
* Ok, so there are enough characters to make the transition to
* code C worthwile
*/
if (checkNext > 3) {
Integer[] ints = new Integer[2];
ints[0] = new Integer(i);
ints[1] = new Integer(i + checkNext);
charCodes = replaceWithCodeC(charCodes, i, i + checkNext);
i = i + checkNext;
}
}
}
/*
* Now that we have the array, lets work out what the check character
* should be
*/
int weighting = 0;
if (charCodes.size() > 0
&& (charCodes.elementAt(0)).character
.equals(CompactCode128.START_C)) {
weighting += 105;
} else {
charCodes.insertElementAt(CompactCode128
.get128BVal(CompactCode128.START_B), 0);
weighting += 104;
}
for (int i = 1; i < charCodes.size(); i++) {
CharacterCode c = charCodes.elementAt(i);
int c128val = c.check;
weighting += c128val * (i);
// System.out.print(c128val + ":" + c128val * (i) + "+");
}
int checksum = weighting % 103;
CharacterCode checkchar;
checkchar = CompactCode128.get128CValByInt(checksum);
charCodes.add(checkchar);
charCodes.add(CompactCode128.get128CVal(CompactCode128.STOP));
CharacterCode[] charArr = new CharacterCode[charCodes.size()];
charCodes.toArray(charArr);
return charArr;
}
/**
* Method replaceWithCodeC.
* @param toChangeVec Vector<CharacterCode>
* @param start int
* @param stop int
* @return Vector<CharacterCode>
*/
private static Vector<CharacterCode> replaceWithCodeC(
Vector<CharacterCode> toChangeVec, int start, int stop) {
CharacterCode[] toChange = new CharacterCode[toChangeVec.size()];
toChangeVec.toArray(toChange);
Vector<CharacterCode> teenyVec = new Vector<CharacterCode>();
if (start == 0) {
teenyVec.add(CompactCode128.get128BVal(CompactCode128.START_C));
}
else {
teenyVec.add(CompactCode128.get128BVal(CompactCode128.MODE_C));
}
// If it is an odd number, make sure not to include the final digit
if ((stop - start) % 2 == 0) {
stop--;
}
for (int j = start; j < stop; j = j + 2) {
CharacterCode newCode = CompactCode128.get128CVal(new String(
new char[] { toChange[j].character.charAt(0),
toChange[j + 1].character.charAt(0) }));
if (newCode != null) {
teenyVec.addElement(newCode);
}
}
teenyVec.addElement(CompactCode128.get128CVal(CompactCode128.MODE_B));
Vector<CharacterCode> newVec = new Vector<CharacterCode>();
for (int p = 0; p < start; p++) {
newVec.add(toChange[p]);
}
for (int r = 0; r < teenyVec.size(); r++) {
newVec.add(teenyVec.elementAt(r));
}
for (int q = stop + 1; q < toChange.length; q++) {
newVec.add(toChange[q]);
}
return newVec;
}
/*
* Return the barcode as a jbarcodebean.EncodedBarcode This is mostly just
* an array of jbarcodebean.BarcodeElements which are the individual
* bars/spaces.
*
*/
/**
* Method getEncodedBarcode.
* @param charCode CharacterCode[]
* @return EncodedBarcode
*/
private EncodedBarcode getEncodedBarcode(CharacterCode[] charCode) {
int size = (charCode.length * 6) + 3;
BarcodeElement[] elements = new BarcodeElement[size];
// Margin
elements[0] = new BarcodeElement();
elements[0].bar = false;
elements[0].width = 2;
int len = charCode.length;
int j = 1;
for (int i = 0; i < len; i++) {
for (int k = 0; k < charCode[i].widths.length; k++) {
elements[j] = new BarcodeElement();
elements[j].width = charCode[i].widths[k];
elements[j].bar = ((k % 2) == 1) ? false : true;
j++;
}
}
elements[j] = new BarcodeElement();
elements[j].bar = false;
elements[j].width = 2;
j++;
return new EncodedBarcode(elements, barcodeString);
}
/**
* Method getBarcodeHeight.
* @return int
*/
public int getBarcodeHeight() {
return barcodeHeight;
}
/**
* Method getBarcodeLengthInChars.
* @return int
*/
public int getBarcodeLengthInChars() {
return cc.length;
}
/**
* Method setBarcodeHeight.
* @param barcodeHeight int
*/
public void setBarcodeHeight(int barcodeHeight) {
this.barcodeHeight = barcodeHeight;
repaint();
}
// parameters: the graphics context on which to paint this barcode, the x
// offset (barcode will be centered) and the y co-ord of the barcode
/**
* Method doPaint.
* @param graphics Graphics
* @param xPos int
* @param yPos int
*/
public void doPaint(Graphics graphics, int xPos, int yPos) {
// this method is problematic - will not work. - see replacement below
Graphics2D g = (Graphics2D) graphics;
// g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
// RenderingHints.VALUE_ANTIALIAS_ON);
// Dimension d = new Dimension(width,height);
Dimension d = getSize();
log.debug("D.toString(): "+d.toString());
StringBuffer barString = new StringBuffer(encoded.elements.length);
// Save graphics properties
AffineTransform tran = g.getTransform();
Shape oldClip = g.getClip();
Color oldColor = g.getColor();
// Fill control background
g.setColor(Color.WHITE);
g.fillRect(xPos, yPos, d.width, d.height);
g.rotate(angleDegrees / 180 * Math.PI, d.width / 2.0, d.height / 2.0);
// Draw barcode
if (encoded != null) {
for (int i = 0; i < encoded.elements.length; i++) {
if (encoded.elements[i].bar == true) {
switch (encoded.elements[i].width) {
case 1:
barString.append("A");
break;
case 2:
barString.append("B");
break;
case 3:
barString.append("C");
break;
case 4:
barString.append("D");
break;
}
}
else if (encoded.elements[i].bar == false) {
switch (encoded.elements[i].width) {
case 1:
barString.append(" ");
break;
case 2:
barString.append(" ");
break;
case 3:
barString.append(" ");
break;
case 4:
barString.append(" ");
break;
}
}
}
}
try {
File fontFile = new File("Code128mel.ttf");
Font barFont = Font.createFont(Font.TRUETYPE_FONT, fontFile);
barFont = barFont.deriveFont(Font.PLAIN, 12);
g.setFont(barFont);
g.setColor(Color.BLACK);
FontMetrics fm = g.getFontMetrics();
g.drawString(barString.toString(), PrintLayoutUtils.center(fm, barString.toString(), (int)d.getWidth()), yPos);
log.debug("============BarString.toString(): "+barString.toString());
log.debug("WIDTH: " + (int)d.getWidth());
//g.drawString(barString.toString(), PrintLayoutUtils.center(fm, barString.toString(), xPos), yPos);
}
catch (java.io.IOException e) {
e.printStackTrace();
} catch (FontFormatException fe) {
fe.printStackTrace();
}
// Restore graphics properties
g.setTransform(tran);
g.setClip(oldClip);
g.setColor(oldColor);
}
public void doPaint(Graphics graphics, int xPos, int yPos, int height, int width) {
Graphics2D g = (Graphics2D) graphics;
// g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
// RenderingHints.VALUE_ANTIALIAS_ON);
Dimension d = new Dimension(width,height);
log.debug("D.toString(): "+d.toString());
StringBuffer barString = new StringBuffer(encoded.elements.length);
// Save graphics properties
AffineTransform tran = g.getTransform();
Shape oldClip = g.getClip();
Color oldColor = g.getColor();
g.rotate(angleDegrees / 180 * Math.PI, d.width / 2.0, d.height / 2.0);
// Draw barcode
if (encoded != null) {
for (int i = 0; i < encoded.elements.length; i++) {
if (encoded.elements[i].bar == true) {
switch (encoded.elements[i].width) {
case 1:
barString.append("A");
break;
case 2:
barString.append("B");
break;
case 3:
barString.append("C");
break;
case 4:
barString.append("D");
break;
}
}
else if (encoded.elements[i].bar == false) {
switch (encoded.elements[i].width) {
case 1:
barString.append(" ");
break;
case 2:
barString.append(" ");
break;
case 3:
barString.append(" ");
break;
case 4:
barString.append(" ");
break;
}
}
}
}
try {
File fontFile = new File("Code128mel.ttf");
Font barFont = Font.createFont(Font.TRUETYPE_FONT, fontFile);
barFont = barFont.deriveFont(Font.PLAIN, 32f);
g.setFont(barFont);
g.setColor(Color.BLACK);
FontMetrics fm = g.getFontMetrics();
g.drawString(barString.toString(), PrintLayoutUtils.center(fm, barString.toString(), (int)d.getWidth()), yPos);
log.debug("============BarString.toString(): "+barString.toString());
log.debug("WIDTH: " + (int)d.getWidth());
//g.drawString(barString.toString(), PrintLayoutUtils.center(fm, barString.toString(), xPos), yPos);
}
catch (java.io.IOException e) {
e.printStackTrace();
} catch (FontFormatException fe) {
fe.printStackTrace();
}
// Restore graphics properties
g.setTransform(tran);
g.setClip(oldClip);
g.setColor(oldColor);
}
public static int getLengthForCurrentOS(){
String OSName = System.getProperty("os.name").toUpperCase(); //$NON-NLS-1$
if (OSName.startsWith("WINDOWS")) { //$NON-NLS-1$
return windowsBarcodeLength;
} else{
return otherOSBarcodeLength;
}
}
}