Android Bitmap
I Definition of Bitmap
Bitmap is one of the most important classes of image processing in Android system. It can be used to obtain the image file information, cut, rotate and zoom the image, and save the image file in a specified format.
There are two main uses of Bitmap:
- 1. Set the background for ImageView
- 2. Use as canvas
Corresponding to the following two methods
imageView.setImageBitmap(Bitmap bm); Canvas canvas = new Canvas(Bitmap bm)
II Format of Bitmap
We know that Bitmap is a Bitmap, which is composed of pixels, which involves two problems,
- First: how to store each pixel?
- Second: how to compress pixels?
There are two internal enumeration classes in Bitmap: config and CompressFormat. Config is used to set color configuration information and CompressFormat is used to set compression mode
2.1 storage format
2.2 compressed format
We might as well calculate that if a Bitmap image with the same size as the mobile phone screen uses ARGB_ How much memory is required for 8888 format storage!
According to the screen size of 1024 * 768, each pixel needs 32 bits, that is, 4 bytes,
result = 1024*768*32B=25165824B=24MB
A Bitmap picture the size of a mobile phone screen should be 24M? It's not surprising that my app has been flashing back, but dozens of them have been created with the for loop and used in the sliding list.
Therefore, we must compress the image. The compression format uses the enumeration class bitmap CompressFormat
Bitmap.CompressFormat.JPEG: JPEG compression algorithm is a lossy compression format, which will change the original image quality in the compression process. The worse the image quality, the greater the damage to the original image quality, but the resulting file is relatively small, and JPEG does not support transparency. When transparency pixels are encountered, it will be filled with black background.
Bitmap.CompressFormat.PNG: using PNG algorithm, it is a lossless compression format that supports transparency.
Bitmap.CompressFormat.WEBP:WEBP is a picture file format that provides both lossy compression and lossless compression. When 14 < = API < = 17, WEBP is a lossy compression format and does not support transparency. After api18, WEBP is a lossless compression format and supports transparency. When lossy compression, under the same quality, the picture volume of WEBP format is 40% smaller than JPEG, But the encoding time is 8 times longer than JPEG. In lossless compression, lossless WEBP images are 26% smaller than PNG compression, but the compression time of WEBP is 5 times that of PNG format.
III Bitmap creation method
How do we create a Bitamap object? Google offers us two ways:
- 1. Static method of Bitmap createBitmap(XX)
- 2. decodeXX series static method of BitmapFactory
3.1 BitmapFactory
BitmapFactory provides a variety of static methods for creating bitmap s
decodeFile, decodeResource, decodeStream and decodebyte array are used to load a Bitmap object from the file system, resource, input stream and byte array respectively. The decodeFile and decodeResource indirectly call the decodeStream method. These four types of methods are finally implemented at the bottom of Android and correspond to several native methods of BitmapFactory class.
3.1.1, Bitmap.Options class
How to load bitmap efficiently?
Via bitmapfactory Options loads the reduced image according to a certain sampling rate and displays the reduced image in ImageView, which will reduce the memory occupation, avoid OOM to a certain extent and improve the performance of Bitmap loading.
Interpretation of sampling rate:
BitmapFactory supports all four methods of loading pictures provided by BitmapFactory Options parameter
Via bitmapfactory Options to zoom the picture, mainly using the inSampleSize parameter, that is, the sampling rate.
- When inSampleSize is 1, the size of the sampled picture is the original size of the picture;
- When inSampleSize is greater than 1, such as 2, the width / height of the sampled image is 1 / 2 of the size of the original image, the number of pixels is 1 / 4 of the original image, and its memory size is also 1 / 4 of the original image.
Take one × For 1024 pixel pictures, if they are stored in ARGB8888 format, the memory occupied by them is 1024 × one thousand and twenty-four × 4, that is, 4MB. If inSampleSize is 2, the memory occupation of the sampled picture is only 512 × five hundred and twelve × 4, i.e. 1MB.
The sampling rate acts on the width / height at the same time, which will cause the scaled picture size to decrease in the form of the second power of the sampling rate, that is, the scaling scale is 1 / (the second power of insamplesize)
- For example, if inSampleSize is 4, the scale is 1 / 16.
- There is a special case, that is, when inSampleSize is less than 1, its effect is equivalent to 1, that is, there is no scaling effect.
Parameter Description:
Examples
try { FileInputStream fis = new FileInputStream(filePath); BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; // Setting inJustDecodeBounds to true and then using methods such as decodeFile() will not really allocate space, //That is, the decoded Bitmap is null, but the width and height of the original picture can be calculated, that is, options Outwidth and options outHeight BitmapFactory.decodeFileDescriptor(fis.getFD(), null, options); float srcWidth = options.outWidth; float srcHeight = options.outHeight; int inSampleSize = 1; if (srcHeight > height || srcWidth > width) { if (srcWidth > srcHeight) { inSampleSize = Math.round(srcHeight / height); } else { inSampleSize = Math.round(srcWidth / width); } } options.inJustDecodeBounds = false; options.inSampleSize = inSampleSize; return BitmapFactory.decodeFileDescriptor(fis.getFD(), null, options); } catch (Exception e) { e.printStackTrace(); }
Process Description:
- (1) BitmapFactory Set the inJustDecodeBounds parameter of options to true and load the picture. When this parameter is true, BitmapFactory will only parse the original width and height information of the picture and will not actually load the picture. At the same time, the obtained information and the location of the picture are related to the device where the program runs
- (2) From bitmapfactory Take out the original width and height information of the picture in options, which correspond to the outWidth and outHeight parameters.
- (3) Calculate the sampling rate inSampleSize according to the rules of the sampling rate and the required size of the target View
- (4) Bitmapfactory Set the inJustDecodeBounds parameter of options to false, and then reload the picture.
3.2 Bitmap static method
//Width and height are length and width units Px, and config is the storage format static Bitmap createBitmap(int width , int height Bitmap.Config config) // Create as like as two peas of an image. static Bitmap createBitmap(Bitmap bm) //Intercept a bitmap. The starting point is (x, y). Width and height correspond to width and height respectively static Bitmap createBitmap(Bitmap bm,int x,int y,int width,int height) //There are two more parameters than the above clipping function. Matrix: Add matrix to the clipped image. boolean filter: whether to add filtering effect to the image static Bitmap createBitmap(Bitmap bm,int x,int y,int width,int height,Matrix m,boolean filter); //Used to scale bitmap. Dstwidth and dstHeight are the target width and height respectively createScaledBitmap(Bitmap bm,int dstWidth,int dstHeight,boolean filter)
These methods can be roughly divided into three categories:
- 1. Create a new Bitmap based on an existing Bitmap
/** * Returns an immutable subset of the original Bitmap in the form of a matrix. The new Bitmap may return the original Bitmap, or it may be copied. * The new Bitmap has the same density and color space as the original Bitmap; * * @param source Original Bitmap * @param x The starting coordinate in the x direction of the original Bitmap (you may only need a part in the x direction of the original Bitmap) * @param y The starting coordinate of the y direction in the original Bitmap (you may only need a part of the y direction of the original Bitmap) * @param width The width of the Bitmap (px) needs to be returned (an error will be reported if it exceeds the original Bitmap width) * @param height The height (px) of the Bitmap needs to be returned (an error will be reported if it exceeds the original Bitmap height) * @param m Matrix Type, indicating the transformation operation to be done * @param filter Whether filtering is required. Only matrix transformation, not only translation, is effective */ public static Bitmap createBitmap(@NonNull Bitmap source, int x, int y, int width, int height, @Nullable Matrix m, boolean filter)
- 2. Create an empty Bitmap from an array of pixels
/** * * Returns an immutable bitmap with a specified width and height, each pixel value set to the corresponding value in the colors array. * Its initial density is determined by the given DisplayMetrics. The newly created bitmap is in the sRGB color space. * @param display Displays the metrics that will display this bitmap * @param colors sRGB array used to initialize pixels * @param offset The number of values to skip before the first color in the color array * @param stride Number of colors in the array between rows (must be > = width or < = - width) * @param width Width of bitmap * @param height The height of the bitmap * @param config The bitmap configuration to create. If the configuration does not support alpha per pixel (for example, RGB_565), * Then the alpha byte in colors [] will be ignored (assuming FF) */ public static Bitmap createBitmap(@NonNull DisplayMetrics display, @NonNull @ColorInt int[] colors, int offset, int stride, int width, int height, @NonNull Config config)
- 3. Create a scaled Bitmap
/** * Scale the Bitmap to a new Bitmap with wide dstWidth and high dstHeight */ public static Bitmap createScaledBitmap(@NonNull Bitmap src, int dstWidth, int dstHeight,boolean filter)
3.3 summary of creating Bitmap
- 1. BitmapFactory and bitmap can be used to load images Create series methods
- 2. You can zoom the picture, obtain the picture information, configure the zoom ratio and other functions through Options
- 3. If you need to crop or zoom the picture, you can only use the create series functions
- 4. Pay attention to loading and creating bitmap events, and catch OOM exceptions through try catch
IV Common functions
4.1 function and its parameters
copy(Config config,boolean isMutable) //Create a copy from the original image, but you can specify the pixel storage format of the copy //Parameter meaning. // config: the storage format of pixels in memory, but you can specify the pixel storage format of the copy // boolean isMutable: can the pixel value of the new bitmap be modified extractAlpha() //The main function is to obtain the Alpha value from the bitmap and generate an image with only Alpha value. The storage format is Alpha_ eight getByteCount()//Gets the number of bytes of the bitmap recycle()://Unused bitmap s must be recycled in time to avoid causing oom isRecycled()//Judge whether the bitmap is recycled. If it is recycled and cannot be used, it will cause crash
Comprehensive case demonstration
String items[] = {"copy","extractAlpha 1","extractAlpha 2","bitmap size","recycle","isRecycled()"}; ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item,items); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner.setAdapter(adapter); spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { switch (position){ case 0: //copy Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.photo); Bitmap copy = bm.copy(Bitmap.Config.ARGB_8888, true); imageView.setImageBitmap(copy); bm.recycle(); break; case 1: //extractAlpha without parameters Bitmap bp = BitmapFactory.decodeResource(getResources(), R.drawable.photo); Bitmap alpha = bp.extractAlpha(); imageView.setImageBitmap(alpha); bp.recycle(); break; case 2: //extractAlpha with parameters Bitmap bp1 = BitmapFactory.decodeResource(getResources(), R.drawable.photo); Paint paint = new Paint(); BlurMaskFilter blurMaskFilter = new BlurMaskFilter(6, BlurMaskFilter.Blur.NORMAL); paint.setMaskFilter(blurMaskFilter); int[] offsetXY = new int[2]; Bitmap alpha1 = bp1.extractAlpha(paint, offsetXY); imageView.setImageBitmap(alpha1); break; case 3: //Get bitmap size Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.photo); Toast.makeText(getApplicationContext(), "Picture size:"+b.getByteCount()+"byte", Toast.LENGTH_SHORT).show(); break; case 4: //Recycling bitmap Bitmap b1 = BitmapFactory.decodeResource(getResources(), R.drawable.photo); b1.recycle(); if(b1.isRecycled()){ Toast.makeText(getApplicationContext(), "Has been recycled", Toast.LENGTH_SHORT).show(); } //isRecycled() determines whether it is recycled break; } } @Override public void onNothingSelected(AdapterView<?> parent) { } });
4.2 common operations
1. Crop, scale, rotate, move
Matrix matrix = new Matrix(); // zoom matrix.postScale(0.8f, 0.9f); // Left rotation, the parameter is regular right rotation matrix.postRotate(-45); // Pan, modify the set again based on the last modification, and each operation is the latest, which will overwrite the last operation matrix.postTranslate(100, 80); // Crop and do the above Bitmap bitmap = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
2. Save and release
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test); File file = new File(getFilesDir(),"test.jpg"); if(file.exists()){ file.delete(); } try { FileOutputStream outputStream=new FileOutputStream(file); bitmap.compress(Bitmap.CompressFormat.JPEG,90,outputStream); outputStream.flush(); outputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } //Releasing the resources of bitmap is an irreversible operation bitmap.recycle();
3. Picture compression
public static Bitmap compressImage(Bitmap image) { if (image == null) { return null; } ByteArrayOutputStream baos = null; try { baos = new ByteArrayOutputStream(); image.compress(Bitmap.CompressFormat.JPEG, 100, baos); byte[] bytes = baos.toByteArray(); ByteArrayInputStream isBm = new ByteArrayInputStream(bytes); Bitmap bitmap = BitmapFactory.decodeStream(isBm); return bitmap; } catch (OutOfMemoryError e) { e.printStackTrace(); } finally { try { if (baos != null) { baos.close(); } } catch (IOException e) { e.printStackTrace(); } } return null; }
V common problem
5.1 relationship between bitmap and Canvas, View and Drawable
5.2 how does Bitmap cause memory overflow?
Personally, I think that Bitmap is easy to cause memory overflow because the Bitmap is large and the ARGB of a screen size_ There are 24M pictures in 8888 storage format. If there are several pictures of this magnitude in memory and they are not recycled in time, it will easily cause OOM
5.3 how to solve or avoid Bitmap memory overflow?
- 1. We can compress bitmaps by PNG, JPEG and webp
- 2. The unused Bitmap must be recycled in time.
- 3. When creating Bitmap, use the try catch step to make the program more robust. Even if OOM occurs, it will not flash back, resulting in a bad use experience
5.4 conversion between bitmap and Drawable
5.4.1 converting drawable to Bitmap
public static Bitmap drawableToBitmap(Drawable drawable) { // Take the length and width of drawable int w = drawable.getIntrinsicWidth(); int h = drawable.getIntrinsicHeight(); // Take the color format of drawable Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; // Establish corresponding bitmap Bitmap bitmap = Bitmap.createBitmap(w, h, config); // Create a canvas corresponding to bitmap Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, w, h); // Draw drawable content onto canvas drawable.draw(canvas); return bitmap; }
5.4.2 converting bitmap to Drawable
Bitmap bm=Bitmap.createBitmap(xxx); BitmapDrawable bd= new BitmapDrawable(getResource(), bm);
reference resources
1,Little things about Bitmap image resource optimization
2,The most detailed complete solution in the history of Bitmap
3,Detailed explanation of Android Bitmap
4,How is the memory size of Android Bitmap calculated?
5,Android Bitmap explanation: everything you need to know about Bitamp