package org.agnitas.emm.core.imagehelper;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Locale;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;
import org.agnitas.emm.core.commons.util.ConfigService;
import org.apache.log4j.Logger;
public class ImageHelperService {
private static final transient Logger logger = Logger.getLogger(ImageHelperService.class);
public static int MAXSCALE=100; // max scale value.
private ConfigService configService = null;
// ----------------------------------------------------------------------------------------------------------------
// Dependency Injection
public void setConfigService(ConfigService configService) {
this.configService = configService;
}
// ----------------------------------------------------------------------------------------------------------------
// Business Logic
/**
* This method creates a thumbnail from the given byte-array.
* The values for x and y are fetched from DB. Also the quality of
* the thumbnail is fetched from DB and the type of the target image.
* @return
*/
byte[] createThumbnail(byte[] sourceImage) {
ByteArrayOutputStream out = null;
float quality = 0.4f;
// BufferedImage buff = null;
try {
BufferedImage buff = ImageIO.read(new ByteArrayInputStream(sourceImage));
ImageWriter writer = ImageIO.getImageWritersByFormatName( "jpg" ).next();
ImageOutputStream ios;
ios = ImageIO.createImageOutputStream( out );
writer.setOutput( ios );
ImageWriteParam iwparam = new JPEGImageWriteParam( Locale.getDefault() );
iwparam.setCompressionMode( ImageWriteParam.MODE_EXPLICIT ) ;
iwparam.setCompressionQuality( quality );
writer.write( null, new IIOImage(buff, null, null), iwparam );
ios.flush();
writer.dispose();
ios.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
* This method takes a buffered image and scales it with the given scaleX and scaleY values.
* If only one scale value is given, it will be used for both dimensions.
* Take care that the given scale values are valid.
* @param originalImage
* @param scaleX
* @param scaleY
* @return
* @throws Exception
*/
public BufferedImage scaleImage(BufferedImage originalImage, float scaleX, float scaleY) throws Exception {
logger.info("ImageHelperService: called scaleImage");
// basic checking if scaleX or scaleY are valid.
if (scaleX == 0 && scaleY == 0) {
throw new Exception("Invalid scale values given: X: " + scaleX + " Y: " + scaleY);
}
if (scaleX >= MAXSCALE || scaleY >= MAXSCALE ) {
throw new Exception("Scale value too high. Maxscale is: " + MAXSCALE + " ,X: " + scaleX + " Y: " + scaleY);
}
if (scaleX == 0) {
scaleX = scaleY;
}
if (scaleY == 0) {
scaleY = scaleX;
}
// calculate new size
int width = (int)(originalImage.getWidth() * scaleX);
int height =(int)(originalImage.getHeight() * scaleY);
// generate new image
BufferedImage tmpImg = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
// get context
Graphics2D g2 = (Graphics2D) tmpImg.getGraphics();
// scale
g2.scale(scaleX, scaleY);
// paint
g2.drawImage(originalImage, 0, 0, null);
// the scaled image is now drawn on the context of tmpImg.
g2.dispose();
return tmpImg;
}
/**
* This method returns a BufferedImage with the scaled image.
* @param originalImage
* @param scaleX
* @param scaleY
* @return
*/
public BufferedImage createThumbnail(BufferedImage originalImage, float scaleX, float scaleY) {
BufferedImage returnImage = null;
try {
returnImage = scaleImage(originalImage, scaleX, scaleY);
} catch (Exception e) {
logger.error("An error occured during creation of thumbnails." + e);
}
return returnImage;
}
/**
* This method gets the scale values from the DB and returns a scaled image with this values.
* @param originalImage
* @return
*/
public BufferedImage createThumbnail(BufferedImage originalImage) {
float[] scales = getScaleFactor(originalImage);// scales[0] = X, scales[1] = Y.
BufferedImage returnImage = createThumbnail(originalImage, scales[0], scales[1]);
return returnImage;
}
public byte[] createPNGThumbnailFromByteArray(byte[] img) {
ByteArrayInputStream byteIn = new ByteArrayInputStream(img);
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
try {
BufferedImage buffImg = ImageIO.read(byteIn);
BufferedImage thumbImg = createThumbnail(buffImg);
ImageOutputStream ios;
ios = ImageIO.createImageOutputStream( byteOut );
ImageWriter writer = ImageIO.getImageWritersByFormatName( "png" ).next();
writer.setOutput(ios);
writer.write( null, new IIOImage(thumbImg, null, null), writer.getDefaultWriteParam() );
ios.flush();
writer.dispose();
ios.close();
} catch (IOException e) {
logger.error("Error reading image from byte array");
e.printStackTrace();
}
return byteOut.toByteArray();
}
/**
* This method returns the x,y scale factor calculated from the size given with the
* bufferedImage and the values in the DB.
* Example:
* DB-Values for sizeX = 500, sizeY=500;
* BufferedImage has sizeX = 1000,sizeY = 1000
* Scale factor is {0.5, 0.5} (500 / 1000)
* Hint: If scale for one value is not set, the appropriate scale size is calculated to
* maintain aspect ratio.
* @param buffImg
* @return
*/
private float[] getScaleFactor(BufferedImage buffImg) {
float[] returnValues = new float[2];
int sizex = configService.getIntegerValue(ConfigService.Value.Thumbnail_Sizex);
int sizey = configService.getIntegerValue(ConfigService.Value.Thumbnail_Sizey);
if (buffImg.getWidth() == 0 && buffImg.getHeight() == 0) {
// setting default values and writing warning
returnValues[0] = 119;
returnValues[1] = 84;
logger.error("ImageHelperService: getScaleFactor: getting XYSize for thumbnails from DB failed!" +
" Please check, if values are given in config_tbl. Defaults are set the hard way.");
} else {
returnValues[0] = (float)sizex / (float)buffImg.getWidth();
returnValues[1] = (float)sizey / (float)buffImg.getHeight();
if (returnValues[0] == 0) {
returnValues[0] = returnValues[1];
}
if (returnValues[1] == 0) {
returnValues[1] = returnValues[0];
}
}
return returnValues;
}
/**
* This method returns a thumbnailed version of the given PNG image if the scale factor
* would be more than the DB parameter.
* The return value is the same image if we dont need scaling!
* @param img
* @return
*/
public byte[] createThumbIfNeeded(byte[] img) {
logger.info("ImageHelperService: called createThumbIfNeeded");
byte[] returnImage = img;
float scaleLimit = configService.getFloatValue(ConfigService.Value.Thumbnail_Treshold);
ByteArrayInputStream byteIn = new ByteArrayInputStream(img);
BufferedImage buffImg = null;
try {
buffImg = ImageIO.read(byteIn);
} catch (IOException e) {
logger.error("Error creating image from given buffer");
}
float scales[] = getScaleFactor(buffImg);
if (scales[0] > scaleLimit || scales[1] > scaleLimit) {
logger.info("ImageHelperService::createThumbIfNeeded: createPNGThumbnailFromByteArray called");
returnImage = createPNGThumbnailFromByteArray(img);
} else {
logger.info("ImageHelperService::createThumbIfNeeded: Scale factor prevents calculating thumbnail");
}
return returnImage;
}
public byte[] createDummyIfNeeded( byte[] img) {
if( img == null) {
try {
BufferedImage image = new BufferedImage( 1, 1, BufferedImage.TYPE_3BYTE_BGR);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write( image, "png", baos);
img = baos.toByteArray();
} catch( IOException e) {
Logger.getLogger( getClass()).error( "Unable to create dummy image", e);
}
}
return img;
}
}