Al usar imageIO, suelo tener el problema de transformar un archivo de imagen y, después de sobreescribirlo, pierde todos sus datos EXIF. ¿Hay alguna forma de preservarlo sin primero extraerlo, almacenarlo en caché y luego reiniciarlo?Manipular una imagen sin eliminar sus datos EXIF
Respuesta
Aquí está mi solución usando una combinación de ImageIO, Imgscalr y Apache commons-imaging. Es una lástima que no haya una única biblioteca que combine la lectura de la imagen con sus metadatos, lo que probablemente sea bastante excesivo para el uso de la memoria; Mejoras bienvenidas.
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;
}
}
Muchas gracias. Funcionó bien. Lo único es que aparentemente 'IImageMetadata' se llama 'ImageMetadata' en el repositorio actual de Apache Commons Imaging –
También verifique la otra solución de @Rigeborod que se ve un poco más eficiente –
ImageIO tienen esta funcionalidad en sí, pero en lugar de ImageIO.read tendrá que utilizar ImageReader:
ImageReader reader = ImageIO.getImageReadersBySuffix("jpg").next();
(es posible que desee comprobar también si existe tal lector) . Luego hay que ajustar la entrada:
reader.setInput(ImageIO.createImageInputStream(your_imput_stream));
Ahora puede guardar los metadatos:
IIOMetadata metadata = reader.getImageMetadata(0);
// As far as I understand you should provide
// index as tiff images could have multiple pages
Y luego leer la imagen:
BufferedImage bi = reader.read(0);
Cuando desea guardar una imagen nueva , debe utilizar 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);
Como es un tema antiguo, creo que esta respuesta es un poco tarde, pero puede ayudar a otros ya que este tema todavía es googleable.
Esto se ve sustancialmente más eficiente en la memoria que mi solución, Supongo que una copia de la imagen todavía está en la memoria, pero realmente no puede evitar eso. –
- 1. ¿Cómo agrego datos exif a una imagen?
- 2. Copia de una imagen, pierde los datos Exif
- 3. Copie una imagen y conserve sus datos EXIF / IPTC con PHP imageCreateFromJpeg?
- 4. Eliminar datos EXIF de JPG usando PHP
- 5. En Python, ¿cómo leo los datos exif de una imagen?
- 6. Cambiar el tamaño de una imagen con .NET sin perder datos EXIF
- 7. ¿Cómo eliminar los datos EXIF (cámara) de la imagen con carrierwave?
- 8. ImageIO - obtener el tipo de imagen y datos EXIF
- 9. C# Recuperar Canon específico Datos EXIF
- 10. ¿Cómo manipular una imagen a nivel de píxel en C?
- 11. escribiendo datos exif en php
- 12. datos Exif Android en archivo JPEG
- 13. Cómo editar datos EXIF en .NET
- 14. Extracto PHP Datos GPS EXIF
- 15. Cómo recuperar información EXIF de una imagen en Rails
- 16. ¿Cómo puedo leer los datos EXIF de una imagen tomada con un iPhone de Apple?
- 17. Ocultar sin eliminar la imagen de fondo
- 18. .NET C# library para la reescritura Exif sin pérdida?
- 19. Manipular elementos vinculando datos nuevos
- 20. PHP/(malo) exif datos/advertencias, ¿qué hacer?
- 21. ¿Cómo puedo extraer datos EXIF usando PerlMagick?
- 22. escalar una imagen, pero mantener sus proporciones
- 23. Etiquetas personalizadas Exif
- 24. D3.js - cargar y manipular datos externos
- 25. Exif data TAG_ORIENTATION always 0
- 26. Extraer EXIF de JPEG
- 27. ¿Hay alguna gema para leer datos exif de imágenes png?
- 28. manera simple de eliminar datos EXIF de un JPEG con .NET
- 29. Datos de exif de imagen en el motor de la aplicación de google
- 30. Lectura de datos EXIF de una matriz de bytes en android
¿Almacenar en otro lugar y luego sobrescribir una nueva imagen con un viejo exif meta? http://www.screaming-penguin.com/node/7485 –
Esto es precisamente lo que quiero evitar – preslavrachev
¿cuál es el problema con copiar el meta? aquí hay otro ejemplo http://nucleussystems.com/blog/java-copy-exif-data –