How to load Bitmap efficiently with KJFrameForAndroid Framework

  • 2020-06-03 08:18:49
  • OfStack

When we write Android, we use a lot of pictures. Then for the image compression processing is essential. Why do you compress it? I don't want to this problem in stressed, at the time of initial learning Android sure everybody will know so one reason: we write applications are a maximum memory limit, including JAVA program and C (NDK calls) to share the 1 piece of memory size, the program takes up too much memory is prone to OOM (OutOfMemory) anomalies. As for the maximum amount of memory, we can verify 1 by calling the Runtime.getRuntime ().maxMemory () method.

This is due to the limitation of memory size, which is the key reason (in fact, I think a 1M image and a 10k image must load at different speeds). If your control is only 40 by 40 pixels in size, just to display a thumbnail, it's not worth loading a 1024 by 768 pixel image completely into memory, so we compress the image.

The BitmapFactory class provides multiple methods (decodeByteArray, decodeFile, decodeResource, etc.) for creating Bitmap objects, and we can choose the appropriate method based on the source of the image. These methods, however, allocate memory for bitmap that has already been read, in which case a very large image will cause OOM to appear. To do this, each parse method provides an BitmapFactory.Options parameter, which can be set to true to disable the parse method from allocating memory to bitmap, but the return value of BitmapFactory is null instead of an Bitmap object. Although Bitmap is null, the outWidth, outHeight, and outMimeType attributes of BitmapFactory. Options are assigned. Using this technique allows you to get the length, width and type of an image before you load it, and compress the image as you see fit.

BitmapFactory.Options options = new BitmapFactory.Options(); 
 options.inJustDecodeBounds = true; 
 BitmapFactory.decodeFile(pathName, options);
 int h = options.outHeight; 
 int w = options.outWidth; 
 String type = options.outMimeType;

Now that you know the width and height of the image, how do you compress it? BitmapFactory. Options has 1 inSampleSize attribute, and this int value means that the original width and height of the image change to 1/inSampleSize times. If the original image is 1024*768, inSampleSize=2, then the compressed image becomes 512*384. Finally, set BitmapFactory.Options to the appropriate VALUE of inSampleSize, and remember to set inJustDecodeBounds back to false, and call once BitmapFactory corresponding method to create Bitmap, and pass Options, you can get the compressed image.

Here is one excerpt from the open source Android application development framework KJFrameForAndroid

 *  Image compression processing (use Options The method) 
 * @ Method of use   The first thing you have to do is Options the inJustDecodeBounds Properties are set to true . BitmapFactory.decode1 Images. 
 *   then Options Along with the desired width and height 1 Start and pass to this method. 
 *   The argument is then called using the return value of this method BitmapFactory.decode Create an image. 
 * @explain BitmapFactory create bitmap Will try to build for what is already built bitmap Allocate memory 
 *  ", which can easily lead to OOM Appear. For each 1 Each of the creation methods is provided 1 An optional Options parameter 
 *  Of this parameter inJustDecodeBounds Properties are set to true You can disable parsing methods bitmap Allocate memory 
 *  The return value is no longer 1 a Bitmap Object,   but null . although Bitmap is null Now, but Options the outWidth , 
 * outHeight and outMimeType Properties are assigned. 
 * @param reqWidth
 *   The target width 
 * @param reqHeight
 *   Target height 
  public static BitmapFactory.Options calculateInSampleSize(
   final BitmapFactory.Options options, int reqWidth, int reqHeight) {
   //  Height and width of the source image 
   final int height = options.outHeight;
   final int width = options.outWidth;
   int inSampleSize = 1;
   if (height > reqHeight || width > reqWidth) {
   //  Calculate the ratio of actual width and height to target width and height 
   final int heightRatio = Math.round((float) height
    / (float) reqHeight);
   final int widthRatio = Math.round((float) width / (float) reqWidth);
   //  Choose the minimum ratio of width and high school as inSampleSize To ensure the width and height of the final image 
   // 1 Must be greater than or equal to the width and height of the target. 
   inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
   //  Set compression ratio 
   options.inSampleSize = inSampleSize;
   options.inJustDecodeBounds = false;
   return options;

The above method is suitable for use in reading a unknown source images, because you don't know the size of the unknown source images, there is one kind of method is used in load memory images, to load the memory images already do after compression to save to a local, which can turn 1 original 1 M size pictures to 1 10 K pictures.

The core idea of this method was that the images into one output stream, and record the output stream byte array size, by calling the bitmap compress method of the object do 1 time for image compression and formatting, and byte array size and it is expected that the aim of compression size comparison, it is concluded that the compression ratio, and call the Bitmap scaling method, scaling to calculate the compression ratio, compression is obtained after the method.

Let's move on to another piece of code in the KJFrameForAndroid framework:

  *  Image compression method :(use compress The method) 
  * @explain  if bitmap Its size is less than maxSize , do not make processing 
  * @param bitmap
  *   The image to be compressed 
  * @param maxSize
  *   The size of the compressed unit kb
 public static void imageZoom(Bitmap bitmap, double maxSize) {
  //  will bitmap Put it in an array to get bitmap Size (larger than the original file actually read) 
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  //  Format, quality, output stream 
  bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
  byte[] b = baos.toByteArray();
  //  Replace bytes with KB
  double mid = b.length / 1024;
  //  To obtain bitmap The size of the   Is the maximum allowed size 
  double i = mid / maxSize;
  //  judge bitmap Whether the occupied space is greater than the maximum allowed space   If greater than, compress   Less than does not compress 
  if (i > 1) {
   //  Zoom pictures   We use square root here   Compress the bandwidth and height by a factor of square root 
   //  (Keep the width and height constant, and the maximum space occupied is reached after scaling) 
   bitmap = scale(bitmap, bitmap.getWidth() / Math.sqrt(i),
     bitmap.getHeight() / Math.sqrt(i));
  *  The zoom method of the image 
  * @param src
  *   : Source photo resources 
  * @param newWidth
  *   : Width after scaling 
  * @param newHeight
  *   : Height after scaling 
 public static Bitmap scale(Bitmap src, double newWidth, double newHeight) {
  //  record src The wide high 
  float width = src.getWidth();
  float height = src.getHeight();
  //  create 1 a matrix The container 
  Matrix matrix = new Matrix();
  //  Calculate the scale 
  float scaleWidth = ((float) newWidth) / width;
  float scaleHeight = ((float) newHeight) / height;
  //  Began to zoom 
  matrix.postScale(scaleWidth, scaleHeight);
  //  Create the zoomed image 
  return Bitmap.createBitmap(src, 0, 0, (int) width, (int) height,
    matrix, true);

Also enclosed KJFrameForAndroid framework project address: https: / / github com/kymjs/KJFrameForAndroid

Or standby address http: / / git oschina. net/kymjs/KJFrameForAndroid

Have the friend of this respect need to be able to download next oneself research

Related articles: