Home>

Foreword:

I'm going to study the image cache framework recently.Based on this idea, I still understand the basics of image caching first.Today I will focus on the two classes of bitmap and bitmapfactory.

bitmap:Bitmap is one of the most important classes of image processing in the android system.Use it to get image file information,Cut, rotate, and zoom the image.And you can save the image file in a specified format.

Important function

•public void recycle () //recycle the memory space occupied by the bitmap,Mark the bitmap as dead

•public final boolean isrecycled () //Determine if the bitmap memory has been released

•public final int getwidth () //Get the width of the bitmap

•public final int getheight () //Get the height of the bitmap

•public final boolean ismutable () //Can the picture be modified?

•public int getscaledwidth (canvas canvas) //Get the width of the image after the specified density conversion

•public int getscaledheight (canvas canvas) //Get the height of the image after the specified density conversion

•public boolean compress (compressformat format, int quality, outputstream stream) //According to the specified picture format and picture quality,Converts a picture into an output stream.

format:bitmap.compressformat.png or bitmap.compressformat.jpeg

quality:picture quality, 0-100.0 means the lowest picture quality compression,100 is compressed at the highest quality.For pictures in lossless formats such as png,This setting is ignored.

•public static bitmap createbitmap (bitmap src) //Generate a new image with src as the original image

•public static bitmap createscaledbitmap (bitmap src, int dstwidth, int dstheight, boolean filter) //Use src as the original image to create a new image,Specify the height and width of the new image and whether it is variable.

•public static bitmap createbitmap (int width, int height, config config)-create a bitmap of the specified format and size

•public static bitmap createbitmap (bitmap source, int x, int y, int width, int height) creates a new image with source as the original image,Specify the starting coordinates and the height and width of the new image.

bitmapfactory factory class:option parameter class:•public boolean injustdecodebounds //If set to true, do not get pictures,Does not allocate memory,But it returns the height and width information of the picture.

•public int insamplesize //multiples of picture scaling

•public int outwidth //Get the width value of the picture

•public int outheight ///Get the height value of the picture

•public int indensity //pixel compression ratio for bitmaps

•public int intargetdensity //pixel compression ratio for the target bitmap (bitmap to be generated)

•public byte [] intempstorage //Create a temporary file,Store pictures

•public boolean inscaled //set image compression when true,From indensity to intargetdensity

•public boolean indither //If true, the decoder attempts to jitter decode

•public bitmap.config inpreferredconfig //Set the decoder

•public string outmimetype //Set the decoded image

•public boolean inpurgeable //whether the memory space for storing pixels can be recycled when the system memory is insufficient

•public boolean ininputshareable //takes effect only when inpurgeable is true,Is it possible to share an inputstream

•public boolean inpreferqualityoverspeed //If true, the bitmap quality is guaranteed first, followed by the decoding speed

•public boolean inmutable //configure whether the bitmap can be changed,For example:add a line segment every few pixels on the bitmap

•public int inscreendensity //pixel density of the current screen

Factory method:•public static bitmap decodefile (string pathname, options opts) //Read pictures from file

•public static bitmap decodefile (string pathname)

•public static bitmap decodestream (inputstream is) //Read image from input stream

•public static bitmap decodestream (inputstream is, rect outpadding, options opts)

•public static bitmap decoderesource (resources res, int id) //Read image from resource file

•public static bitmap decoderesource (resources res, int id, options opts)

•public static bitmap decodebytearray (byte [] data, int offset, int length) //Read the picture from the array

•public static bitmap decodebytearray (byte [] data, int offset, int length, options opts)

•public static bitmap decodefiledescriptor (filedescriptor fd) //Read a file from a file. Unlike decodefile, this directly calls the jni function for reading. It is more efficient.

•public static bitmap decodefiledescriptor (filedescriptor fd, rect outpadding, options opts)

bitmap.config inpreferredconfig:Enumeration variable (The higher the bitmap, the more color information it can store.The more realistic the image,Occupies more memory)

•public static final bitmap.config alpha_8 //represents 8-bit alpha bitmap, each pixel occupies 1byte of memory

•public static final bitmap.config argb_4444 //represents a 16-bit argb bitmap, each pixel occupies 2byte of memory

•public static final bitmap.config argb_8888 //represents 32-bit argb bitmap each pixel occupies 4byte memory

•public static final bitmap.config rgb_565 //represents 8-bit rgb bitmap. Each pixel occupies 2byte memory

The memory occupied by a picture (bitmap) in Android is mainly related to the following factors:picture length,Image width,The number of bytes per unit pixel.

Memory occupied by a picture (bitmap)=picture length * picture width * number of bytes occupied by a unit pixel

Image reading example:

1.) Read from file one

/**
  * Get zoomed local image
  *
  * @param filepath file path
  * @param width
  * @param height high
  * @return
  * /
 public static bitmap readbitmapfromfile (string filepath, int width, int height) {
  bitmapfactory.options options=new bitmapfactory.options ();
  options.injustdecodebounds=true;
  bitmapfactory.decodefile (filepath, 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.decodefile (filepath, options);
 }

2.) Method 2 is more efficient than reading from file 1.

/**
  * Get zoomed local image
  *
  * @param filepath file path
  * @param width
  * @param height high
  * @return
  * /
 public static bitmap readbitmapfromfiledescriptor (string filepath, int width, int height) {
  try {
   fileinputstream fis=new fileinputstream (filepath);
   bitmapfactory.options options=new bitmapfactory.options ();
   options.injustdecodebounds=true;
   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 ex) {
  }
  return null;
 }

The test also generated 10 pictures. The two methods took a long time to compare. The CPU usage and memory consumption were almost the same. The second method is more efficient, so it is recommended to use the second method first.

 start=system.currenttimemillis ();
  for (int i=0;i<testmaxcount;i ++) {
   bitmaputils.readbitmapfromfile (filepath, 400, 400);
  }
  end=system.currenttimemillis ();
  log.e (tag, "bitmapfactory decodefile--time->" + (end-start));
  start=system.currenttimemillis ();
  for (int i=0;i<testmaxcount;i ++) {
   bitmaputils.readbitmapfromfiledescriptor (filepath, 400, 400);
  }
  end=system.currenttimemillis ();
  log.e (tag, "bitmapfactory decodefiledescriptor--time->" + (end-start));

3.) Read the file from the input stream

/**
  * Get zoomed local image
  *
  * @param ins input stream
  * @param width
  * @param height high
  * @return
  * /
 public static bitmap readbitmapfrominputstream (inputstream ins, int width, int height) {
  bitmapfactory.options options=new bitmapfactory.options ();
  options.injustdecodebounds=true;
  bitmapfactory.decodestream (ins, 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.decodestream (ins, null, options);
 }

4.) Read files from resource files

public static bitmap readbitmapfromresource (resources resources, int resourcesid, int width, int height) {
  bitmapfactory.options options=new bitmapfactory.options ();
  options.injustdecodebounds=true;
  bitmapfactory.decoderesource (resources, resourcesid, 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.decoderesource (resources, resourcesid, options);
 }

This method consumes considerable memory. It is recommended to use decodestream instead of decoderesource.

public static bitmap readbitmapfromresource (resources resources, int resourcesid, int width, int height) {
  inputstream ins=resources.openrawresource (resourcesid);
  bitmapfactory.options options=new bitmapfactory.options ();
  options.injustdecodebounds=true;
  bitmapfactory.decodestream (ins, 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.decodestream (ins, null, options);
 }

Comparison of decodestream and decoderesource memory usage:

start=system.currenttimemillis ();
  for (int i=0;i<testmaxcount;i ++) {
   bitmaputils.readbitmapfromresource (getresources (), r.mipmap.ic_app_center_banner, 400, 400);
   log.e (tag, "bitmapfactory decoderesource--num->" + i);
  }
  end=system.currenttimemillis ();
  log.e (tag, "bitmapfactory decoderesource--time->" + (end-start));
  start=system.currenttimemillis ();
  for (int i=0;i<testmaxcount;i ++) {
   bitmaputils.readbitmapfromresource1 (getresources (), r.mipmap.ic_app_center_banner, 400, 400);
   log.e (tag, "bitmapfactory decodestream--num->" + i);
  }
  end=system.currenttimemillis ();
  log.e (tag, "bitmapfactory decodestream--time->" + (end-start));

The image loaded by bitmapfactory.decoderesource may be scaled.The scaling is currently done on the java layer, which is relatively inefficient.And need to consume the memory of the java layer.So if you use this interface heavily to load images,Easy to cause oom error.

bitmapfactory.decodestream does not scale the loaded image,In contrast, it takes up less memory,higher efficiency.

Both interfaces are useful,If performance requirements are high,Decodestream should be used;if performance is not critical,And need the image adaptive zoom function that comes with android,You can use decoderesource.

5.) Reading pictures from binary data

public static bitmap readbitmapfrombytearray (byte [] data, int width, int height) {
  bitmapfactory.options options=new bitmapfactory.options ();
  options.injustdecodebounds=true;
  bitmapfactory.decodebytearray (data, 0, data.length, 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.decodebytearray (data, 0, data.length, options);
 }

6.) Reading pictures from assets files

/**
  * Get zoomed local image
  *
  * @param filepath file path
  * @return
  * /
 public static bitmap readbitmapfromassetsfile (context context, string filepath) {
  bitmap image=null;
  assetmanager am=context.getresources (). getassets ();
  try {
   inputstream is=am.open (filepath);
   image=bitmapfactory.decodestream (is);
   is.close ();
  } catch (ioexception e) {
   e.printstacktrace ();
  }
  return image;
 }

Picture save file:

public static void writebitmaptofile (string filepath, bitmap b, int quality) {
  try {
   file desfile=new file (filepath);
   fileoutputstream fos=new fileoutputstream (desfile);
   bufferedoutputstream bos=new bufferedoutputstream (fos);
   b.compress (bitmap.compressformat.jpeg, quality, bos);
   bos.flush ();
   bos.close ();
  } catch (ioexception e) {
   e.printstacktrace ();
  }
 }

Picture compression:

private 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) {
  } finally {
   try {
    if (baos!=null) {
     baos.close ();
    }
   } catch (ioexception e) {
   }
  }
  return null;
 }

Picture zoom:

/**
  * Generate an image based on scale
  *
  * @param bitmap
  * @param scale proportional scaling value
  * @return
  * /
 public static bitmap bitmapscale (bitmap bitmap, float scale) {
  matrix matrix=new matrix ();
  matrix.postscale (scale, scale);//scale of length and width zoom
  bitmap resizebmp=bitmap.createbitmap (bitmap, 0, 0, bitmap.getwidth (), bitmap.getheight (), matrix, true);
  return resizebmp;
 }

Get the image rotation angle:

/**
  * Read the rotation angle in photo exif information
  *
  * @param path photo path
  * @returnangular
  * /
 private static int readpicturedegree (string path) {
  if (textutils.isempty (path)) {
   return 0;
  }
  int degree=0;
  try {
   exifinterface exifinterface=new exifinterface (path);
   int orientation=exifinterface.getattributeint (exifinterface.tag_orientation, exifinterface.orientation_normal);
   switch (orientation) {
    case exifinterface.orientation_rotate_90:
     degree=90;
     break;
    case exifinterface.orientation_rotate_180:
     degree=180;
     break;
    case exifinterface.orientation_rotate_270:
     degree=270;
     break;
   }
  } catch (exception e) {
  }
  return degree;
 }
</pre>
<strong>
</strong>
</div>
<p>
<strong>
Picture rotation angle:
</strong>
</p>
<div>
<pre>
  private static bitmap rotatebitmap (bitmap b, float rotatedegree) {
    if (b == null) {
      return null;
    }
    matrix matrix=new matrix ();
    matrix.postrotate (rotatedegree);
    bitmap rotabitmap=bitmap.createbitmap (b, 0, 0, b.getwidth (), b.getheight (), matrix, true);
    return rotabitmap;
  }

Picture to binary:

public byte [] bitmap2bytes (bitmap bm) {
    bytearrayoutputstream baos=new bytearrayoutputstream ();
    bm.compress (bitmap.compressformat.png, 100, baos);
    return baos.tobytearray ();
  }

bitmap to drawable

public static drawable bitmaptodrawable (resources resources, bitmap bm) {
    drawable drawable=new bitmapdrawable (resources, bm);
    return drawable;
  }

drawable to bitmap

public static bitmap drawabletobitmap (drawable drawable) {
    bitmap bitmap=bitmap.createbitmap (drawable.getintrinsicwidth (), drawable.getintrinsicheight (), drawable.getopacity ()!=pixelformat.opaque)
    canvas canvas=new canvas (bitmap);
    drawable.setbounds (0, 0, drawable.getintrinsicwidth (), drawable.getintrinsicheight ());
    drawable.draw (canvas);
    return bitmap;
  }

Discussion on drawable, bitmap memory occupationAnyone who has used afinal and xutils before is familiar with both frameworks,Both come from the same person,xutils is an upgraded version of afina,Afinal uses a bitmap for the image memory cache. Why did xutils change the memory cache object to drawable?

Write a test program:

list<bitmap>bitmaps=new arraylist<>();
    start=system.currenttimemillis ();
    for (int i=0;i<testmaxcount;i ++) {
      bitmap bitmap=bitmaputils.readbitmap (this, r.mipmap.ic_app_center_banner);
      bitmaps.add (bitmap);
      log.e (tag, "bitmapfactory bitmap--num->" + i);
    }
    end=system.currenttimemillis ();
    log.e (tag, "bitmapfactory bitmap--time->" + (end-start));
    list<drawable>drawables=new arraylist<>();
    start=system.currenttimemillis ();
    for (int i=0;i<testmaxcount;i ++) {
      drawable drawable=getresources (). getdrawable (r.mipmap.ic_app_center_banner);
      drawables.add (drawable);
      log.e (tag, "bitmapfactory drawable--num->" + i);
    }
    end=system.currenttimemillis ();
    log.e (tag, "bitmapfactory drawable--time->" + (end-start));

Test data 1000 the same picture

Tests show that drawable has a large memory footprint advantage over bitmap.This is why the mainstream image cache framework uses drawable as the cache object.

summary:I ’ve learned about image processing for now,Do it later.

  • Previous Comparison of cookies and sessions based on java
  • Next AngularJS basic ng-keypress directive simple example