2016-04-17 68 views
0

我正在使用以下測試來讀取文件,基地64編碼它,然後解碼基地64回到一個新的圖像。我注意到新的圖像文件大小(轉換後)明顯小於原始圖像,導致我以某種方式認爲部分圖像數據在轉換中丟失。我可以看到圖像,但擔心圖像質量。任何有關我可能會做錯什麼的洞察力將不勝感激。基地64編碼/解碼後,圖像文件大小不同

Test類:

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); 
     } 

    } 

} 

ImageConverter

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; 
    } 
} 

我可以嘗試同時測試底座64編碼器/在jdk8可用譯碼器以及一個在sun.java。雜項(我意識到我不需要使用)。關於什麼可能會導致圖像大小縮小的任何想法(如果需要使用imagemagick或graphicsmagick等,我寧願自己做這件事)。

原始圖像是1.2 MB(1,249,934字節),但新圖像是354.5 kB(354,541字節) - 兩個圖像的寬度/高度相同。

+1

爲什麼使用ImageIO讀取和寫入?你不需要那樣做。只要讀取文件中的字節,對它們進行編碼並將結果寫入另一個文件。反之亦然解碼。 –

+0

@JBNizet感謝您的分享。你是說這是文件大小縮小的原因還是隻是我應該避免在任何情況下? –

+1

我在說這是大小縮減的原因:不是隻編碼字節,而是將它們作爲內存中的圖像讀取,然後將該圖像重新寫入文件(在進程中將其編碼爲base64) )。 –

回答

1

正如@JBNizet在他的評論中指出的那樣,尺寸變化的原因(尺寸可能會隨着輸入圖像和壓縮設置的增加而增長),是因爲您不僅僅是將二進制數據編碼/解碼爲/ from Base64,你也是使用JPEG編碼(默認編碼設置)重新編碼圖像數據(兩次)。除非原始圖像使用完全相同的設置進行編碼,否則您將失去一些精確度,文件大小將發生變化。

文件大小減小的另一個可能原因是BufferedImage不包含原始JPEG文件中包含的任何元數據。因此,對JPEG重新編碼的過程也會丟失任何Exif或XMP元數據,縮略圖,顏色配置文件等。根據圖像來源的不同,這可能會導致文件大小的很大一部分。

再次,正如@JBNizet所說,最好的情況是在這種情況下根本不涉及ImageIO,只需使用普通文件I/O並使用Base64對原始字節進行編碼,然後再次解碼以完全恢復原始文件內容。 PS:如果打算在Base64編碼/解碼之間對圖像進行圖像處理,您當然需要對圖像數據進行解碼(使用ImageIO或類似的方法),但是您應該只嘗試一次(以獲得更好的性能),並且可能會考慮保留元數據。另外,我認爲圖像編碼/解碼和Base64編碼/解碼是不同的問題,不應該像現在這樣交織。將其拆分爲better separation of concerns