imageIO를 사용하면 일반적으로 이미지 파일을 변환하는 데 문제가 있으며 이미지 파일을 덮어 쓰면 EXIF 데이터가 모두 손실됩니다. 먼저 압축을 풀고 캐싱 한 다음 다시 설정하지 않고 보존하는 방법이 있습니까?EXIF 데이터를 삭제하지 않고 이미지 조작
답변
여기 ImageIO, Imgscalr 및 Apache commons-imaging의 조합을 사용하는 나의 해결책이 있습니다. 거기에는 유감스럽게도 이미지를 메타 데이터와 함께 읽는 단일 라이브러리가 없기 때문에 메모리 사용량이 과도하게 많습니다. 개선 된 점을 환영합니다.
ImageReader reader = ImageIO.getImageReadersBySuffix("jpg").next();
(당신은 그런 독자가 존재하는 경우도 확인 할 수 있습니다) :
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;
}
}
고마워. 그것은 잘 작동했습니다. 유일한 것은 아파치 코 몬즈 이미징을위한 현재의 Repo에서'IImageMetadata'라는 이름이'ImageMetadata'입니다. –
좀 더 효율적으로 보이는 @Rigeborod의 다른 솔루션도 확인하십시오 –
ImageIO에서이 기능 자체를 할 수 있지만, 대신 ImageIO.read 당신이하는 ImageReader를 사용해야합니다 . 당신이 당신의 메타 데이터를 저장할 수 있습니다 이제
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);
옛날 주제이기 때문에이 답변은 조금 늦은 것 같지만이 주제가 여전히 귀엽기 때문에 다른 사람들에게 도움이 될 수 있습니다.
이것은 내 솔루션보다 훨씬 메모리 효율적인 것으로 보입니다. 나는 이미지의 한 복사본이 여전히 메모리에 있다고 생각하지만 실제로 그것을 피할 수는 없다. –
- 1. EXIF 데이터를 잃지 않고 이미지 크기를 조정할 수 있습니까?
- 2. OpenCV를 사용하여 이미지 Exif 데이터를 얻는 방법?
- 3. 전체 데이터를 삭제하지 않고 ORM 스키마 바꾸기
- 4. 이전 데이터를 삭제하지 않고 plist에 데이터 추가
- 5. 데이터를 삭제하지 않고 데이터로 열 유형 수정
- 6. exif 데이터를 PHP에서 얻으려면
- 7. exif 데이터를 PHP로 작성
- 8. .NET에서 EXIF 데이터를 편집하는 방법
- 9. 이미지 파일에서 EXIF 정보 업데이트
- 10. 파이썬에서 외부 스크립트를 사용하지 않고 이미지에서 EXIF 데이터를 읽으려면 어떻게해야합니까?
- 11. Exif 및 메타 데이터를 잃지 않고 사진을 회전하는 방법은 무엇입니까?
- 12. EXIF 데이터를 저장할 테이블 설계
- 13. Silverlight로 EXIF 데이터를 읽고 쓰십시오.
- 14. exif 데이터를 임베드하기위한 기능은 무엇입니까?
- 15. exif 데이터를 이미지에 어떻게 추가합니까?
- 16. 이미지 조작
- 17. 메타 데이터를 잃지 않고 TIF/JPG 이미지 회전 : EXIF 및 색상 프로파일
- 18. 데이터를 삭제하지 않는 오이 테스트
- 19. `test` 데이터베이스 데이터를 삭제하지 않고 JavaScripts를 테스트하는 방법은 무엇입니까?
- 20. MS Access에서 기존 레코드를 삭제하지 않고 데이터를 삽입하려면 어떻게해야합니까?
- 21. 여러 번로드 된 데이터를 삭제하지 않고 중복 제거
- 22. 지도 주석을 삭제하지 않고 숨기기
- 23. 셀을 삭제하지 않고 UITableView commitEditingStyle
- 24. 삭제하지 않고 SQL Server 복제?
- 25. RSpec을 삭제하지 않고 레코드를 삭제합니다.
- 26. EXIF 데이터를 추가하지 않으려는 카메라 설정
- 27. PerlMagick을 사용하여 EXIF 데이터를 추출하려면 어떻게해야합니까?
- 28. 코드 닛터 스트립 이미지 EXIF 데이터
- 29. ImageIO에서 - 얻을 이미지 유형 및 EXIF 데이터
- 30. EXIF 데이터를 저장/검색하기위한 데이터베이스 솔루션
다른 위치에 저장 한 다음 이전 exif 메타로 새 이미지를 덮어 씁니까? http://www.screaming-penguin.com/node/7485 –
이것은 정확히 내가 피하고 싶습니다 – preslavrachev
메타를 복사 할 때의 문제점은 무엇입니까? http://nucleussystems.com/blog/java-copy-exif-data –