Używając imageIO, zazwyczaj mam problem z przekształceniem pliku obrazu, a po jego zastąpieniu, traci on wszystkie swoje dane EXIF. Czy istnieje sposób na zachowanie go bez wcześniejszego wyodrębniania, buforowania go, a następnie resetowania?Manipulowanie obrazem bez usuwania jego danych EXIF
Odpowiedz
Oto moje rozwiązanie wykorzystujące połączenie Imageio, Imgscalr i Apache-obrazowania. Szkoda, że nie ma jednej biblioteki, która łączy czytanie obrazu z jego metadanymi, sprawiając, że prawdopodobnie jest to nadmierne użycie pamięci; Usprawnienia mile widziane.
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;
}
}
Wielkie dzięki. To działało ładnie. Jedyną rzeczą jest to, że najwyraźniej 'IImageMetadata' ma nazwę 'ImageMetadata' w bieżącym repozytorium dla Apache Commons Imaging –
Sprawdź także inne rozwiązanie z @Rigeborod, które wygląda na nieco bardziej wydajne –
ImageIO mają tę samą funkcjonalność, ale zamiast ImageIO.read trzeba będzie użyć ImageReader:
ImageReader reader = ImageIO.getImageReadersBySuffix("jpg").next();
(możesz też sprawdzić, czy istnieje taki czytnik) . Następnie trzeba ustawić wejście:
reader.setInput(ImageIO.createImageInputStream(your_imput_stream));
Teraz możesz zapisać metadane:
IIOMetadata metadata = reader.getImageMetadata(0);
// As far as I understand you should provide
// index as tiff images could have multiple pages
a następnie odczytać obraz:
BufferedImage bi = reader.read(0);
Kiedy chcesz zapisać nowy obraz , powinieneś używać 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);
Jak to jest stary temat, myślę, że ta odpowiedź jest nieco za późno, ale może pomóc innym, ponieważ ten temat jest nadal w stanie googlable.
To wygląda na znacznie wydajniejszą pamięć niż moje rozwiązanie, Domyślam się, że jedna kopia obrazu jest nadal w pamięci, ale tak naprawdę nie może tego uniknąć. –
- 1. Metoda usuwania Ruby (manipulowanie ciągami znaków)
- 2. Manipulowanie linie danych
- 3. Ponownie załaduj dane widoku tabeli bez usuwania jego stanu wyboru.
- 4. Jquery dołączanie bez usuwania
- 5. Manipulowanie okienkiem SVG z JavaScript (bez bibliotek)
- 6. Jak usunąć wskaźnik bez usuwania danych wskazywanych przez wskaźnik?
- 7. Ograniczanie osi ggplot2 bez usuwania danych (limity zewnętrzne): powiększ
- 8. ImageIO - uzyskać typ obrazu i danych EXIF
- 9. C# Odzyskiwanie danych EXIF firmy Canon
- 10. Manipulowanie typem danych 80-bitowych w C
- 11. Ukryj tytuł paska nawigacji bez usuwania go
- 12. Podziel ciąg bez usuwania separatora
- 13. Kompilowanie C++ bez operatora usuwania
- 14. css z obrazem tła bez powtarzania obrazu
- 15. UIBarButtonItem z niestandardowym obrazem i bez obramowania
- 16. Rozpiętość z obrazem tła i bez zawartości
- 17. Jak podzielić i napisać DataFrame w Spark bez usuwania partycji bez nowych danych?
- 18. Jak zaktualizować bazę danych bez usuwania danych wprowadzonych przez użytkownika w poprzedniej bazie danych?
- 19. Najszybsza technika usuwania powielonych danych
- 20. Manipulowanie polem formularza PDF
- 21. Używanie klejnotu bez jego instalowania
- 22. Manipulowanie wyrażeniami w R
- 23. Python 2.7 uzyskiwanie danych wejściowych od użytkownika i manipulowanie ciągiem bez cytowania
- 24. Jak usunąć plik exif z JPG bez utraty jakości obrazu?
- 25. Ukrywanie adnotacji map bez ich usuwania
- 26. Spark streaming mapWithState timeout bez usuwania
- 27. rpmbuild% czysta faza bez usuwania plików
- 28. Dzielenie łańcucha przez spację bez usuwania miejsca?
- 29. Zastępowanie funkcji bez usuwania właściwości statycznych
- 30. można wyłączyć listę zdarzeń bez jej usuwania?
Przechowuj go w innym miejscu, a następnie zastąp nowe zdjęcie starą metą exif? http://www.screaming-penguin.com/node/7485 –
Dokładnie tego chcę uniknąć – preslavrachev
jaki jest problem z kopiowaniem mety? oto inny przykład http://nucleussystems.com/blog/java-copy-exif-data –