com.identityx.clientSDK.piiSupport.PNGUtility Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of IdentityXClientSDK Show documentation
Show all versions of IdentityXClientSDK Show documentation
Client SDK for IdentityX Rest Services
package com.identityx.clientSDK.piiSupport;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.imageio.ImageIO;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/*
* Utility class for image resizing
*
*/
public class PNGUtility {
private static final Log logger = LogFactory.getLog(PNGUtility.class);
private List fontSizes = Arrays.asList( 60, 48, 36, 28, 26, 24, 22,20, 18, 16, 14, 12, 11, 10, 9, 8);
class TextDetails {
private List lines = new ArrayList();
private int fontSize;
private boolean overrun;
public TextDetails(int fontSize, String firstLine, boolean overrun) {
this.lines.add(firstLine);
this.fontSize = fontSize;
this.overrun = overrun;
}
public TextDetails(int fontSize, boolean overrun) {
this.fontSize = fontSize;
this.overrun = overrun;
}
public TextDetails(int fontSize) {
this.fontSize = fontSize;
}
public List getLines() {
return lines;
}
public void addLine(String line) {
this.lines.add(line);
}
public int getFontSize() {
return fontSize;
}
public void setFontSize(int fontSize) {
this.fontSize = fontSize;
}
public boolean isOverrun() {
return overrun;
}
public void setOverrun(boolean overrun) {
this.overrun = overrun;
}
}
public BufferedImage createPNGFromBase64Data(String content) throws IOException
{
BufferedImage bufferedImage = null;
byte[] imageContent = Base64.decodeBase64(content);
try {
bufferedImage = ImageIO.read(new ByteArrayInputStream(imageContent));
} catch (IOException e) {
logger.error("The PNG Data supplied for the transaction was not valid");
throw e;
}
return bufferedImage;
}
public BufferedImage resizePNGFromBase64Data(DisplayPNGCharacteristics descriptor, String content) throws IOException
{
BufferedImage bufferedImage = null;
byte[] imageContent = Base64.decodeBase64(content);
BufferedImage scaledImage = null;
if (descriptor != null)
{
try {
bufferedImage = ImageIO.read(new ByteArrayInputStream(imageContent));
scaledImage = this.getScaledInstance(bufferedImage, (int)descriptor.getWidth(), (int)descriptor.getHeight(), RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR, false);
} catch (IOException e) {
logger.error("The PNG Data supplied for the transaction was not valid");
throw e;
}
return scaledImage;
}
else
{
logger.error("Null DisplayPNGCharacteristicsDescriptor supplied so just returning the original image");
}
return bufferedImage;
}
public String createBase64DatafromPNG(BufferedImage image) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ImageIO.write(image, "png", baos);
} catch (IOException e) {
logger.error("Failed to write the scaled PNG image");
throw e;
}
return Base64.encodeBase64URLSafeString(baos.toByteArray());
}
public DisplayPNGCharacteristics getDisplayCharacteristicsOfImage(String content) throws IOException
{
BufferedImage image = createPNGFromBase64Data(content);
DisplayPNGCharacteristics pngDescriptor = new DisplayPNGCharacteristics();
int bitDepth = image.getColorModel().getPixelSize();
pngDescriptor.setBitDepth(bitDepth);
pngDescriptor.setWidth(image.getWidth());
pngDescriptor.setHeight(image.getHeight());
return pngDescriptor;
}
public BufferedImage getScaledInstance(BufferedImage img, int targetWidth, int targetHeight, Object hint, boolean higherQuality)
{
int type = (img.getTransparency() == Transparency.OPAQUE) ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage)img;
int w, h;
h = img.getHeight();
w = img.getWidth();
if (higherQuality)
{
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached w = img.getWidth();
double scaleFactor = determineImageScale(w, h, targetWidth, targetHeight);
w = (int) (w * scaleFactor);
h = (int) (h * scaleFactor);
}
else
{
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call w = targetWidth;
h = targetHeight;
} w = targetWidth;
do
{
if (higherQuality && w > targetWidth)
{
w /= 2;
if (w < targetWidth)
{
w = targetWidth;
}
}
if (higherQuality && h > targetHeight)
{
h /= 2;
if (h < targetHeight)
{
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
}
while (w > targetWidth || h > targetHeight);
return ret;
}
public double determineImageScale(int sourceWidth, int sourceHeight, int targetWidth, int targetHeight)
{
double scalex = (double) targetWidth / sourceWidth;
double scaley = (double) targetHeight / sourceHeight;
return Math.min(scalex, scaley);
}
public String createBase64ImageFromText(String text, int width, int height) throws IOException {
int leftPadding = 2;
int rightPadding = 10;
TextDetails details = getFontSize(text, width - leftPadding - rightPadding, height);
if (logger.isDebugEnabled()) {
logger.debug("Creating PNG image from text, using font size: " + String.valueOf(details.getFontSize()) + " width: " + String.valueOf(width) + " and text: " + text);
}
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
Font font = new Font("Arial", Font.PLAIN, details.getFontSize());
g2d.setFont(font);
g2d.setBackground(Color.WHITE);
g2d.clearRect(0, 0, width, height);
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
int counter = 1;
for (String line : details.getLines()) {
g2d.drawString(line, leftPadding, fm.getAscent() * counter);
counter++;
}
g2d.dispose();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ImageIO.write(img, "png", baos);
} catch (IOException e) {
logger.error("Failed to write the text to PNG image");
throw e;
}
return Base64.encodeBase64URLSafeString(baos.toByteArray());
}
public BufferedImage addTransparentBackground(BufferedImage sourceImage, int requiredWidth, int requiredHeight, boolean isCentred) {
int imageWidth = 0;
int imageHeight = 0;
BufferedImage combinedImage = null;
imageWidth = sourceImage.getWidth();
imageHeight = sourceImage.getHeight();
if (imageWidth > requiredWidth || imageHeight > requiredHeight) {
// TODO problem
}
combinedImage = new BufferedImage(requiredWidth, requiredHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = combinedImage.createGraphics();
if (isCentred) {
g2d.drawImage(sourceImage, (requiredWidth - imageWidth) / 2, (requiredHeight - imageHeight) / 2, null);
}
else {
g2d.drawImage(sourceImage, 0, 0, null);
}
return combinedImage == null ? sourceImage : combinedImage;
}
private TextDetails getFontSize(String text, int width, int height) {
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
Font font = null;
int testWidth = 0;
int testHeight = 0;
int numPossibleLines = 1;
TextDetails details = null;
// Use as large a font size as possible so start with largest
// 1. Can it fit on one line?
// 2. If not, can we fit it on multiple lines
// 3. If not, move down to next largest font
// 4. If on smallest font and still can't fit, make best effort to keep overrun to minimum
for (int size : fontSizes) {
font = new Font("Arial", Font.PLAIN, size);
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
testWidth = fm.stringWidth(text);
if (testWidth <= width) {
// Fits on one line
g2d.dispose();
return new TextDetails(size, text, false);
}
else {
testHeight = fm.getHeight();
numPossibleLines = height / testHeight;
// Try to fit with multiple lines
if (testWidth <= width * numPossibleLines) {
// Theoretically possible to fit the text, depending on how line breaks work out
details = new TextDetails(size);
details = splitToMultiLine(text, width, numPossibleLines, fm, details);
if (!details.isOverrun()) {
g2d.dispose();
return details;
}
}
}
}
// Last chance saloon, it is going to overrun anyway so make the best effort possible at it
g2d.dispose();
return details;
}
private TextDetails splitToMultiLine(String text, int width, int numPossibleLines, FontMetrics fm, TextDetails details) {
// Recursive method to split main text string into a number of lines that will fit into the
if (fm.stringWidth(text) < width) {
// Text fits as is, add line and return with no overrun
details.addLine(text);
details.setOverrun(false);
return details;
}
else if (numPossibleLines == 1) {
// Overrun on last line, add line and return but with overrun
details.addLine(text);
details.setOverrun(true);
return details;
}
else {
// More than one line left to deal with, recursively measure and split
String thisLine = "";
String testLine = "";
String remainingText = null;
int index;
int prevIndex = 0;
while (prevIndex < text.length()) {
index = text.indexOf(" ", prevIndex);
if (index != -1) {
testLine = text.substring(0, index);
if (fm.stringWidth(testLine) < width) {
thisLine = testLine;
prevIndex = index+1;
}
else {
break;
}
}
else {
break;
}
}
details.addLine(thisLine);
remainingText = text.substring(thisLine.length() + 1);
return splitToMultiLine(remainingText, width, numPossibleLines - 1, fm, details);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy