2012-01-23 9 views
10

imageIO का उपयोग करके, मुझे आमतौर पर एक छवि फ़ाइल को बदलने की समस्या होती है, और इसे ओवरराइट करने के बाद, यह अपने सभी EXIF ​​डेटा को खो देता है। क्या इसे पहले निकालने के बिना इसे संरक्षित करने, इसे कैशिंग करने और फिर इसे रीसेट करने का कोई तरीका है?अपने EXIF ​​डेटा को हटाए बिना किसी छवि को मैनिपुलेट करें

+2

इसे कहीं और स्टोर करें, फिर पुरानी एक्सिफ़ मेटा के साथ नई छवि को ओवरराइट करें? http://www.screaming-penguin.com/node/7485 –

+0

यह वही है जो मैं – preslavrachev

+2

से बचाना चाहता हूं मेटा की प्रतिलिपि बनाने में समस्या क्या है? यहां एक और उदाहरण है http://nucleussystems.com/blog/java-copy-exif-data –

उत्तर

9

इमेजियो, इमग्स्लर और अपाचे कॉमन्स-इमेजिंग के संयोजन का उपयोग करके मेरा समाधान यहां है। यह एक दयालुता है जिसमें कोई भी पुस्तकालय नहीं है जो छवि को इसके मेटाडेटा के साथ पढ़ने को जोड़ती है, जिससे यह स्मृति उपयोग पर संभवतः अत्यधिक हो जाती है; सुधार स्वागत है।

import java.awt.image.BufferedImage; 
import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import javax.imageio.ImageIO; 
import org.apache.commons.imaging.ImageReadException; 
import org.apache.commons.imaging.ImageWriteException; 
import org.apache.commons.imaging.Imaging; 
import org.apache.commons.imaging.common.IImageMetadata; 
import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata; 
import org.apache.commons.imaging.formats.jpeg.exif.ExifRewriter; 
import org.apache.commons.imaging.formats.tiff.TiffImageMetadata; 
import org.apache.commons.io.IOUtils; 
import org.imgscalr.Scalr; 


public class ImageData { 

    private byte[] imageData; 


    public ImageData(InputStream instream) throws IOException { 
     imageData = IOUtils.toByteArray(instream); 
     instream.close(); 
    } 


    public synchronized void resize(int maxDimension) throws IOException, ImageReadException, ImageWriteException { 
     // Resize the image if necessary 
     BufferedImage image = readImage(imageData); 
     if (image.getWidth() > maxDimension || image.getHeight() > maxDimension) { 

      // Save existing metadata, if any 
      TiffImageMetadata metadata = readExifMetadata(imageData); 
      imageData = null; // allow immediate GC 

      // resize 
      image = Scalr.resize(image, maxDimension); 

      // rewrite resized image as byte[] 
      byte[] resizedData = writeJPEG(image); 
      image = null; // allow immediate GC 

      // Re-code resizedData + metadata to imageData 
      if (metadata != null) { 
       this.imageData = writeExifMetadata(metadata, resizedData); 
      } else { 
       this.imageData = resizedData; 
      } 
     } 
    } 

    private TiffImageMetadata readExifMetadata(byte[] jpegData) throws ImageReadException, IOException { 
     IImageMetadata imageMetadata = Imaging.getMetadata(jpegData); 
     if (imageMetadata == null) { 
      return null; 
     } 
     JpegImageMetadata jpegMetadata = (JpegImageMetadata)imageMetadata; 
     TiffImageMetadata exif = jpegMetadata.getExif(); 
     if (exif == null) { 
      return null; 
     } 
     return exif; 
    } 


    private byte[] writeExifMetadata(TiffImageMetadata metadata, byte[] jpegData) 
           throws ImageReadException, ImageWriteException, IOException { 
     ByteArrayOutputStream out = new ByteArrayOutputStream(); 
     new ExifRewriter().updateExifMetadataLossless(jpegData, out, metadata.getOutputSet()); 
     out.close(); 
     return out.toByteArray(); 
    } 


    private BufferedImage readImage(byte[] data) throws IOException { 
     return ImageIO.read(new ByteArrayInputStream(data)); 
    } 

    private byte[] writeJPEG(BufferedImage image) throws IOException { 
     ByteArrayOutputStream jpegOut = new ByteArrayOutputStream(); 
     ImageIO.write(image, "JPEG", jpegOut); 
     jpegOut.close(); 
     return jpegOut.toByteArray(); 
    } 

    public synchronized void writeJPEG(OutputStream outstream) throws IOException { 
     IOUtils.write(imageData, outstream); 

    } 

    public synchronized byte[] getJPEGData() { 
     return imageData; 
    } 

} 
+0

बहुत बहुत धन्यवाद। यह अच्छी तरह से काम किया। एकमात्र चीज यह है कि स्पष्ट रूप से 'IImageMetadata' को अपाचे कॉमन्स इमेजिंग –

+0

के लिए वर्तमान रेपो में 'छविमैटाडाटा' नाम दिया गया है @Rigeborod से अन्य समाधान भी देखें जो थोड़ा अधिक कुशल दिखता है –

8

ImageIO इस कार्यक्षमता को स्वयं करते हैं, लेकिन ImageIO.read के बजाय आप ImageReader उपयोग करने के लिए की आवश्यकता होगी:

ImageReader reader = ImageIO.getImageReadersBySuffix("jpg").next(); 

(आप अगर इस तरह के पाठक मौजूद भी चेक कर सकते हैं) ।

reader.setInput(ImageIO.createImageInputStream(your_imput_stream)); 

अब आप अपने मेटाडाटा को बचाने कर सकते हैं::

IIOMetadata metadata = reader.getImageMetadata(0); 
          // As far as I understand you should provide 
          // index as tiff images could have multiple pages 

और फिर छवि पढ़ें:

BufferedImage bi = reader.read(0); 

जब आप नई छवि को सहेजना चाहते तो फिर तुम इनपुट निर्धारित करने की आवश्यकता , आपको ImageWriter का उपयोग करना चाहिए:

// I'm writing to byte array in memory, but you may use any other stream 
ByteArrayOutputStream os = new ByteArrayOutputStream(255); 
ImageOutputStream ios = ImageIO.createImageOutputStream(os); 

Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("jpeg"); 
ImageWriter writer = iter.next(); 
writer.setOutput(ios); 

//You may want also to alter jpeg quality 
ImageWriteParam iwParam = writer.getDefaultWriteParam(); 
iwParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); 
iwParam.setCompressionQuality(.95f); 

//Note: we're using metadata we've already saved. 
writer.write(null, new IIOImage(bi, null, metadata), iwParam); 
writer.dispose(); 

ImageIO.write(bi, "jpg", ios); 

जैसा कि यह पुराना विषय है, मुझे लगता है कि यह उत्तर थोड़ा देर हो चुकी है, लेकिन दूसरों की मदद कर सकती है क्योंकि यह विषय अभी भी गुम हो गया है।

+0

यह मेरे समाधान की तुलना में काफी अधिक स्मृति-कुशल दिखता है, मुझे लगता है कि छवि की एक प्रति अभी भी स्मृति में है लेकिन वास्तव में इससे बच नहीं सकती है। –