在Android的图片传输的流程为:
Bitmap的转换为二进制流:
//将bitmap转换为二进制流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
其中,我们知道compress的方法是进行压缩的,其中方法里面的三个参数,分别代表:图片格式、压缩比例、字节流(节数组输出流在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中)。
其实这个时候我想到了一个问题,当压缩比例为100的时候,也就是没有进行压缩,那这一步的代码意义何在呢? 经过研究下面源码:
/**
* Write a compressed version of the bitmap to the specified outputstream.
* If this returns true, the bitmap can be reconstructed by passing a
* corresponding inputstream to BitmapFactory.decodeStream(). Note: not
* all Formats support all bitmap configs directly, so it is possible that
* the returned bitmap from BitmapFactory could be in a different bitdepth,
* and/or may have lost per-pixel alpha (e.g. JPEG only supports opaque
* pixels).
*
* @param format The format of the compressed image
* @param quality Hint to the compressor, 0-100. 0 meaning compress for
* small size, 100 meaning compress for max quality. Some
* formats, like PNG which is lossless, will ignore the
* quality setting
* @param stream The outputstream to write the compressed data.
* @return true if successfully compressed to the specified stream.
*/
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");
}
StrictMode.noteSlowCall("Compression of a bitmap is slow");
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "Bitmap.compress");
boolean result = nativeCompress(mNativePtr, format.nativeInt,
quality, stream, new byte[WORKING_COMPRESS_STORAGE]);
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
return result;
}
其中最重要的一句代码是这个:
nativeCompress(mNativePtr, format.nativeInt,
quality, stream, new byte[WORKING_COMPRESS_STORAGE]);
再深入发现调用的是这个方法:
private static native boolean nativeCompress(long nativeBitmap, int format,
int quality, OutputStream stream,
byte[] tempStorage);
我们最后发现它最后是调用到了JNI,直接使用.cpp方法里面的C++函数了。这个大家有兴趣可以去参考这篇文章:Bitmap压缩原理解析与Android 7.0之前通过NDK使用libjpeg库高质量压缩图片。 所以回到我们的第一个源码那,看注释,第一句是 Write a compressed version of the bitmap to the specified outputstream. 意思就是将压缩后的Bitmap写入到指定的输出流里面。这样我就弄懂了,其实这个压缩如果是100的话,其最终的目的也就是去将bitmap写入到流里面。流(Stream)二进制数据流,内存中电信号转换,写入到磁盘的存储颗粒上,记录电信号。
二进制流转换为Byte[]数组
- 这个就涉及到了编码的知识了。在最早期的时候,大家的编码方式都使用的是ASCII码的编码方式,而我们要知道的是在计算机中,所有的信息都是以0和1来进行存储的,指定的二进制代表了字母、标点符号、控制字符。譬如存储在计算机上的01000001代表了大写字母A。ASCII码一共有256个,但是常用的也就前128个,标准ASCII码(0~127)。
- 简而言之,对于字符而言,直接用ASCII码对应的数字表示,ASCII码就是用来将字符存储到计算机的,例如“3” 的ASCII码的十进制为51 ,二进制为 0011 0011 。则是将二进制的值存储到了计算机。
- 那么,由此延伸的一个问题是:当本身就是十进制的51,其二进制也为0011 0011 ,存储进了计算机。那么在计算机中的二进制 0011 0011,表现到内存中到底是字符还是数字呢? 我自我理解是计算机中既然存储了0011 0011 那么在内存中表示出来的值,只与其定义的数有关,如果你定义的是int 那么就是51;如果你定义的是String 那么就是“3”。
- 而Byte里面存储为8bit,可以存储所有ASCII所有字符(这是它包含8bits的初衷)。也就是说1Byte里面有8bit的二进制,那么将二进制流每8bit存储于一个Byte,就可以得到最后转换的Byte[]数组了。
Byte[]数组转Base64编码
什么是Base64编码
为什么要进行Base64编码
因为Http协议(超文本传输协议)中,Byte里面的二进制可能为0000 0001B,如果直接转换为String的话,明显是不可能的,因为这个不是可打印字符,那么传输过程中可能就会出现乱码,而Base64也就是64个可打印的字符串。
Value | Char | Value | Char | Value | Char | Value | Char |
---|---|---|---|---|---|---|---|
0 | A | 16 | Q | 32 | g | 48 | w |
1 | B | 17 | R | 33 | h | 49 | x |
2 | C | 18 | S | 34 | i | 50 | y |
3 | D | 19 | T | 35 | j | 51 | z |
4 | E | 20 | U | 36 | k | 52 | 0 |
5 | F | 21 | V | 37 | l | 53 | 1 |
6 | G | 22 | W | 38 | m | 54 | 2 |
7 | H | 23 | X | 39 | n | 55 | 3 |
8 | I | 24 | Y | 40 | o | 56 | 4 |
9 | J | 25 | Z | 41 | p | 57 | 5 |
10 | K | 26 | a | 42 | q | 58 | 6 |
11 | L | 27 | b | 43 | r | 59 | 7 |
12 | M | 28 | c | 44 | s | 60 | 8 |
13 | N | 29 | d | 45 | t | 61 | 9 |
14 | O | 30 | e | 46 | u | 62 | + |
15 | P | 31 | f | 47 | v | 63 | / |