您的位置:首页 > 移动开发 > Android开发

正确的对待android的图片处理与压缩,你所熟悉而又陌生的bitmap

2016-09-21 21:38 615 查看

  你有没有这样的经历?:有些问题,你搜来搜去,都是那些重复的东西,只是展现在不同的平台或者博客中;而且重点事,貌似都解决不了实际问题。


  比如:bitmap相关的图片处理等知识就是其中的一种。



  我要说的是;最好的解决办法就是源代码,加上多思考。因为:除去人云亦云,没有经过实践证明的错误解答外,好多网上搜寻的答案和你要解决的问题没有共同的背景。


  这里在我遇到的真实项目中,我想谈谈我所了解的图片压缩。 (仅仅是JAVA代码层面的。)


 当然最好的解决方案是要用C,C++去实现的,为什么呢?

 android 图片处理这块,java层面的其实只有两个方法,一个是

 public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {}

另外一个是:public boolean compress(CompressFormat format, int quality, OutputStream stream) {}

其他的方法基本上也是多少和这些代码有联系。

1. decodeStream,是输入流写入bitmap如,图片压缩生成bitmap然后在view中显示。

2.compress 是将bitmap 写入输出流,如:bitmap压缩并生成文件。

而看他们的源代码:

 public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {

        // we don't throw in this case, thus allowing the caller to only check

        // the cache, and not force the image to be decoded.

        if (is == null) {

            return null;

        }

        // we need mark/reset to work properly

        if (!is.markSupported()) {

            is = new BufferedInputStream(is, 16 * 1024);

        }

        // so we can call reset() if a given codec gives up after reading up to

        // this many bytes. FIXME: need to find out from the codecs what this

        // value should be.

        is.mark(1024);

        Bitmap  bm;

        if (is instanceof AssetManager.AssetInputStream) {

            bm = nativeDecodeAsset(((AssetManager.AssetInputStream) is).getAssetInt(),

                    outPadding, opts);

        } else {

            // pass some temp storage down to the native code. 1024 is made up,

            // but should be large enough to avoid too many small calls back

            // into is.read(...) This number is not related to the value passed

            // to mark(...) above.

            byte [] tempStorage = null;

            if (opts != null) tempStorage = opts.inTempStorage;

            if (tempStorage == null) tempStorage = new byte[16 * 1024];

            bm = nativeDecodeStream(is, tempStorage, outPadding, opts);

        }

        if (bm == null && opts != null && opts.inBitmap != null) {

            throw new IllegalArgumentException("Problem decoding into existing bitmap");

        }

        return finishDecode(bm, outPadding, opts);

    }

public boolean compress(CompressFormat format, int quality, OutputStream stream) {

        checkRecycled("Can't compress a recycled bitmap");

        // do explicit check before calling the native method

        if (stream == null) {

            throw new NullPointerException();

        }

        if (quality < 0 || quality > 100) {

            throw new IllegalArgumentException("quality must be 0..100");

        }

        return nativeCompress(mNativeBitmap, format.nativeInt, quality,

                              stream, new byte[WORKING_COMPRESS_STORAGE]);

    }

这两部分JAVA代码其实未做任何处理,都交给了底层JNI代码去实现。


回到正题,首先我们要知道bitmap是什么?

说到bitmap 我们先要认识一个重要的人物:像素。

bitmap是用来存储颜色等数据,像素则是图片的基本显示单位。

看看百度关于像素的两部分介绍:

从定义上来看,像素是指基本原色素及其灰度的基本编码。[1] 
像素是构成数码影像的基本单元,通常以像素每英寸PPI(pixels
per inch)为单位来表示影像分辨率的大小。

例如300x300PPI分辨率,即表示水平方向与垂直方向上每英寸长度上的像素数都是300,也可表示为一平方英寸内有9万(300x300)像素。[2] 

如同摄影的相片一样,数码影像也具有连续性的浓淡阶调,我们若把影像放大数倍,会发现这些连续色调其实是由许多色彩相近的小方点所组成,这些小方点就是构成影像的最小单元——像素。这种最小的图形单元在屏幕上显示通常是单个的染色点。越高位的像素,其拥有的色板也就越丰富,也就越能表达颜色的真实感。


位图是位的数组,它制订了像素矩阵中各像素的颜色。

亦称为点阵图像或绘制图像,是由称作像素(图片元素)的单个点组成的。这些点可以进行不同的排列和染色以构成图样。当放大位图时,可以看见赖以构成整个图像的无数单个方块。扩大位图尺寸的效果是增多单个像素,从而使线条和形状显得参差不齐。然而,如果从稍远的位置观看它,位图图像的颜色和形状又显得是连续的。在体检时,工作人员会给你一个本子,在这个本子上有一些图像,而图像都是由一个个的点组成的,这和位图图像其实是差不多的。由于每一个像素都是单独染色的,您可以通过以每次一个像素的频率操作选择区域而产生近似相片的逼真效果,诸如加深阴影和加重颜色。缩小位图尺寸也会使原图变形,因为此举是通过减少像素来使整个图像变小的。同样,由于位图图像是以排列的像素集合体形式创建的,所以不能单独操作(如移动)局部位图。



总结:像素其实是由多种色彩组成的,增加图片的宽高,其实是增加像素的数量。如果色彩不变的话,BITMAP也变大。或者宽高不变,增加每个像素的色彩,BITMAP也变大。比如:1000*1000的图片,其实宽高都有1000个像素。缩小到100*100。那么像素也变为100*100。它在内存中占用的大小是:100*100*色彩位。

反过来,试想下:你所看到的像素变少了(1000*1000个到100*100个),那么反映到人的视觉神经,是不是他变小了。


补充:

BitMap代表一张位图,扩展名可以是.bmp或者.dib。位图是Windows标准格式图形文件,它将图像定义为由点(像素)组成,每个点可以由多种色彩表示,包括2、4、8、16、24和32位色彩。

例如,一幅1024×768分辨率的32位真彩图片,其所占存储字节数为:1024×768×32/(8*1024)=3072KB

位图文件图像效果好,但是非压缩格式的,需要占用较大存储空间,不利于在网络上传送。

file.length:1969

getByteCount:8432

文件长度是1969的图片对应的bitmap是8432。


2)jpg格式则恰好弥补了位图文件这个缺点。

所以往往compress(CompressFormat format, int quality, OutputStream stream)方法中CompressFormat往往用JPEG表示。

而对于PNG格式,quality无论如何设置都无效。但是JPEG也有一个缺点:JPEG格式是无透明度的,所以一般比较小。


3).bitmap位图可以被GZIP压缩很小,


4).图片file转换成bitmap之后,变大,主要是因为file是进行了某种方式的压缩,如,jpeg,png,webp等,

webp压缩效果最好。PNG不失真,但是要注意的是,webp只支持android系统,在windows,mac系统中图片打开会出错。






内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息