【问题标题】:Reduce the size of a bitmap to a specified size in Android在Android中将位图的大小减小到指定的大小
【发布时间】:2013-06-01 23:46:04
【问题描述】:

我想将位图的大小精确地减小到 200kb。我从 sdcard 中获取图像,将其压缩并再次以不同的名称将其保存到 sdcard 到不同的目录中。压缩效果很好(3 mb 像图像被压缩到大约 100 kb)。为此,我编写了以下代码行:

String imagefile ="/sdcard/DCIM/100ANDRO/DSC_0530.jpg";
Bitmap bm = ShrinkBitmap(imagefile, 300, 300);

//this method compresses the image and saves into a location in sdcard
    Bitmap ShrinkBitmap(String file, int width, int height){

         BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
            bmpFactoryOptions.inJustDecodeBounds = true;
            Bitmap bitmap = BitmapFactory.decodeFile(file, bmpFactoryOptions);

            int heightRatio = (int)Math.ceil(bmpFactoryOptions.outHeight/(float)height);
            int widthRatio = (int)Math.ceil(bmpFactoryOptions.outWidth/(float)width);

            if (heightRatio > 1 || widthRatio > 1)
            {
             if (heightRatio > widthRatio)
             {
              bmpFactoryOptions.inSampleSize = heightRatio;
             } else {
              bmpFactoryOptions.inSampleSize = widthRatio; 
             }
            }

            bmpFactoryOptions.inJustDecodeBounds = false;
            bitmap = BitmapFactory.decodeFile(file, bmpFactoryOptions);

            ByteArrayOutputStream stream = new ByteArrayOutputStream();   
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);   
            byte[] imageInByte = stream.toByteArray(); 
            //this gives the size of the compressed image in kb
            long lengthbmp = imageInByte.length / 1024; 

            try {
                bitmap.compress(CompressFormat.JPEG, 100, new FileOutputStream("/sdcard/mediaAppPhotos/compressed_new.jpg"));
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }


         return bitmap;
        }

【问题讨论】:

  • 更改该图像的宽度和高度..
  • 你的意思是让图像变成 200x200?
  • 是的,根据你想要的 200kb .. 尝试直到你得到你的结果..
  • 好的,如果我给定一个恒定的宽度和高度,图像是否总是相同的大小?我已经这样做了:ShrinkBitmap(imagefile, 300, 300)
  • 不,根据你的尺寸改变宽度和高度。如果你在 300*300 上得到 100kb,那么为了使尺寸为 200kb,把宽度和高度都调高。。

标签: android bitmap bitmapimage image-compression


【解决方案1】:

我找到了一个非常适合我的答案:

/**
 * reduces the size of the image
 * @param image
 * @param maxSize
 * @return
 */
public Bitmap getResizedBitmap(Bitmap image, int maxSize) {
    int width = image.getWidth();
    int height = image.getHeight();

    float bitmapRatio = (float)width / (float) height;
    if (bitmapRatio > 1) {
        width = maxSize;
        height = (int) (width / bitmapRatio);
    } else {
        height = maxSize;
        width = (int) (height * bitmapRatio);
    }
    return Bitmap.createScaledBitmap(image, width, height, true);
}

调用方法:

Bitmap converetdImage = getResizedBitmap(photo, 500);

photo 是您的位图

【讨论】:

  • 如果位图较大,此功能将减小位图大小,但较小的位图会怎样。会按规格放大吗?
  • @TharakaNirmana maxSize 是什么?在您的方法调用中是 500、500 kb 还是 500 mb?
  • Max 指的是宽度和高度,而不是大小。 developer.android.com/reference/android/graphics/…, int, int, boolean)
  • @TharakaNirmana 500 mb 也许不是,但这可能是 500kb 500KB 500ko ...
  • 这个答案如何被接受? OP 说:“我想将位图的大小精确地减小到 200kb”。所以我不明白答案将如何将大小减少到某个“千字节”。
【解决方案2】:

这是在不更改widthheight 的情况下限制图像质量的解决方案。这种方法的主要思想是在输出大小大于maxSizeBytesCount 时在循环内压缩位图。归功于this question 的答案。此代码块仅展示了降低图像质量的逻辑:

        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        int currSize;
        int currQuality = 100;

        do {
            bitmap.compress(Bitmap.CompressFormat.JPEG, currQuality, stream);
            currSize = stream.toByteArray().length;
            // limit quality by 5 percent every time
            currQuality -= 5;

        } while (currSize >= maxSizeBytes);

这里是完整的方法:

public class ImageUtils {

    public byte[] compressBitmap(
            String file, 
            int width, 
            int height,
            int maxSizeBytes
    ) {
        BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
        bmpFactoryOptions.inJustDecodeBounds = true;
        Bitmap bitmap;

        int heightRatio = (int)Math.ceil(bmpFactoryOptions.outHeight/(float)height);
        int widthRatio = (int)Math.ceil(bmpFactoryOptions.outWidth/(float)width);

        if (heightRatio > 1 || widthRatio > 1)
        {
            if (heightRatio > widthRatio)
            {
                bmpFactoryOptions.inSampleSize = heightRatio;
            } else {
                bmpFactoryOptions.inSampleSize = widthRatio;
            }
        }

        bmpFactoryOptions.inJustDecodeBounds = false;
        bitmap = BitmapFactory.decodeFile(file, bmpFactoryOptions);

        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        int currSize;
        int currQuality = 100;

        do {
            bitmap.compress(Bitmap.CompressFormat.JPEG, currQuality, stream);
            currSize = stream.toByteArray().length;
            // limit quality by 5 percent every time
            currQuality -= 5;

        } while (currSize >= maxSizeBytes);

        return stream.toByteArray();
    }
}

【讨论】:

  • 不是很好的方法,压缩操作要求很高。如果我们可以预测质量并只压缩一次位图,那就太好了。不过,创造性思维。
  • 我希望你描述的解决方案存在,但我认为 JPEG 是不可能的:(
  • “尝试在位图中的空对象引用上调用虚拟方法 'boolean android.graphics.Bitmap.compress(android.graphics.Bitmap$CompressFormat, int, java.io.OutputStream)'”。压缩(Bitmap.CompressFormat.JPEG,currQuality,流);
  • 上一个解决方案进入不定式循环只需“ByteArrayOutputStream stream = new ByteArrayOutputStream();”循环内
【解决方案3】:

@TharakaNirmana 的方法运行良好,maxSize 以千字节为单位

例子:

fun getResizedBitmap(image: Bitmap, maxSize: Int): Bitmap? {
    var width = image.width
    var height = image.height
    val bitmapRatio = width.toFloat() / height.toFloat()
    if (bitmapRatio > 1) {
        width = maxSize
        height = (width / bitmapRatio).toInt()
    } else {
        height = maxSize
        width = (height * bitmapRatio).toInt()
    }
    return Bitmap.createScaledBitmap(image, width, height, true)
}

用法:

bitmap.let {
    val data = it.value

    if (data != null) {

        var image = viewModel.getResizedBitmap(data, 170)
        Log.d ("bitmap size", image!!.byteCount.toString()) ...

回答

2021-12-18 12:38:11.218 25502-25502/com.jdsalasc.sophosSolutions D/位图尺寸:67200 2021-12-18 12:39:11.673 25745-25745/com.jdsalasc.sophosSolutions D/位图尺寸:67200 2021-12-18 12:39:14.511 25745-25745/com.jdsalasc.sophosSolutions D/位图尺寸:90000 2021-12-18 12:39:20.423 25745-25745/com.jdsalasc.sophosSolutions D/位图尺寸:67200 2021-12-18 12:39:40.112 25907-25907/com.jdsalasc.sophosSolutions D/位图尺寸:120000 2021-12-18 12:39:43.322 25907-25907/com.jdsalasc.sophosSolutions D/位图尺寸:120000 2021-12-18 12:39:47.314 25907-25907/com.jdsalasc.sophosSolutions D/位图尺寸:160000 2021-12-18 12:40:17.231 26069-26069/com.jdsalasc.sophosSolutions D/位图尺寸:115600 2021-12-18 12:40:19.583 26069-26069/com.jdsalasc.sophosSolutions D/位图尺寸:86360

你看,字节大小永远不会超过 150 kb

谢谢 Zoe 和 TharakaNirmana c:

【讨论】:

    猜你喜欢
    • 2013-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-02
    • 2012-06-19
    相关资源
    最近更新 更多