我使用以下测试来读取文件,base 64对其进行编码,然后将base 64解码回新图像。我注意到新的图像文件大小(转换后)明显小于原始图像,导致我认为不知何故,部分图像数据在转换中丢失。我可以看到图像,但我担心图像质量。任何关于我可能做错的见解都将非常感激。
测试类:
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;
}
}
我可以尝试测试jdk8中可用的base 64编码器/解码器以及sun.java.misc中的那个(我意识到我不需要使用它)。关于什么可能导致图像大小缩小的任何想法(如果需要使用imagemagick或graphicsmagick等,我宁愿自己这样做。)
原始图像为1.2 MB(1,249,934字节),但新图像为354.5 kB(354,541字节) - 两个图像的宽度/高度相同。
答案 0 :(得分:1)
正如@JBNizet在他的评论中指出的那样,尺寸变化的原因(尺寸可能会增长,取决于输入图像和压缩设置),就是你不只是将二进制数据编码/解码为/从Base64开始,您还使用JPEG编码(默认编码设置)重新编码图像数据(两次)。除非使用完全相同的设置对原始图像进行编码,否则会丢失一些精度,文件大小也会改变。
文件大小减少的另一个可能原因是BufferedImage
不携带原始JPEG文件中包含的任何元数据。因此,重新编码JPEG的过程也会丢失任何Exif或XMP元数据,缩略图,颜色配置文件等。根据图像的来源,这可能会占据文件大小的很大一部分。
再次,正如@JBNizet所说,在这种情况下最好不要涉及ImageIO
,只需使用普通文件I / O并使用Base64对原始字节进行编码,然后再次解码以恢复原始文件文件内容完全正确。
PS:如果你打算在Base64编码/解码之间对图像进行图像处理,你当然需要解码图像数据(使用ImageIO
或类似),但你应该尝试做它只有一次(为了更好的性能),并且可能会考虑保留元数据。此外,我认为图像编码/解码和Base64编码/解码是分开的问题,不应该像现在一样交错。将其拆分为better separation of concerns。