import java.awt.Color;

import java.awt.Font;

import java.awt.FontMetrics;

import java.awt.Graphics;

import java.awt.Graphics2D;

import java.awt.image.BufferedImage;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.util.Base64;


import javax.imageio.ImageIO;


import org.jbarcode.encode.BarSet;

import org.jbarcode.encode.BarcodeEncoder;

import org.jbarcode.encode.Code128Encoder;

import org.jbarcode.encode.EAN13Encoder;

import org.jbarcode.encode.InvalidAtributeException;


public class BarcodeUtil {


private int width;

private int barWidth;

private double ratio;

private BufferedImage img;

private Boolean showCodeText = false;

private Boolean showLabel = false;


public BarcodeUtil(int barWidth, int ratio) {

this.barWidth = barWidth;

this.ratio = ratio;

}


public BarcodeUtil(int barWidth) {

this(barWidth, 0);

}


public BarcodeUtil() {

this(1, 0);

}


public int getWidth() {

return this.width;

}



public double getRatio() {

return this.ratio;

}


public void setBarWidth(int barWidth) {

this.barWidth = barWidth;

}



public void setRatio(double ratio) {

this.ratio = ratio;

}


public BufferedImage getImage() {

return this.img;

}



public String createCode(String moduleNumber, String label) throws InvalidAtributeException, IOException {

BarcodeEncoder encoder;

String code = moduleNumber;

if (12 == moduleNumber.length()) {

encoder = EAN13Encoder.getInstance();

code += encoder.computeCheckSum(moduleNumber);

} else {

encoder = Code128Encoder.getInstance();

}

BarSet [] encoded = encoder.encode(code);

img = paintBar(encoded, barWidth, ratio);

if (label.isEmpty()||label.equals("-")) paintCodeText(code, 8);

else paintLabel(label, 10);

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

ImageIO.write(img, "BMP", outputStream);

byte[] bytes = outputStream.toByteArray();

return Base64.getEncoder().encodeToString(bytes).trim();

}



public void createCode(String moduleNumber) throws InvalidAtributeException, IOException {

createCode(moduleNumber, "");

}


public BufferedImage paintBar(BarSet[] barcode, int barWidth, double ratio) {

width = 0;

for (int i = 0; i < barcode.length; i++) {

width += barcode[i].length();

}

width *= barWidth;

if (0 >= ratio) ratio = 0.54;

int barHeight = (int)(ratio * width);

BufferedImage result = new BufferedImage(width, barHeight, BufferedImage.TYPE_BYTE_BINARY);

Graphics2D g2d = result.createGraphics();

int x = 0;

for (int i = 0; i < barcode.length; i++) {

for (int j = 0; j < barcode[i].length(); j++) {

g2d.setColor(barcode[i].get(j) ? Color.BLACK : Color.WHITE);

g2d.fillRect(x, 0, barWidth, barHeight);

x += barWidth;

}

}

g2d.dispose();

return result;

}


public void paintCodeText(String code, int fontSize) {

showCodeText = true;

if (13 != code.length()) fontSize = fontSize * code.length() / 14;

Font font = new Font("monospace", Font.PLAIN, fontSize * barWidth);

Graphics g2d = img.getGraphics();

g2d.setFont(font);

FontMetrics fontMetrics = g2d.getFontMetrics();

if (13 == code.length()) {

int digitWidht = barWidth * 7;

int textHeight = fontMetrics.getAscent();

int textXShift = (digitWidht - fontMetrics.stringWidth("0"))/2;

int textYPos = img.getHeight() - textHeight*3/10;

int y = img.getHeight() - textHeight*6/5;

g2d.setColor(Color.WHITE);

g2d.fillRect(0, img.getHeight() - textHeight*3/5, img.getWidth(), textHeight*3/5);

if (!showLabel) g2d.fillRect(0, 0, img.getWidth(), img.getHeight()*1/20);

g2d.fillRect(barWidth * 11, y, digitWidht*6, textHeight);

g2d.fillRect(barWidth * 57, y, digitWidht*6, textHeight);

g2d.setColor(Color.BLACK);

g2d.drawString(code.substring(0, 1), 8 * barWidth - fontMetrics.stringWidth("0") - textXShift, textYPos);

for (int i=1; i<13; i++) {

int textXPos = ((i < 7 ? 4 : 8) + 7*i) * barWidth + textXShift;

g2d.drawString("" + code.charAt(i), textXPos, textYPos);

}

} else {

int textWidth = fontMetrics.stringWidth(code);

int textHeight = fontMetrics.getAscent();

int textYPos = img.getHeight() - textHeight * 3 / 10;

g2d.setColor(Color.WHITE);

g2d.fillRect(0, img.getHeight() - textHeight * 6 / 5, img.getWidth(), textHeight * 6 / 5);

if (!showLabel) g2d.fillRect(0, 0, img.getWidth(), img.getHeight() * 1 / 20);

g2d.setColor(Color.BLACK);

g2d.drawString(code, (img.getWidth() - textWidth) / 2, textYPos);

}

g2d.dispose();

}



public void paintLabel(String label, int fontSize) {

showLabel = true;

if (fontSize < 3) return;

Font font = new Font("monospace", Font.PLAIN, fontSize * barWidth);

Graphics g2d = img.getGraphics();

g2d.setFont(font);

FontMetrics fontMetrics = g2d.getFontMetrics();

int textWidth = fontMetrics.stringWidth(label);

if (img.getWidth() - textWidth < 8 * barWidth) {

paintLabel(label, fontSize - 1);

return;

}

int textHeight = fontMetrics.getAscent();

g2d.setColor(Color.WHITE);

g2d.fillRect(0, 0, img.getWidth(), textHeight*7/5+2*barWidth);

if (!showCodeText) g2d.fillRect(0, img.getHeight() - 4*barWidth, img.getWidth(), 4*barWidth);

g2d.setColor(Color.BLACK);

g2d.drawString(label, (img.getWidth() - textWidth)/2, textHeight*11/10+barWidth*3/2);

g2d.dispose();

}

}