2016-04-17 22 views
0

Ich verwende den folgenden Test, um eine Datei zu lesen, Base 64 codieren, dann dekodieren Sie die Basis 64 zurück zu einem neuen Bild. Mir ist aufgefallen, dass die neue Bilddateigröße (nach der Konvertierung) deutlich kleiner ist als das Originalbild, was mich zu der Annahme veranlasst, dass ein Teil der Bilddaten bei der Konvertierung verloren geht. Ich kann das Bild sehen, bin aber besorgt über die Bildqualität. Jeder Einblick in das, was ich falsch mache, würde sehr geschätzt werden.Bilddateigröße unterscheidet sich nach Base 64 Codierung/Decodierung

Prüfklasse:

package test; 

import javax.imageio.ImageIO; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 
import java.nio.file.Files; 
import java.nio.file.Paths; 
import java.util.Base64; 

public class ImageTest { //should be B64Test 

    public static void main(String[] args) { 
     ImageTest imageTest = new ImageTest(); 
     try { 
      BufferedImage img = null; 
      BufferedImage finalImg = null; 
      try { 
       // img = ImageIO.read(new File("/home/user/Desktop/test1.jpg")); 
       img = ImageIO.read(Files.newInputStream(Paths.get("/home/user/Desktop/test1.jpg"))); 
       //encode base64 and print 
       final String base64encoded = ImageConverter.encodeToString(img, "jpeg"); 
       System.out.println("read file " + base64encoded); 

       //convert base64 string to image 
       finalImg = ImageConverter.decodeToImage(b64encoded); 
       ImageIO.write(finalImg, "jpeg", new File("/home/user/Desktop/test2.jpg")); 
      } catch (IOException e) { 
       System.out.println("exception " + e); 
      } 

     } catch (Exception e) { 
      System.out.println("exception " + e); 
     } 

    } 

} 

Image Converter

package test; 

import javax.imageio.ImageIO; 
import java.awt.image.BufferedImage; 
import java.awt.image.RenderedImage; 
import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.io.UncheckedIOException; 
import java.nio.charset.StandardCharsets; 
import java.util.Base64; 

import sun.misc.BASE64Encoder; 
import sun.misc.BASE64Decoder; 

public class ImageConverter { 

    public static String imgToBase64String(final RenderedImage img, final String formatName) { 
     final ByteArrayOutputStream os = new ByteArrayOutputStream(); 
     try { 
      ImageIO.write(img, formatName, Base64.getEncoder().wrap(os)); 
      return os.toString(StandardCharsets.ISO_8859_1.name()); 
     } catch (final IOException ioe) { 
      throw new UncheckedIOException(ioe); 
     } 
    } 

    public static BufferedImage base64StringToImg(final String base64String) { 
     try { 
      return ImageIO.read(new ByteArrayInputStream(Base64.getDecoder().decode(base64String))); 
     } catch (final IOException ioe) { 
      throw new UncheckedIOException(ioe); 
     } 
    } 


    public static String encodeToString(BufferedImage image, String type) { 
     String imageString = null; 
     ByteArrayOutputStream bos = new ByteArrayOutputStream(); 

     try { 
      ImageIO.write(image, type, bos); 
      byte[] imageBytes = bos.toByteArray(); 

      BASE64Encoder encoder = new BASE64Encoder(); 
      imageString = encoder.encode(imageBytes); 

      bos.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     return imageString; 
    } 


    public static BufferedImage decodeToImage(String imageString) { 

     BufferedImage image = null; 
     byte[] imageByte; 
     try { 
      BASE64Decoder decoder = new BASE64Decoder(); 
      imageByte = decoder.decodeBuffer(imageString); 
      ByteArrayInputStream bis = new ByteArrayInputStream(imageByte); 
      image = ImageIO.read(bis); 
      bis.close(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     return image; 
    } 
} 

Ich kann versuchen, sowohl die Basis 64 Encoder/Decoder Testen in jdk8 sowie die in sun.java. misc (was ich merke, brauche ich nicht). Irgendwelche Gedanken dazu, was die Bildgröße zum Schrumpfen bringen könnte (ich würde das lieber selbst machen, wenn nötig mit imagemagick oder graphicsmagick etc.).

Das ursprüngliche Bild war 1,2 MB (1.249.934 Bytes), aber das neue Bild ist 354,5 kB (354.541 Bytes) - Breite/Höhe ist für beide Bilder identisch.

+1

Warum verwenden Sie ImageIO zum Lesen und Schreiben? Du musst das nicht tun. Lies einfach die Bytes in der Datei, kodiere sie und schreibe das Ergebnis in eine andere Datei. Und umgekehrt zum Decodieren. –

+0

@ JBNizet danke für das Teilen. Wollen Sie damit sagen, dass die Dateigröße schrumpft oder dass ich sie auf jeden Fall vermeiden sollte? –

+1

Ich sage, dass dies der Grund für die Größenverkleinerung ist: Anstatt nur Bytes zu codieren, liest man sie als Bild im Speicher und schreibt das Bild dann in eine Datei um (die dabei in base64 kodiert wird)). –

Antwort

1

Wie @JBNizet in seinem Kommentar darauf hinweist, ist der Grund für die Änderung der Größe (die Größe kann je nach Eingabebild und Komprimierungseinstellungen ebenfalls steigen), dass Sie nicht nur binäre Daten codieren/dekodieren/von Base64, Sie sind auch Erneut Codierung die Bilddaten (zwei Mal) mit JPEG-Codierung (mit Standard-Encoding-Einstellungen). Wenn das ursprüngliche Bild nicht mit genau den gleichen Einstellungen codiert wurde, verlieren Sie etwas an Präzision, und die Dateigröße ändert sich.

Ein weiterer wahrscheinlicher Grund für die Verringerung der Dateigröße ist, dass ein BufferedImage keine der in der ursprünglichen JPEG-Datei enthaltenen Metadaten enthält. Ihr Prozess des erneuten Kodierens des JPEGs wird auch jegliche Exif- oder XMP-Metadaten, Thumbnails, Farbprofile usw. verlieren. Abhängig von der Quelle des Bildes kann dies zu einem erheblichen Teil der Dateigröße beitragen.

Nochmals, wie @JBNizet sagt, ist die beste Sache, in diesem Fall ImageIO überhaupt nicht zu involvieren, einfach normale Datei-I/O zu verwenden und die ursprünglichen Bytes mit Base64 zu codieren und wieder zu dekodieren, um den ursprünglichen Dateiinhalt genau wiederherzustellen .

PS: Wenn Sie beabsichtigen, zwischen dem Base64-Encoding/Decoding Bildverarbeitung auf dem Bild durchzuführen, müssen Sie die Bilddaten natürlich decodieren (ImageIO oder ähnliches), aber Sie sollten es nur einmal versuchen (für bessere Leistung), und vielleicht in die Erhaltung der Metadaten schauen. Außerdem denke ich, dass die Bildcodierung/-decodierung und die Base64-Codierung/Decodierung separate Probleme sind und nicht so verschachtelt werden sollten, wie es jetzt der Fall ist. Teilen Sie es auf, für eine better separation of concerns.