android图片压缩总结

作者:操作系统    发布时间:2020-02-02 23:44     浏览次数 :

[返回]

图片 1

【借使您想领悟那一个点读笔写字App的背景,请移步这里
http://www.jianshu.com/p/ee2a1bb99280 】

意气风发、bitmap 图片格式介绍

android中图纸是以bitmap方式存在的,那么bitmap所占内部存款和储蓄器,直接影响到了动用所占内部存款和储蓄器大小,首先要知道bitmap所占内部存储器大小总括方法:

  bitmap内部存款和储蓄器大小 =  图片长度 x 图片宽度 x 贰个像素点占用的字节数

以下是图表的压缩格式:

图片 2

其间,A代表反射率;昂Cora代表中湖蓝;G代表黑褐;B代表青白。  

  1. ALPHA_8         表示8位Alpha位图,即A=8,叁个像素点占用1个字节,它并未颜色,独有反射率  
  2. ARGB_4444    表示16人A奥迪Q3GB位图,即A=4,Koleos=4,G=4,B=4,贰个像素点占4+4+4+4=15个人,2个字节 
  3. ARGB_8888    表示叁10位A福睿斯GB位图,即A=8,Tiguan=8,G=8,B=8,一个像素点占8+8+8+8=叁14位,4个字节 
  4. RGB_565         表示十六人安德拉GB位图,即Wrangler=5,G=6,B=5,它未有反射率,一个像素点占5+6+5=20人,2个字节

中间有关函数介绍:

显示bitmap: 

支出中通常会境遇射击师队友提议的狼狈按键的难题,早前蒙受外人要做扇形、五角星按键,本人也蒙受过梯形的,图形各异,假设自个儿去算真的蛋疼。考虑到黄金时代种同等的艺术,监听控件的点击的点,并得到其相应的像素点,点击到透明背景(无需点击的地点卡塔尔(قطر‎的像素点为0,那时不做操作,若点击像素点不为0为决断为UI有效部分实行点击事件。早先写了个demo,。不过这一个demo存在多个标题,间接拿到imagebutton的drawable,drawable是原本图片的深浅,可是imagebutton大小确是足以转移的比如能够定死width300dpheight200dp,最终结果是点击的像素点和原始图片的像素点映射不对应。所以要将全体imagebutton转变为bitmap,再来做映射。view转变bitmap的代码如下:

直到那篇文章的时候,作者并不知道在android App运营的长河中必要利用到的图纸文件应该放权哪个地方相比较适宜,一点得以确定的是无法在app安装时直接写到安装路线包的公文夹下边,因为如此会时有产生误删,进而引起app启动时拿到不到图片的谬误。倘使不该如此做,麻烦告诉自身应该放置哪吧。

二、生成Bitmap对象:

1. 从drawable能源文件中生成Bitmap对象:能够通过Option设置生成bitmap的质量

BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inScaled  = false;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.kb455,options);

注: 假设财富只放在drawable目录下,没有在hdpi等文件夹中,获取的bitmap文件会要命大,超越原始图片的分寸,很或许现身OOM。

风流罗曼蒂克种方法是将财富文件放在各类 dpi目录下  二、能够安装为options.inscaled = false,生成的bitmap与图片大小后生可畏致。

  还是能够透过此外门路生成bitmap如inputstream,代码见“四”中的例子。

这里须要潜心的是 Option.inJustDecodeBounds 那些变量,官方的分解:

If set to true, the decoder will return null (no bitmap), but the out… fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels.

当只是须求来获取图片的宽高而不创立三个 bitmap对象时索要设置为 true,那个时候系统不会分配 bitmap的内存。如下是合法的事例:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
publicBitmapgetBitmapFromView(Viewview){view.setDrawingCacheEnabled(true);view.measure(MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED),MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED));view.layout(0,0,view.getMeasuredWidth(),view.getMeasuredHeight());view.buildDrawingCache(true);Bitmapb=Bitmap.createBitmap(view.getDrawingCache());view.setDrawingCacheEnabled(false);//cleardrawingcachereturnb;}

正如标题所说的,作者把她放到了Drawable中,运转中就足以方便的收获图片了,可是放到drawable文件中有益的还要也给本身带给一些麻烦,下边听自身慢慢道来呢。

三、图片压缩(不变图片宽高)

  上边代码通过while循环将图纸压缩到topLimit(KB)之下,可是该种方法有个破绽,假若topLimit十分的小,不过原始的Bitmap

又一点都不小,当options减小到负值时任然不可能达到目标大小之下。(

public static byte[] compressQualityBitmap(Bitmap bitmap, int topLimit) {
        if(bitmap != null && topLimit > 0) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int options = 100;
            bitmap.compress(CompressFormat.JPEG, options, baos);

            while(baos.toByteArray().length > topLimit * 1024) {
                baos.reset();
                options -= 5;
                bitmap.compress(CompressFormat.JPEG, options, baos);
            }

            byte[] bitmapArray = baos.toByteArray();

            try {
                baos.close();
                baos = null;
            } catch (IOException var14) {
                ;
            } finally {
                if(baos != null) {
                    try {
                        baos.close();
                        baos = null;
                    } catch (IOException var13) {
                        ;
                    }
                }

                return bitmapArray;
            }
        } else {
            return null;
        }
    }

1、上边函数是在维系像素的前提下退换图片的位深及光滑度等,来达成缩小图片的目标,那也是干吗该办法叫质量滑坡方法。图片的长,宽,像素都不改变,bitmap所占内部存储器大小是不会变的,可是压缩到byte数组baos的尺寸会日渐的变小。

     bitmap.compress(CompressFormat.JPEG, options, baos);

2、要求要是是bit.compress(CompressFormat.PNG, quality, baosState of Qatar;那样的png格式,quality就向来不遵循了,bytes.length不会调换,因为png图片是无毒的,不可能开展裁减。

3、该办法压缩并不能够无界定的减弱,当压缩到自然水准后,baos的尺寸变不再变化。

 

校勘图片的格式: 

  第意气风发章中列出了多样格式的Config,能够将AWranglerGB_8888格式转换为 RubiconGB_565存款和储蓄空间可以减掉为本来的百分之五十,而不改过图片的宽高。

做了后难点来了,直接传入imagebutton后getDrawingCache为null,假设在imagebutton外面加个RelativeLayout,并带走RelativeLayout能收获bitmap,最终运维期待效果也可能有了。难题是为啥会为null或然有未有此外更加好的不二等秘书诀

在app中,作者去赢得图片来作为台式机的页背景(便是平日的台式机上风流罗曼蒂克行业作风流倜傥行的行文线的标准),在上头书写,实际也便是用特定的像素点去代替在此以前背景图片的像素点了。当然最后台式机的写上内容的图纸是急需保留的,因为小编期望后一次张开笔记本的时候,笔者在那少年老成页页上写下的小心思照旧存在的。当然小编没办法再把它们存在drawable中了,小编接纳把这几个记录保留到地面。

四、图片缩放(改变图片宽高)

 1、bitmap采集样板率压缩:在BitmapFactory.decodexxxx(卡塔尔(قطر‎设置 options.inSampleSize 大小来缩放图片举例: 为2时,缩放为原来宽高的八分之四。

public static Bitmap compressBoundsBitmap(Context context, Uri uri, int targetWidth, int targetHeight) {
        InputStream input = null;
        Bitmap bitmap = null;

        try {
            input = context.getContentResolver().openInputStream(uri);
            Options options = new Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(input, (Rect)null, options);
            input.close();
            int originalWidth = options.outWidth;
            int originalHeight = options.outHeight;
            if(originalWidth != -1 && originalHeight != -1) {
                boolean be1 = true;
                int widthBe = 1;
                if(originalWidth > targetWidth) {
                    widthBe = originalWidth / targetWidth;
                }

                int heightBe = 1;
                if(originalHeight > targetHeight) {
                    heightBe = originalHeight / targetHeight;
                }

                int be2 = widthBe > heightBe?heightBe:widthBe;
                if(be2 <= 0) {
                    be2 = 1;
                }

                options.inJustDecodeBounds = false;
                options.inSampleSize = be2;
                input = context.getContentResolver().openInputStream(uri);
                bitmap = BitmapFactory.decodeStream(input, (Rect)null, options);
                input.close();
                input = null;
            } else {
                Object be = null;
            }
        } catch (FileNotFoundException var23) {
            ;
        } catch (IOException var24) {
            ;
        } finally {
            if(input != null) {
                try {
                    input.close();
                } catch (IOException var22) {
                    ;
                }
            }

            return bitmap;
        }
    }

可取:功用较高,解析速度快

症结:采集样本率inSampleSize的取值只好是2的次方数(举例:in萨姆pleSize=15,实际取值为8;inSampleSize=17,实际取值为16;实际取值会往2的次方付账卡塔尔(قطر‎,由此该格局不能够规范的钦定图片的分寸

 

2.因而Matrix缩放图片(不推荐卡塔尔(قطر‎

图片 3图片 4

/**
 * 图片的缩放方法
 *
 * @param bitmap  :源图片资源
 * @param maxSize :图片允许最大空间  单位:KB
 * @return
 */
public static Bitmap getZoomImage(Bitmap bitmap, double maxSize) {
    if (null == bitmap) {
        return null;
    }
    if (bitmap.isRecycled()) {
        return null;
    }

    // 单位:从 Byte 换算成 KB
    double currentSize = bitmapToByteArray(bitmap, false).length / 1024;
    // 判断bitmap占用空间是否大于允许最大空间,如果大于则压缩,小于则不压缩
    while (currentSize > maxSize) {
        // 计算bitmap的大小是maxSize的多少倍
        double multiple = currentSize / maxSize;
        // 开始压缩:将宽带和高度压缩掉对应的平方根倍
        // 1.保持新的宽度和高度,与bitmap原来的宽高比率一致
        // 2.压缩后达到了最大大小对应的新bitmap,显示效果最好
        bitmap = getZoomImage(bitmap, bitmap.getWidth() / Math.sqrt(multiple), bitmap.getHeight() / Math.sqrt(multiple));
        currentSize = bitmapToByteArray(bitmap, false).length / 1024;
    }
    return bitmap;
}

/**
 * 图片的缩放方法
 *
 * @param orgBitmap :源图片资源
 * @param newWidth  :缩放后宽度
 * @param newHeight :缩放后高度
 * @return
 */
public static Bitmap getZoomImage(Bitmap orgBitmap, double newWidth, double newHeight) {
    if (null == orgBitmap) {
        return null;
    }
    if (orgBitmap.isRecycled()) {
        return null;
    }
    if (newWidth <= 0 || newHeight <= 0) {
        return null;
    }

    // 获取图片的宽和高
    float width = orgBitmap.getWidth();
    float height = orgBitmap.getHeight();
    // 创建操作图片的matrix对象
    Matrix matrix = new Matrix();
    // 计算宽高缩放率
    float scaleWidth = ((float) newWidth) / width;
    float scaleHeight = ((float) newHeight) / height;
    // 缩放图片动作
    matrix.postScale(scaleWidth, scaleHeight);
    Bitmap bitmap = Bitmap.createBitmap(orgBitmap, 0, 0, (int) width, (int) height, matrix, true);
    return bitmap;
}

/**
 * bitmap转换成byte数组
 *
 * @param bitmap
 * @param needRecycle
 * @return
 */
public static byte[] bitmapToByteArray(Bitmap bitmap, boolean needRecycle) {
    if (null == bitmap) {
        return null;
    }
    if (bitmap.isRecycled()) {
        return null;
    }

    ByteArrayOutputStream output = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.PNG, 100, output);
    if (needRecycle) {
        bitmap.recycle();
    }

    byte[] result = output.toByteArray();
    try {
        output.close();
    } catch (Exception e) {
        Log.e(TAG, e.toString());
    }
    return result;
}

View Code

可取:能够确切地钦定图片的缩放大小

症结:是在原bitmap的功底之上生成的,占内部存款和储蓄器,功能低.

 

3/ThumbnailUtils 类进行

 

 将bitmap转换为byte方法:

public static byte[] BitmapToByte(Bitmap bitmap) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    bitmap.compress(CompressFormat.PNG, 80, baos);//其中80参数表示要压缩的比例
    return baos.toByteArray();
}

 

 参考: