我正在使用android应用,用户将使用相机拍摄照片。生成的照片大小可以从<1 MB到3-4 MB以上不等。我需要确保照片小于1 MB,才能将其存储在服务器上。因此,对于大于1 MB的图像,我希望将其缩小到小于1 MB,但要保持尽可能高的质量。我不担心失去(某些)质量。
我该如何实现?据我所知,大多数解决方案都涉及将图像缩小到目标尺寸(宽度X高度),但就我而言,我只关心缩小图像的结果尺寸。
非常重要的是,结果必须小于1 MB,如果存在任何错误余量,则必须在较小的文件大小上。
有没有一种方法可以计算出达到目标文件大小的宽度和高度?还是更好,在不指定宽度和高度的情况下缩小它?
答案 0 :(得分:1)
我该如何实现?
三大选择是:
有没有一种方法可以计算出达到目标文件大小的宽度和高度?
不,因为它在很大程度上取决于图像的内容以及使用JPEG的压缩算法进行压缩的程度。
或者更好的是,在不指定宽度和高度的情况下缩小它?
要从3-4 MB减小到1 MB以下,几乎可以保证您需要降低分辨率。
但是,由于只有您知道自己认为可接受的输出,因此您将需要进行实验以确定如何最好地应用这三个选项。
答案 1 :(得分:1)
大约15年前,我使用Swing和javax.image
做过,唯一可行的解决方案是对JPG编码器应用不同的质量级别,以找到最佳质量设置,而该图像的图像质量仍小于要求的最大值尺寸。代码是这样的(这里的代码是由实际代码合成的,从未在此版本中测试过……):
/** Create JPG version of some image with given JPG quality setting (0..1), helper method */
private byte[] createResultBytes(BufferedImage losslessimage,float lossyquality) {
Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("JPG");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (iter.hasNext()) {
ImageWriter writer = iter.next();
ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(lossyquality);
MemoryCacheImageOutputStream mcios = new MemoryCacheImageOutputStream(baos);
writer.setOutput(mcios);
// workaround for alpha-channel problems with lossy images: Seems to be non-functional for some pictures, anyway.
BufferedImage img2=new BufferedImage(losslessimage.getWidth(),losslessimage.getHeight(),BufferedImage.TYPE_INT_RGB);
Graphics g=img2.getGraphics();
g.drawImage(new ImageIcon(losslessimage).getImage(),0,0,null);
g.dispose();
IIOImage iioimg = new IIOImage(img2, null, null);
try {
writer.write(null, iioimg, iwp);
mcios.close();
}
catch (IOException ioe) {}
}
return baos.toByteArray();
}
/** Create JPG version of some image with best JPG quality where the file size is still not larger than maxsize. */
public byte[] getLossyImage(BufferedImage losslessimage,int maxsize,float maxquality) {
byte[] resultbytes=createResultBytes(losslessimage,maxquality);
if (resultbytes.length>size) {
int minsize=(int)(size*.9f);
float newq=maxquality/2f;
resultbytes=createResultBytes(losslessimage,newq);
float qdiff=newq/2f;
while ((resultbytes.length<minsize || resultbytes.length>size) && diff>.02f) {
newq+=(resultbytes.length<minsize?qdiff:-qdiff);
resultbytes=createResultBytes(losslessimage,newq);
qdiff=qdiff/2f;
}
}
return resultbytes;
}
请注意,我仅通过JPG质量设置来更改文件大小,而不是通过自动更改图像大小来更改文件大小。如果要这样,则必须首先应用这些大小更改。