Android - 减小图像文件大小

Posted

技术标签:

【中文标题】Android - 减小图像文件大小【英文标题】:Android - Reduce image file size 【发布时间】:2012-06-19 03:35:36 【问题描述】:

我有一个 URI 图像文件,我想减小它的大小来上传它。初始图像文件大小取决于移动设备(可以是 2MB,也可以是 500KB),但我希望最终大小约为 200KB,以便上传。 根据我的阅读,我有(至少)两个选择:

使用BitmapFactory.Options.inSampleSize,对原始图像进行二次采样,得到更小的图像; 使用 Bitmap.compress 压缩指定压缩质量的图像。

什么是最好的选择?


我正在考虑最初调整图像宽度/高度的大小,直到宽度或高度超过 1000 像素(例如 1024x768 或其他),然后以降低的质量压缩图像,直到文件大小超过 200KB。这是一个例子:

int MAX_IMAGE_SIZE = 200 * 1024; // max final file size
Bitmap bmpPic = BitmapFactory.decodeFile(fileUri.getPath());
if ((bmpPic.getWidth() >= 1024) && (bmpPic.getHeight() >= 1024)) 
    BitmapFactory.Options bmpOptions = new BitmapFactory.Options();
    bmpOptions.inSampleSize = 1;
    while ((bmpPic.getWidth() >= 1024) && (bmpPic.getHeight() >= 1024)) 
        bmpOptions.inSampleSize++;
        bmpPic = BitmapFactory.decodeFile(fileUri.getPath(), bmpOptions);
    
    Log.d(TAG, "Resize: " + bmpOptions.inSampleSize);

int compressQuality = 104; // quality decreasing by 5 every loop. (start from 99)
int streamLength = MAX_IMAGE_SIZE;
while (streamLength >= MAX_IMAGE_SIZE) 
    ByteArrayOutputStream bmpStream = new ByteArrayOutputStream();
    compressQuality -= 5;
    Log.d(TAG, "Quality: " + compressQuality);
    bmpPic.compress(Bitmap.CompressFormat.JPEG, compressQuality, bmpStream);
    byte[] bmpPicByteArray = bmpStream.toByteArray();
    streamLength = bmpPicByteArray.length;
    Log.d(TAG, "Size: " + streamLength);

try 
    FileOutputStream bmpFile = new FileOutputStream(finalPath);
    bmpPic.compress(Bitmap.CompressFormat.JPEG, compressQuality, bmpFile);
    bmpFile.flush();
    bmpFile.close();
 catch (Exception e) 
    Log.e(TAG, "Error on saving file");

有没有更好的方法呢?我应该尝试继续使用所有两种方法还是只使用一种?谢谢

【问题讨论】:

源图片是png还是jpg? 【参考方案1】:

使用Bitmap.compress() 您只需指定压缩算法,顺便说一下压缩操作需要相当长的时间。如果您需要调整大小以减少图像的内存分配,您确实需要使用Bitmap.Options 对图像进行缩放,首先计算位图边界,然后将其解码为您指定的大小。

我在 *** 上找到的最佳示例是 this one。

【讨论】:

我的第一个想法是迭代图像的缩放(使用inSampleSize)直到图像文件低于MAX_IMAGE_SIZE,但是由于我必须将位图保存到文件中,所以我必须使用@ 987654326@(或者可能有不同的方法将其保存在文件中?),并称它为 100% 质量,图像变得比MAX_IMAGE_SIZE 大,所以无论如何我应该迭代Bitmap.compress()(降低质量)直到文件大小 MAX_IMAGE_SIZE。也许有更好的解决方案?【参考方案2】:

我找到的大部分答案只是我必须拼凑起来以获得工作代码的部分,该代码发布在下面

 public void compressBitmap(File file, int sampleSize, int quality) 
        try 
           BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize = sampleSize;
            FileInputStream inputStream = new FileInputStream(file);

            Bitmap selectedBitmap = BitmapFactory.decodeStream(inputStream, null, options);
            inputStream.close();

            FileOutputStream outputStream = new FileOutputStream("location to save");
            selectedBitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
            outputStream.close();
            long lengthInKb = photo.length() / 1024; //in kb
            if (lengthInKb > SIZE_LIMIT) 
               compressBitmap(file, (sampleSize*2), (quality/4));
            

            selectedBitmap.recycle();
         catch (Exception e) 
            e.printStackTrace();
        
    

2个参数sampleSize和quality起重要作用

sampleSize用于对原图进行二次采样,返回较小的图像,即 SampleSize == 4 返回的图像是原始宽度/高度的 1/4。

品质用于提示压缩器,输入范围在0-100之间。 0 表示压缩为 小尺寸,100 表示压缩以获得最大质量

【讨论】:

显然这不是完整的。变量“photo”甚至没有在本地声明。此外,它使用递归,这不是一个好主意。 @Shroud 请随时编辑和添加缺少的东西, @Pawan Y is Recursion is not a good Idea,整个android onDraw onLayout onMeasure使用递归传递视图 @war_Hero :兄弟,我使用日志打印了开始和结束时间。这比我在没有递归的情况下编写的正常逻辑要花费更多的时间。其次,您在这里编写的代码有很多未定义的变量,如果您能给这些未定义的变量提供一些 cmets,我会很高兴。 @Pawan 你能和我们分享你的工作代码,以便未来的访问者可以看看它是如何完成的吗?【参考方案3】:

BitmapFactory.Options - 减小图像大小(在内存中)

Bitmap.compress() - 减小图像大小(在磁盘中)


有关使用它们的更多信息,请参阅此链接: https://android.jlelse.eu/loading-large-bitmaps-efficiently-in-android-66826cd4ad53

【讨论】:

你的答案如何改进之前接受的答案?

以上是关于Android - 减小图像文件大小的主要内容,如果未能解决你的问题,请参考以下文章

减小一些 pdf 文件的大小

如何使用 PIL 减小图像文件大小

减小 png 图像的文件大小

磁盘上的图像文件大小(KB)随着Java中动态图像大小的调整(减小大小)而增加

如何在本机反应中减小图像文件大小?

在android中减小从相机捕获的图像的大小