Scrivi metadati dpi su un'immagine jpeg in Java
-
04-07-2019 - |
Domanda
Sto cercando di impostare programmaticamente i metadati dpi di un'immagine jpeg in Java. La fonte dell'immagine è uno scanner, quindi ottengo la risoluzione orizzontale / verticale da TWAIN, insieme ai dati grezzi dell'immagine. Vorrei salvare queste informazioni per risultati di stampa migliori.
Ecco il codice che ho finora. Salva l'immagine non elaborata (byteArray) in un file JPEG, ma ignora le informazioni sulla densità X / Y specificate tramite IIOMetadata. Qualche consiglio su cosa sto facendo di sbagliato?
Anche qualsiasi altra soluzione (libreria di terze parti, ecc.) sarebbe benvenuta.
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream
import org.w3c.dom.Element;
import com.sun.imageio.plugins.jpeg.JPEGImageWriter;
public boolean saveJpeg(int[] byteArray, int width, int height, int dpi, String file)
{
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
WritableRaster wr = bufferedImage.getRaster();
wr.setPixels(0, 0, width, height, byteArray);
try
{
// Image writer
JPEGImageWriter imageWriter = (JPEGImageWriter) ImageIO.getImageWritersBySuffix("jpeg").next();
ImageOutputStream ios = ImageIO.createImageOutputStream(new File(file));
imageWriter.setOutput(ios);
// Compression
JPEGImageWriteParam jpegParams = (JPEGImageWriteParam) imageWriter.getDefaultWriteParam();
jpegParams.setCompressionMode(JPEGImageWriteParam.MODE_EXPLICIT);
jpegParams.setCompressionQuality(0.85f);
// Metadata (dpi)
IIOMetadata data = imageWriter.getDefaultImageMetadata(new ImageTypeSpecifier(bufferedImage), jpegParams);
Element tree = (Element)data.getAsTree("javax_imageio_jpeg_image_1.0");
Element jfif = (Element)tree.getElementsByTagName("app0JFIF").item(0);
jfif.setAttribute("Xdensity", Integer.toString(dpi));
jfif.setAttribute("Ydensity", Integer.toString(dpi));
jfif.setAttribute("resUnits", "1"); // density is dots per inch
// Write and clean up
imageWriter.write(data, new IIOImage(bufferedImage, null, null), jpegParams);
ios.close();
imageWriter.dispose();
}
catch (Exception e)
{
return false;
}
return true;
}
Grazie!
Soluzione
Alcuni problemi che non sono stati considerati qui:
-
La struttura ad albero non è mappata direttamente su IOMetaData. Per applicare i dati dall'albero, aggiungere la seguente chiamata dopo aver impostato i parametri di densità e raster:
data.setFromTree("javax_imageio_jpeg_image_1.0", tree);
-
non utilizza i metadati come primo parametro nella chiamata di scrittura. Vedi
JPEGImageWriter # write (IIOMetaData, IIOImage, ImageWriteParam)
. Se streamMetaData non è NULL, verrà generato un avviso (WARNING_STREAM_METADATA_IGNORED). -
imposta i metadati come
IOMetadata
diIOImage
. Questi metadati sono utilizzati da JPEGImageWriter. La chiamata di scrittura corretta è quindiimageWriter.write(null, new IIOImage(F_scaledImg, null, data), jpegParams);
Altri suggerimenti
Sembrerebbe che questo potrebbe essere un bug.
Ho trovato questo post da alcune ricerche su Google
Apparentemente ce ne sono molti altri che indicano anche un bug.
Il post sopra parla dell'utilizzo di JMagick come soluzione alternativa da parte di terzi.