Ridimensionamento immagini utilizzando JAI e Java2D
Sto preparando una nuova versione del codice del mio photoblog www.enricod.it, e una delle principali migliorie è l'introduzione della libreria JAI, in particolare per il ridimensionamento delle immagini.
La documentazione in rete non è ricchissima, quindi ho pensato di scrivere 2 note per ricapitolare quello che ho fatto.
Ho per ora fatto le prove utilizzando la versione "solo java", quindi semplicemente aggiungendo al classpath le librerie:
Nel caso uin cui vogliare ridimensionare un'immagine jpeg salvata in un file, e salvare il risultato ancora in un file, è sufficiente fare:
Io ho provato con i seguenti algoritmi di interpolazione:
trovando un buon compromesso con l'interpolazione Bilineare.
Nel caso in cui l'immagine sia in forma binaria (per esempio perchè salvata in un database), ho risolto con il seguente metodo:
Un metodo alternativo, più lento ma con una buona qualità, prevede l'utilizzo di Java2D anzichè di JAI. Riporto anche in questo caso il metodo:
La documentazione in rete non è ricchissima, quindi ho pensato di scrivere 2 note per ricapitolare quello che ho fatto.
Ho per ora fatto le prove utilizzando la versione "solo java", quindi semplicemente aggiungendo al classpath le librerie:
- jai_codec.jar
- jai_core.jar
Nel caso uin cui vogliare ridimensionare un'immagine jpeg salvata in un file, e salvare il risultato ancora in un file, è sufficiente fare:
Ho ottenuto risultati molto variabili, sia per quanto riguarda qualità che velocità, utilizzando i diversi algoritmi di interpolazione a disposizione.
public void resize(File source, File dest, int maxDim) {
InputStream is;
try {
is = new FileInputStream( source );
SeekableStream s = SeekableStream
.wrapInputStream(is, true);
RenderedOp objImage = JAI.create("stream", s);
((OpImage) objImage.getRendering()).setTileCache(null);
Dimension newDim = // calculate new image dimensions
float xScale = ((float) newDim.width)
/ objImage.getWidth();
float yScale = ((float) newDim.height)
/ objImage.getHeight();
RenderedOp out1 = JAI.create("scale"
, getParameterBlock(
objImage
, xScale
, yScale)
, null);
ImageIO.write(out1, "jpg", dest);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
protected ParameterBlock getParameterBlock(
RenderedOp objImage
, float xScale, float yScale) {
ParameterBlock pb = new ParameterBlock();
pb.addSource(objImage); // The source image
pb.add(xScale); // The xScale
pb.add(yScale); // The yScale
pb.add(0.0F); // The x translation
pb.add(0.0F); // The y translation
pb.add( getInterpolation() ); // The interpolation
return pb;
}
Io ho provato con i seguenti algoritmi di interpolazione:
public Interpolation getInterpolation() {
return new javax.media.jai.InterpolationBilinear();
}
public Interpolation getInterpolation() {
return new InterpolationNearest() ;
}
public Interpolation getInterpolation() {
return new InterpolationBicubic(1);
}
public Interpolation getInterpolation() {
return new InterpolationBicubic2( 0 );
}
trovando un buon compromesso con l'interpolazione Bilineare.
Nel caso in cui l'immagine sia in forma binaria (per esempio perchè salvata in un database), ho risolto con il seguente metodo:
public byte[] resize(final byte[] source, int maxDim) {
InputStream is;
byte[] dest = null;
try {
is = new ByteArraySeekableStream( source );
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageOutputStream outStream =
ImageIO.createImageOutputStream(bos);
SeekableStream s =
SeekableStream.wrapInputStream(is, true);
RenderedOp objImage = JAI.create("stream", s);
((OpImage) objImage.getRendering()).setTileCache(null);
Dimension newDim = ImageUtils
.getNewDimension(
new Dimension(
objImage.getWidth()
, objImage.getHeight())
, maxDim );
float xScale = ((float) newDim.width)
/ objImage.getWidth();
float yScale = ((float) newDim.height)
/ objImage.getHeight();
RenderedOp out1
= JAI.create("scale"
, getParameterBlock(objImage, xScale, yScale), null);
ImageIO.write(out1, "jpg", outStream);
dest = bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return dest;
}
Un metodo alternativo, più lento ma con una buona qualità, prevede l'utilizzo di Java2D anzichè di JAI. Riporto anche in questo caso il metodo:
public void resize(File source, File dest, int maxDim) {
String THUMBEXT = "jpg";
Image i;
try {
i = ImageIO.read(source);
Image resizedImage = null;
int iWidth = i.getWidth(null);
int iHeight = i.getHeight(null);
if (iWidth > iHeight)
resizedImage = i.getScaledInstance(maxDim
, (maxDim * iHeight) / iWidth
, Image.SCALE_SMOOTH);
else
resizedImage = i.getScaledInstance(
(maxDim * iWidth) / iHeight
, maxDim
, Image.SCALE_SMOOTH);
// This code ensures that all the
// pixels in the image are loaded.
Image temp = new ImageIcon(resizedImage).getImage();
// Create the buffered image.
BufferedImage bufferedImage = new BufferedImage(
temp.getWidth(null)
, temp.getHeight(null)
, BufferedImage.TYPE_INT_RGB);
// Copy image to buffered image.
Graphics g = bufferedImage.createGraphics();
// Clear background and paint the image.
g.setColor(Color.white);
g.fillRect(0, 0
, temp.getWidth(null), temp.getHeight(null));
g.drawImage(temp, 0, 0, null);
g.dispose();
// soften
float softenFactor = 0.01f;
float[] softenArray = { 0, softenFactor, 0, softenFactor
, 1 - (softenFactor * 4),
softenFactor, 0, softenFactor, 0 };
Kernel kernel = new Kernel(3, 3, softenArray);
ConvolveOp cOp = new ConvolveOp(kernel
, ConvolveOp.EDGE_NO_OP, null);
bufferedImage = cOp.filter(bufferedImage, null);
// suffix of resized should always be jpg
String resizedpath = dest.getPath();
if (!resizedpath.endsWith("." + THUMBEXT)) {
resizedpath += "." + THUMBEXT;
dest = new File(resizedpath);
}
ImageIO.write(bufferedImage, THUMBEXT, dest);
} catch (IOException e1) {
e1.printStackTrace();
}
}
Comments
Quando avrò problemi, contatterò subito il tuo sito!!