Sử dụng imageIO, tôi thường gặp sự cố khi chuyển đổi tệp hình ảnh và sau khi ghi đè hình ảnh, nó sẽ mất tất cả dữ liệu EXIF của nó. Có cách nào để bảo tồn nó mà không cần giải nén nó trước, lưu vào bộ nhớ đệm và sau đó đặt lại nó?Thao tác hình ảnh mà không xóa dữ liệu EXIF
Trả lời
Đây là giải pháp của tôi bằng cách sử dụng kết hợp ImageIO, Imgscalr và Apache commons-hình ảnh. Thật đáng tiếc là không có thư viện nào kết hợp việc đọc hình ảnh với siêu dữ liệu của nó, làm cho điều này có thể khá là quá mức khi sử dụng bộ nhớ; Cải tiến chào đón.
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;
}
}
Cảm ơn rất nhiều. Nó hoạt động rất tốt. Điều duy nhất là rõ ràng 'IImageMetadata' được đặt tên là 'ImageMetadata' trong repo hiện tại cho Apache Commons Imaging –
Bạn cũng có thể kiểm tra giải pháp khác từ @Rigeborod trông có vẻ hiệu quả hơn một chút –
ImageIO làm có chức năng này chính nó, nhưng thay vì ImageIO.read bạn sẽ cần phải sử dụng ImageReader:
ImageReader reader = ImageIO.getImageReadersBySuffix("jpg").next();
(bạn có thể muốn cũng để kiểm tra xem người đọc như vậy tồn tại) . Sau đó, bạn cần phải thiết lập đầu vào:
reader.setInput(ImageIO.createImageInputStream(your_imput_stream));
Bây giờ bạn có thể tiết kiệm siêu dữ liệu của bạn:
IIOMetadata metadata = reader.getImageMetadata(0);
// As far as I understand you should provide
// index as tiff images could have multiple pages
Và sau đó đọc hình ảnh:
BufferedImage bi = reader.read(0);
Khi bạn muốn lưu hình ảnh mới , bạn nên sử dụng 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);
Vì đó là chủ đề cũ, tôi đoán câu trả lời này hơi muộn một chút, nhưng có thể giúp người khác vì chủ đề này vẫn còn googlable.
Điều này có vẻ hiệu quả hơn bộ nhớ so với giải pháp của tôi, Tôi đoán một bản sao của hình ảnh vẫn còn trong bộ nhớ nhưng thực sự không thể tránh được điều đó. –
- 1. Thao tác hình ảnh trong NodeJS với dữ liệu hình ảnh base64
- 2. Thay đổi kích cỡ hình ảnh bằng .NET mà không làm mất dữ liệu EXIF
- 3. Thao tác hình ảnh C++
- 4. Ghi siêu dữ liệu EXIF vào hình ảnh trong Android
- 5. Sao chép một hình ảnh, mất dữ liệu Exif
- 6. ImageIO - nhận loại hình ảnh và Exif dữ liệu
- 7. Chỉnh sửa/Xóa dữ liệu hình ảnh Exif trên Windows Phone
- 8. dòng Thao tác dữ liệu
- 9. Thao tác hình ảnh bằng Javascript?
- 10. C# Thao tác với dữ liệu JSON
- 11. Thao tác hình ảnh watermark với Go
- 12. Làm cách nào để xóa dữ liệu EXIF (camera) khỏi ảnh bằng sóng mang?
- 13. Thao tác dữ liệu mạng trong R
- 14. Thao tác hình ảnh trong asp.net/c# mà không có System.Drawing/GDI +
- 15. Thao tác thao tác không kích hoạt
- 16. Thao tác nhấn tab lựa chọn hình ảnh trong VIM
- 17. Làm thế nào để viết hoặc sửa đổi dữ liệu EXIF cho một hình ảnh hiện có trên hệ thống tập tin, mà không cần tải hình ảnh?
- 18. Thao tác dữ liệu utf8mb4 từ MySQL với PHP
- 19. Thao tác dòng lệnh của hình ảnh PhotoShop
- 20. Vấn đề hiệu suất thao tác hình ảnh F #
- 21. TListbox - Thao tác bố cục hình ảnh và văn bản?
- 22. Dữ liệu hình ảnh exif trong công cụ ứng dụng google
- 23. Phương pháp xóa Ruby (thao tác chuỗi)
- 24. Làm cách nào để thêm dữ liệu exif vào hình ảnh?
- 25. Siêu dữ liệu truy cập (thẻ exif) của hình ảnh được chụp bởi UIImagePickerController - iOS/iPhone
- 26. Sao chép hình ảnh và lưu giữ dữ liệu EXIF / IPTC của nó bằng PHP imageCreateFromJpeg?
- 27. Trong Python, làm cách nào để đọc dữ liệu exif cho một hình ảnh?
- 28. Có đá quý nào để đọc dữ liệu exif từ hình ảnh png
- 29. Thao tác "dữ liệu" từ thành công $ .ajax: chức năng (dữ liệu) {
- 30. Xóa dữ liệu EXIF khỏi JPG bằng cách sử dụng PHP
Lưu trữ ở nơi khác sau đó ghi đè hình ảnh mới bằng meta exif cũ? http://www.screaming-penguin.com/node/7485 –
Đây chính xác là những gì tôi muốn tránh – preslavrachev
vấn đề với việc sao chép meta là gì? đây là một ví dụ khác http://nucleussystems.com/blog/java-copy-exif-data –