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!

È stato utile?

Soluzione

Alcuni problemi che non sono stati considerati qui:

  1. 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);
    
  2. 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).

  3. imposta i metadati come IOMetadata di IOImage . Questi metadati sono utilizzati da JPEGImageWriter. La chiamata di scrittura corretta è quindi

    imageWriter.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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top