CardPrintBean.java 12.1 KB
package fi.codecrew.moya.beans;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOInvalidTreeException;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.ImageOutputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.pdfjet.CoreFont;
import com.pdfjet.Image;
import com.pdfjet.ImageType;
import com.pdfjet.PDF;
import com.pdfjet.Page;
import com.pdfjet.TextLine;

import fi.codecrew.moya.facade.CardTemplateFacade;
import fi.codecrew.moya.facade.EventUserFacade;
import fi.codecrew.moya.facade.PrintedCardFacade;
import fi.codecrew.moya.facade.UserFacade;
import fi.codecrew.moya.model.CardTemplate;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.PrintedCard;
import fi.codecrew.moya.util.MassPrintResult;

/**
 * Session Bean implementation class CardPrintBean
 */
@Stateless
@LocalBean
public class CardPrintBean implements CardPrintBeanLocal {

	@EJB
	private UserBean userBean;
	@EJB
	private EventUserFacade eventUserFacade;
	@EJB
	private CardTemplateBean cardTemplateBean;
	@EJB
	private CardTemplateFacade cardTemplateFacade;
	@EJB
	private UserFacade userfacade;
	@EJB
	private BarcodeBean barcodeBean;
	@EJB
	private PrintedCardFacade printedCardFacade;
	private static final Logger logger = LoggerFactory.getLogger(CardPrintBean.class);

	private int nick_x = 0;
	private int nick_y = 0;

	/**
	 * Default constructor.
	 */
	public CardPrintBean() {
		// TODO Auto-generated constructor stub
	}

	// TODO: Roles?
	public MassPrintResult getUserCardsAsPrintablePdf(List<Integer> userIdList) throws Exception {
		ArrayList<EventUser> listOfEventUsers = new ArrayList<EventUser>();

		for (Integer userId : userIdList) {
			listOfEventUsers.add(eventUserFacade.find(userId));
		}

		return constructPdf(listOfEventUsers);
	}

	public MassPrintResult getUserCardAsPrintablePdf(Integer userId) throws Exception {
		ArrayList<EventUser> listOfEventUsers = new ArrayList<EventUser>();

		listOfEventUsers.add(eventUserFacade.find(userId));

		return constructPdf(listOfEventUsers);
	}

	public void acceptMassPrintResult(MassPrintResult mpr) {
		for (EventUser eu : mpr.getAffectedUsers()) {
			PrintedCard printedCard = cardTemplateBean.checkPrintedCard(eu);
			printedCard.setPrintCount(printedCard.getPrintCount() + 1);
			System.out.println("Print count " + printedCard.getPrintCount());
		}

		cardTemplateFacade.flush();
	}

	private MassPrintResult constructPdf(List<EventUser> users) throws Exception {

		// double[] pageSize = new double[] { cardBackground.getWidth(),
		// cardBackground.getHeight() };

		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

		PDF pdf = new PDF(outputStream);
		pdf.setTitle("CARD");

		float pagex = 155.52f; // 54,0 mm
		float pagey = 243.84f; // 85,5 mm

		MassPrintResult mpr = new MassPrintResult();

		for (EventUser user : users) {

			PrintedCard printedCard = cardTemplateBean.checkPrintedCard(user);

			if (printedCard == null)
				continue;

			CardTemplate cardTemplate = printedCard.getTemplate();

			BufferedImage cardBackground = ImageIO.read(new ByteArrayInputStream(
					cardTemplate.getImage()));

			BufferedImage faceBufferedImage = ImageIO
					.read(new ByteArrayInputStream(user.getCurrentImage().getImageData()));

			/*
			 * if (faceBufferedImage.getWidth() > 1024 ||
			 * faceBufferedImage.getHeight() > 1024) { throw new
			 * Exception("Image dimensions too large, please take/upload smaller!"
			 * ); }
			 */
			int originalWidth = faceBufferedImage.getWidth();
			int originalHeight = faceBufferedImage.getHeight();

			int width = originalWidth;
			int height = (int) Math.round(originalWidth * (1 / 0.7317073170731707));

			if (height > originalHeight) {
				height = originalHeight;
				width = (int) Math.round(originalHeight * 0.7317073170731707);
			}

			int offsetx = (originalWidth - width) / 2;
			int offsety = (originalHeight - height) / 2;

			faceBufferedImage = faceBufferedImage.getSubimage(offsetx, offsety, width, height);

			Page page = new Page(pdf, new float[] { pagex, pagey });

			// Render background image
			Image templateImage = new Image(pdf,
					convertBufferedImageToPng(cardBackground), ImageType.PNG);
			templateImage.setPosition(0, 0);
			templateImage.scaleBy(0.245);
			templateImage.drawOn(page);

			// Render face image
			Image faceImage = new Image(pdf,
					convertBufferedImageToPng(faceBufferedImage), ImageType.PNG);
			faceImage.setPosition(15.5, 67);
			//faceImage.setPosition(175, 222);
			// faceImage.scaleBy(0.32);
			faceImage.scaleBy(((410.0 * 0.245) / faceImage.getHeight()));
			faceImage.drawOn(page);

			// Render texts
			// Big font for nick
			com.pdfjet.Font nickFont = new com.pdfjet.Font(pdf, CoreFont.HELVETICA);
			nickFont.setSize(16.0);

			// User nick text

			TextLine nickTextLine = new TextLine(nickFont);
			nickTextLine.setText(user.getUser().getNick());
			nickTextLine.setPosition(19.0, 193.0);
			nickTextLine.setColor(new int[] { 1, 1, 1 });
			nickTextLine.drawOn(page);

			// Smaller font
			com.pdfjet.Font font = new com.pdfjet.Font(pdf, CoreFont.HELVETICA);
			font.setSize(10.0);

			// Full name text
			String wholeName = user.getUser().getFirstnames() + " "
					+ user.getUser().getLastname();
			TextLine wholeNameText = new TextLine(font);
			wholeNameText.setText(wholeName);
			wholeNameText.setPosition(17.0, 212.0);
			wholeNameText.setColor(new int[] { 1, 1, 1 });
			wholeNameText.drawOn(page);

			// Role text
			TextLine roleTextLine = new TextLine(font);
			roleTextLine.setText(cardTemplate.getName());
			roleTextLine.setPosition(17.0, 223.0);
			roleTextLine.setColor(new int[] { 1, 1, 1 });
			roleTextLine.drawOn(page);

			// Barcode
			// String barcodeString =
			// String.valueOf(user.getUser().getCreated().getTime().getTime());

			// barcodeString = barcodeString.substring(barcodeString.length() -
			// 12);

			BufferedImage barCodeBufferedImage = ImageIO.read(barcodeBean.getCardBarcode(printedCard));
			Image barCodeImage = new Image(pdf, convertBufferedImageToPng(barCodeBufferedImage), ImageType.PNG);
			barCodeImage.setPosition(0.0, 230);// 243.5);
			barCodeImage.scaleBy(0.7);
			barCodeImage.drawOn(page);

			mpr.getAffectedUsers().add(user);
		}
		pdf.flush();
		outputStream.close();

		if (mpr.getAffectedUsers().size() == 0)
			throw new Exception("No cards generated");
		mpr.setPdf(outputStream.toByteArray());
		return mpr;
	}

	@Override
	public byte[] constructPNG(PrintedCard card) throws Exception {
		if (card == null) {
			return null;
		}

		card = printedCardFacade.reload(card);
		// logger.info("Printing card tpl {} with template image  {}",
		// card.getTemplate(), card.getTemplate().getImage());
		EventUser user = card.getUser();

		BufferedImage face = ImageIO.read(new ByteArrayInputStream(user.getUser().getCurrentImage().getImageData()));

		BufferedImage base = ImageIO.read(new ByteArrayInputStream(card.getTemplate().getImage()));

		BufferedImage outimage = new BufferedImage(base.getWidth(), base.getHeight(), BufferedImage.TYPE_INT_RGB);

		Graphics2D g = outimage.createGraphics();
		// g.drawImage(org, AffineTransform.getScaleInstance(0.31, 0.31), null);
		g.drawImage(base, 0, 0, base.getWidth(), base.getHeight(), null);
		// g.drawImage(face, AffineTransform.getScaleInstance(0.31, 0.31),
		// null);
		g.drawImage(face, 174, 237, 301, 410, null);
		g.setFont(new Font("Century gothic", Font.PLAIN, 70));

		Font font = new Font("Century gothic", Font.PLAIN, 70);
		int nickWidth = g.getFontMetrics(font).stringWidth(user.getUser().getNick());

		int nickX = (646 / 2) - (nickWidth / 2);
		int nickY = 750;

		//Color transparentWhite = new Color(255, 255, 255, 140);
		//g.setColor(transparentWhite);
		//g.fillRect(nickX - 20, nickY - 50, nickWidth + 40, 50);

		g.setColor(Color.black);
		g.setFont(font);
		g.drawString(user.getUser().getNick(), nickX, nickY);

		g.setFont(new Font("Century gothic", Font.BOLD, 45));

		StringBuilder wholeName = new StringBuilder();
		wholeName.append(user.getUser().getFirstnames()).append(" ").append(user.getUser().getLastname());

		// g.setFont(new Font("Arial", Font.BOLD, 35));
		// g.drawString(name, 595 -
		// g.getFontMetrics().charsWidth(name.toCharArray(), 0, name.length()),
		// 890);
		//
		// g.drawString(owner.getId().toString(), 60, 948);

		g.setFont(new Font("Century gothic", Font.BOLD, 40));
		g.drawString(wholeName.toString(), 60, 950);
		//g.drawString(card.getTemplate().getName(), 60, 915);

		PrintedCard printedCard = cardTemplateBean.checkPrintedCard(user);

		g.setFont(new Font("Century gothic", Font.PLAIN, 30));
		g.setColor(Color.white);
		if (printedCard != null)
			g.drawString(barcodeBean.getVrAuthCodeForCard(printedCard), 445, 905);

		BufferedImage barCodeBufferedImage = ImageIO.read(barcodeBean.getCardBarcode(printedCard));

		//int barcodeX = (base.getWidth()/2) - (image.getWidth()/2);
		int barcodeX = (base.getWidth() - 400) / 2;
		int barcodeY = base.getHeight() - 50;
		if (printedCard != null)
			g.drawImage(barCodeBufferedImage, barcodeX, barcodeY, 400, barCodeBufferedImage.getHeight(), null);

		g.setColor(Color.white);

		g.fillRect(0, base.getHeight() - 20, base.getWidth(), base.getHeight());
		g.dispose();

		ByteArrayOutputStream ostr = new ByteArrayOutputStream();

		for (Iterator<ImageWriter> pngWriter = ImageIO.getImageWritersByFormatName("png"); pngWriter.hasNext();)
		{
			ImageWriter writer = pngWriter.next();
			logger.info("Trying to write with writer {}", writer);

			ImageWriteParam writeParam = writer.getDefaultWriteParam();
			ImageTypeSpecifier typeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
			IIOMetadata metadata = writer.getDefaultImageMetadata(typeSpecifier, writeParam);
			if (metadata.isReadOnly() || !metadata.isStandardMetadataFormatSupported()) {
				continue;
			}

			setDPI(metadata);

			final ImageOutputStream stream = ImageIO.createImageOutputStream(ostr);
			try {
				writer.setOutput(stream);
				writer.write(metadata, new IIOImage(outimage, null, metadata), writeParam);
			} finally {
				stream.close();
			}
			break;

		}

		// ImageIO.write(outimage, "png", ostr);

		byte[] ret = ostr.toByteArray();
		logger.info("Returning {} bytes for pngimage", ret.length);

		// double meter2inchRatio = 1d / 0.0254d;
		// int dpi = 300;
		// int dim = (int) (dpi * meter2inchRatio) + 1;

		return ret;
	}

	private ByteArrayInputStream convertBufferedImageToPng(BufferedImage img)
			throws IOException {
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		ImageIO.write(img, "png", outStream);
		outStream.close();

		return new ByteArrayInputStream(outStream.toByteArray());
	}

	private static void setDPI(IIOMetadata metadata) throws IIOInvalidTreeException {

		// for PMG, it's dots per millimeter
		double dotsPerMilli = 1.0 * 300 / 10 / 2.54;

		IIOMetadataNode horiz = new IIOMetadataNode("HorizontalPixelSize");
		horiz.setAttribute("value", Double.toString(dotsPerMilli));

		IIOMetadataNode vert = new IIOMetadataNode("VerticalPixelSize");
		vert.setAttribute("value", Double.toString(dotsPerMilli));

		IIOMetadataNode dim = new IIOMetadataNode("Dimension");
		dim.appendChild(horiz);
		dim.appendChild(vert);

		IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
		root.appendChild(dim);

		metadata.mergeTree("javax_imageio_1.0", root);
	}
}