我想将 JPEG 压缩为固定文件大小(20480 字节)。这是我的代码:
package io.github.baijifeilong.jpeg;
import lombok.SneakyThrows;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.FileImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
/**
* Created by BaiJiFeiLong@gmail.com at 2019/10/9 上午11:26
*/
public class JpegApp {
@SneakyThrows
public static void main(String[] args) {
BufferedImage inImage = ImageIO.read(new File("demo.jpg"));
BufferedImage outImage = new BufferedImage(143, 143, BufferedImage.TYPE_INT_RGB);
outImage.getGraphics().drawImage(inImage.getScaledInstance(143, 143, Image.SCALE_SMOOTH), 0, 0, null);
JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null);
jpegParams.setCompressionMode(ImageWriteParam.MODE_DISABLED);
ImageWriter imageWriter = ImageIO.getImageWritersByFormatName("jpg").next();
imageWriter.setOutput(new FileImageOutputStream(new File("demo-xxx.jpg")));
imageWriter.write(null, new IIOImage(outImage, null, null), jpegParams);
}
}
并且发生了错误:
Exception in thread "main" javax.imageio.IIOException: JPEG compression cannot be disabled
at com.sun.imageio.plugins.jpeg.JPEGImageWriter.writeOnThread(JPEGImageWriter.java:580)
at com.sun.imageio.plugins.jpeg.JPEGImageWriter.write(JPEGImageWriter.java:363)
at io.github.baijifeilong.jpeg.JpegApp.main(JpegApp.java:30)
Process finished with exit code 1
那么如何禁用JPEG压缩呢?或者有什么方法可以通过任何压缩将任何图像压缩为固定文件大小?
最佳答案
至于最初的问题,如何创建未压缩的 jpeg:出于根本原因,不能。虽然我最初假设可以编写一个非压缩的 jpg 编码器产生输出,通过操作所涉及的哈夫曼树,可以使用任何现有的解码器进行解码,I had to dismiss it .霍夫曼编码只是相当多的转换管道的最后一步,不能跳过。 Custom Huffman trees也可能破坏不太复杂的解码器。
对于考虑到评论中的需求更改的答案(以您喜欢的任何方式调整大小和压缩,只需给我所需的文件大小),可以这样推理:
jpeg file specification定义图像结束标记。所以很有可能,事后修补零(或者只是任何东西)没有任何区别。将一些图像修补到特定大小的实验表明,gimp、chrome、firefox 和您的 JpegApp 毫无怨言地吞下了这样一个膨胀的文件。
为任何图像创建一个精确压缩到您的尺寸要求的压缩是相当复杂的(类型:对于图像 A,您需要 0.7143 的压缩比,对于图像 B 0.9356633,对于 C 12.445 ...)。有尝试predict image compression ratios不过,基于原始图像数据。
所以我建议只调整/压缩到任何小于 20480 的大小,然后修补它:
所需的大小,包括一个安全裕度来考虑
问题本质上是模糊的
如此处所述
private static void scaleAndcompress(String fileNameIn, String fileNameOut, Long desiredSize) {
try {
long size = getSize(fileNameIn);
// calculate desired ratio for conversion to stay within size limit, including a safte maring (of 10%)
// to account for the vague nature of the procedure. note, that this will also scale up if needed
double desiredRatio = (desiredSize.floatValue() / size) * (1 - SAFETY_MARGIN);
BufferedImage inImg = ImageIO.read(new File(fileNameIn));
int widthOut = round(inImg.getWidth() * desiredRatio);
int heigthOut = round(inImg.getHeight() * desiredRatio);
BufferedImage outImg = new BufferedImage(widthOut, heigthOut, BufferedImage.TYPE_INT_RGB);
outImg.getGraphics().drawImage(inImg.getScaledInstance(widthOut, heigthOut, Image.SCALE_SMOOTH), 0, 0, null);
JPEGImageWriter imageWriter = (JPEGImageWriter) ImageIO.getImageWritersByFormatName("jpg").next();
ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
imageWriter.setOutput(new MemoryCacheImageOutputStream(outBytes));
imageWriter.write(null, new IIOImage(outImg, null, null), new JPEGImageWriteParam(null));
if (outBytes.size() > desiredSize) {
throw new IllegalStateException(String.format("Excess output data size %d for image %s", outBytes.size(), fileNameIn));
}
System.out.println(String.format("patching %d bytes to %s", desiredSize - outBytes.size(), fileNameOut));
patch(desiredSize, outBytes);
try (FileOutputStream outFileStream = new FileOutputStream(new File(fileNameOut))) {
outBytes.writeTo(outFileStream);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void patch(Long desiredSize, ByteArrayOutputStream bytesOut) {
long patchSize = desiredSize - bytesOut.size();
for (long i = 0; i < patchSize; i++) {
bytesOut.write(0);
}
}
private static long getSize(String fileName) {
return (new File(fileName)).length();
}
private static int round(double f) {
return Math.toIntExact(Math.round(f));
}
关于java - 在java中编写JPEG时如何禁用压缩?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58297626/