Android Bitmap Facets

Source: Internet
Author: User
Tags intl

Turn from Android programmer: http://mp.weixin.qq.com/s?__biz=MzA4MjU5NTY0NA==&mid=404530070&idx=1&sn= E2580b69d6ec73dabf8160216aa6702a&scene=23&srcid= #rd

Opened the first article of appreciation, still by everyone familiar with the Feng Jian classmate, his articles can be said style similar, are a particular topic of detailed finishing, this turn to bitmap. Click here for quick access to his previous post: You should know about those Android little experiences

In the daily development, it can be said and bitmap bow to see, basically every application will be directly or indirectly used, and here involves a lot of relevant knowledge.
So here to bitmap common knowledge to do a comb, limited to experience and ability, do not do too in-depth analysis.

    1. difference between Decoderesource () and DecodeFile ()

The difference here does not refer to the difference between the method name and the parameter, but the difference in the processing of the image size after decoding:

DecodeFile () is used to read the image on the SD card, resulting in the original size of the picture
Decoderesource () is used to read res, raw and other resources, resulting in the original size of the picture * scaling factor

Can be seen, Decoderesource () more than decodefile () a scaling factor, the calculation of the scaling factor depends on the screen density, of course, this parameter can also be adjusted:

The scaling factor can be adjusted by these parameters of the Bitmapfactory.options
public class Bitmapfactory {
public static class Options {
Default True
public Boolean inscaled;
Non-DPI folder under Default 160
public int indensity;
Depends on the specific screen
public int intargetdensity;
}
}
In the specific case, we now have a picture of 720x720:

Inscaled Property

If inscaled is set to false, it is not scaled and the image size is 720x720 after decoding; Otherwise please look down.

If inscaled is set to TRUE or not set, the scaling factor is computed based on indensity and intargetdensity.

Default condition

Put this picture in the drawable directory, default:

In the case of 720p Red Rice 3, the scaling factor = intargetdensity (320/indensity (default) = 2 = density, the image size is 1440x1440 after decoding.

In the case of 1080p MX4, the zoom factor = intargetdensity (the specific 480/indensity (default) = 3 = density, the image size is 2160x2160 after decoding.

Impact of the *DPI folder

Put the picture in drawable or draw such a folder without DPI, will be calculated according to the above algorithm.

What if we put it in xhdpi? On MX4, put to xhdpi, decoded image size is x 1080.

Because it is placed in a DPI folder, it will affect the default value of indensity and put it to xhdpi x 2 = 320; So the scaling factor = 480 (screen)/(XHDPI) = 1.5; So the resulting image size is x 1080.

Setting the zoom factor manually

If you do not want to rely on the density of the system itself, you can manually set the indensity and intargetdensity to control the zoom factor:

Bitmapfactory.options Options =
New Bitmapfactory.options ();
Options.injustdecodebounds = false;
Options.insamplesize = 1;
options.indensity = 160;
options.intargetdensity = 160;
Bitmap = Bitmapfactory.decoderesource (Getresources (), r.drawable.origin, options);

MX4, although density = 3
But by setting intargetdensity/indensity = 160/160 = 1
The image size is 720x720 after decoding
System.out.println ("W:" + bitmap.getwidth () + ", H:" + bitmap.getheight ());
2. Recycle () method

Official statement

First, Android's allocation area for bitmap memory (pixel data) is differentiated on different versions:

As of Android 3.0 (API level One), the pixel data is stored on the Dalvik heap along with the associated bitmap.

Starting with 3.0, the bitmap pixel data is stored with the bitmap object in the Dalvik heap, and the bitmap pixel data is stored in native memory before 3.0.

Therefore, before 3.0, the bitmap pixel data in Nativie memory release is indeterminate, easy memory overflow and crash, the official strongly recommended to call Recycle () (of course, when it is determined when not needed), and after 3.0, there is no such requirement.

Reference link: Managing Bitmap Memory
Http://developer.android.com/intl/zh-cn/training/displaying-bitmaps/manage-memory.html
A little discussion

3.0 after the official no recycle () advice, is it really do not need recycle () it?

In this article of the Doctor: the Bitmap.recycle-induced massacre (http://blog.csdn.net/eclipsexys/article/details/50581162) concludes: " In the case of incompatible Android2.3, do not use the Recycle method to manage the bitmap, that's the GC! ”。 The article begins by stating that the reason lies in the comment description of the Recycle () method:

/**
* ... This is a advanced call, and normally need not being called,
* Since the normal GC process would free up this memory when
* There is no more references to this bitmap.
*/
public void Recycle () {}
In fact, this assertion is inaccurate and is not a basis for the Recycle () method not being invoked.

Because from the commit history, this line of comments started early in the 08, but the early code did not require the recycle () method.

If after 3.0 really do not need to actively recycle (), the latest AOSP source code should have the corresponding embodiment, I checked the systemui and Gallery2 codes, and did not outlaw bitmap recycle () method.

So, I personally think, if bitmap really do not have, recycle a bit what?

PS: As for the doctor said that the bug, is obviously an optimization strategy, app development, add a two bitmap unequal judgment conditions can be.
3. How much memory does the bitmap account for?

This is a very good Article bugly produced very clear:
Android development around the hole: how much memory does your Bitmap account for?
http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=498
4. Inbitmap

BitmapFactory.Options.inBitmap is a new property of Android3.0, and if set this property will reuse this bitmap memory to improve performance.

But this reuse is conditional, before Android4.4 can only reuse the same size bitmap,android4.4+, as long as the proportion of bitmap small can.

Detailed information on the official website, here are two ways to enumerate the sample code to understand:

private static void Addinbitmapoptions (
Bitmapfactory.options Options, Imagecache cache) {
Inbitmap works with mutable bitmaps,
The decoder to return mutable bitmaps
Options.inmutable = true;

if (cache != null) {    // Try to find a bitmap to use for inBitmap.    Bitmap inBitmap = cache.getBitmapFromReusableSet(options);    if (inBitmap != null) {        // If a suitable bitmap has been found,        // set it as the value of inBitmap.        options.inBitmap = inBitmap;    }}

}

Static Boolean Canuseforinbitmap (
Bitmap candidate, Bitmapfactory.options targetoptions) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {    // From Android 4.4 (KitKat) onward we can re-use    // if the byte size of the new bitmap is smaller than    // the reusable bitmap candidate    // allocation byte count.    int width = targetOptions.outWidth / targetOptions.inSampleSize;    int height = targetOptions.outHeight / targetOptions.inSampleSize;    int byteCount = width * height * getBytesPerPixel(candidate.getConfig());    return byteCount <= candidate.getAllocationByteCount();}// On earlier versions,// the dimensions must match exactly and the inSampleSize must be 1return candidate.getWidth() == targetOptions.outWidth&& candidate.getHeight() == targetOptions.outHeight&& targetOptions.inSampleSize == 1;

}
Reference Links:
Managing Bitmap Memory
http://developer.android.com/intl/zh-cn/training/displaying-bitmaps/m

Reuse of Anage-memory.htmlbitmap objects
http://hukai.me/android-performance-oom/
5. LRU Cache algorithm

Lru,least recently used,discards the Least recently used items first.

In the most recently used data, discard the least used data. In contrast, there is an MRU that discards the most used data.

This is the famous principle of locality.

Implementation ideas

1. Inserting new data into the list head;
2. Whenever the cache hits (that is, the cached data is accessed), the data is moved to the list header;
3. When the list is full, discard the data at the end of the list.

LruCache

The implementation class LRUCache of the LRU algorithm is provided in both Android3.1 and support V4.

Implemented internally using LINKEDHASHMAP.

Disklrucache

All of LRUCache's objects and data are in memory (or Linkedhashmap), and Disklrucache is a disk cache, but its implementation is slightly more complicated.

With Disklrucache, you don't have to worry about files or pictures that take up too much disk space, which automatically cleans up images that are not commonly used.

The Disklrucache system is not officially available and needs to be downloaded separately: Disklrucache
Https://android.googlesource.com/platform/libcore/+/jb-mr2-release/luni/src/main/java/libcore/io/DiskLruCache.java
6. Calculate Insamplesize

The most important trick to save memory with bitmap is to load the right size of bitmap, because now camera pixels, many photos are Big Macs, these large graphs are loaded directly into memory, the easiest to oom.

Loading the appropriate bitmap requires reading the original size of the bitmap and loading it by reducing the size of the appropriate multiples.

So, the calculation of this scaled-down multiplier is insamplesize.

According to MaxWidth, MaxHeight calculates the most suitable insamplesize
public static int $sampleSize (bitmapfactory.options Options, int maxWidth, int maxheight) {

// raw height and width of imageint rawWidth = options.outWidth;int rawHeight = options.outHeight;// calculate best sample sizeint inSampleSize = 0;if (rawHeight > maxHeight || rawWidth > maxWidth) {float ratioWidth = (float) rawWidth / maxWidth;float ratioHeight = (float) rawHeight / maxHeight;    inSampleSize = (int) Math.min(ratioHeight, ratioWidth);

}
Insamplesize = Math.max (1, insamplesize);

return inSampleSize;

}
About Insamplesize It is important to note that it can only be 2 of the time, otherwise it will take the nearest 2 of the value.

    1. Thumbnail images

To save memory, It is necessary to set the Bitmapfactory.options injustdecodebounds to True, so that bitmap can store the height and width in bitmap.options with the DecodeFile method, but the memory footprint is empty (does not really load the picture).

With the options of high-wide information, combined with the above insamplesize algorithm to calculate the reduced multiples, we can load a local large map of a suitable size thumbnail.

/**
* Get thumbnails
* Support automatic rotation
* Some models of mobile phone camera pictures are reversed, can be automatically corrected according to EXIF information
* @return
*/
public static Bitmap Span class= "Mathjax_preview" > thumbnail (String path, int maxwidth, int maxheight, boolean autorotate)  {  
    int angle = 0;  
     if  (autorotate)  {  
        angle =  imageless. Exifrotateangle (path);
}

BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;   // 获取这个图片的宽和高信息到options中, 此时返回bm为空Bitmap bitmap = BitmapFactory.decodeFile(path, options);options.inJustDecodeBounds = false;   // 计算缩放比int sampleSize = $sampleSize(options, maxWidth, maxHeight);options.inSampleSize = sampleSize;options.inPreferredConfig = Bitmap.Config.RGB_565;options.inPurgeable = true;options.inInputShareable = true;if (bitmap != null && !bitmap.isRecycled()) {    bitmap.recycle();}bitmap = BitmapFactory.decodeFile(path, options);if (autoRotate && angle != 0) {    bitmap = $rotate(bitmap, angle);}return bitmap;

}
The system built in a thumbnailutils can also generate thumbnails, the details are different but the principle is the same.

    1. Matrix variants

Students who have studied linear algebra or image processing must know that the matrix is powerful, and many common image transformations can be done with a matrix, even more complex.

Matrix matrix = new Matrix ();
Each kind of change includes set,pre,post three kinds, namely set, matrix multiplication, matrix after multiplication.
Pan: Matrix.settranslate ()
Scaling: Matrix.setscale ()
Rotation: Matrix.setrotate ()
Oblique cut: Matrix.setskew ()

Let me give you two examples to illustrate.

Rotating

Use the matrix's Postrotate method to rotate a certain angle.

Matrix matrix = new Matrix ();
Angle is the angle of rotation
Matrix.postrotate (angle);
Bitmap Rotatedbitmap = Bitmap.createbitmap (
Originbitmap,
0,
0,
Originbitmap.getwidth (),
Originbitmap.getheight (),
Matrix
true);
Scaling

Use the matrix's Postscale method to rotate a certain angle.

Matrix matrix = new Matrix ();
Scalex,scaley scale in horizontal and vertical directions, respectively
Matrix.postscale (ScaleX, ScaleY);
Bitmap Scaledbitmap = Bitmap.createbitmap (
Originbitmap,
0,
0,
Originbitmap.getwidth (),
Originbitmap.getheight (),
Matrix
true);
Bitmap itself with a scaling method, but the bitmap zoom to the target size, the principle is also used in the matrix, we encapsulate:

Horizontal and width zoom to the specified size, note that this situation is prone to deformation of the slice
Bitmap Scaledbitmap = Bitmap.createscaledbitmap (
Originbitmap,
Dstwidth,
Dstheight,
true);
More effects can be achieved by combining them.

    1. Cutting

There are a lot of application scenarios for picture clipping: Avatar cutting, photo clipping, rounded corners, circles, etc.

Rectangular

Matrix shape cutting is relatively simple, directly using the CreateBitmap method can:

Canvas canvas = new canvas (ORIGINBITMAP);
Draw (canvas);
Determine the location of the crop and the size of the crop
Bitmap Clipbitmap = Bitmap.createbitmap (
Originbitmap,
Left
Top
Clipwidth,
Clipheight);
Rounded Corners

For the fillet we need to use Xfermode and Porterduffxfermode, the fillet matrix is set on the original bitmap to get the intersection of the rounded angle bitmap.

Prepare the Brush
Paint paint = new paint ();
Paint.setantialias (TRUE);

Prepare the matrix for cropping
Rect rect = new Rect (0, 0,
Originbitmap.getwidth (),
Originbitmap.getheight ());

RECTF RECTF = new RECTF (new Rect (0, 0,
Originbitmap.getwidth (),
Originbitmap.getheight ()));

Bitmap Roundbitmap = Bitmap.createbitmap (
Originbitmap.getwidth (),
Originbitmap.getheight (),
Bitmap.Config.ARGB_8888);
Canvas canvas = new canvas (ROUNDBITMAP);

Fillet matrix, radius rounded to size
Canvas.drawroundrect (
RECTF, radius, radius, paint);

Key code, about Xfermode and src_in please check it yourself
Paint.setxfermode (
New Porterduffxfermode (PorterDuff.Mode.SRC_IN));
Canvas.drawbitmap (Originbitmap, rect, rect, paint);
Circular

The same is done with the rounded corners above, but the circle is drawn on top.
To crop a circle from the middle, we need to calculate the left and top values of the original bitmap.

int min = originbitmap.getwidth () > Originbitmap.getheight ()? Originbitmap.getheight (): Originbitmap.getwidth ();

Paint paint = new paint ();
Paint.setantialias (TRUE);
Bitmap Circlebitmap = Bitmap.createbitmap (min, Min, Bitmap.Config.ARGB_8888);
Canvas canvas = new canvas (CIRCLEBITMAP);

Circular
Canvas.drawcircle (MIN/2, MIN/2, MIN/2, paint);
Paint.setxfermode (
New Porterduffxfermode (PorterDuff.Mode.SRC_IN));

Center Display
int left =-(Originbitmap.getwidth ()-min)/2;
int top =-(Originbitmap.getheight ()-min)/2;
Canvas.drawbitmap (Originbitmap, left, top, paint);
We should be able to see what we can do with rounded corners and circles. It is possible to draw any polygon.

    1. Save Bitmap

Many image applications are supported by crop function, filter function and so on, and ultimately need to save the bitmap after processing to local, or it is a powerful function is also white busy.

public static String $save (
Bitmap Bitmap,
Bitmap.compressformat format,
int quality, File destfile) {

try {    FileOutputStream out = new FileOutputStream(destFile);    if (bitmap.compress(format, quality, out)) {        out.flush();        out.close();    }    if (bitmap != null && !bitmap.isRecycled()) {        bitmap.recycle();    }    return destFile.getAbsolutePath(); } catch (FileNotFoundException e) {    e.printStackTrace();} catch (IOException e) {    e.printStackTrace();}return null;

}
If you want to be more stable or easier to save to the SDcard package name path, you can encapsulate it again:

Save to local, default path/mnt/sdcard/[package]/save/, name file with random UUID
public static String $save (
Bitmap Bitmap,
Bitmap.compressformat format,
int quality, Context context) {

if (!Environment.getExternalStorageState()    .equals(Environment.MEDIA_MOUNTED)) {    return null;}File dir = new File(Environment.getExternalStorageDirectory() + "/" + context.getPackageName() + "/save/");if (!dir.exists()) {    dir.mkdirs();}File destFile = new File(dir, UUID.randomUUID().toString());return $save(bitmap, format, quality, destFile);

}
11. Mega Map Loading

Macro map loading, of course, can not use the regular method, must oom.
The principle is relatively simple, there is a class Bitmapregiondecoder in the system:

public static Bitmapregiondecoder newinstance (
byte[] data, int offset,
int length, Boolean isshareable) throws IOException {
}
public static Bitmapregiondecoder newinstance (
FileDescriptor fd, Boolean isshareable) throws IOException {
}
public static Bitmapregiondecoder newinstance (
InputStream is, Boolean isshareable) throws IOException {
}
public static Bitmapregiondecoder newinstance (
String PathName, Boolean isshareable) throws IOException {
}
Can be loaded by region:

Public Bitmap decoderegion (rect rect, bitmapfactory.options Options) {
}
The big picture of the microblog is also through this bitmapregiondecoder realization, the specific can be self-check.

    1. Color Matrix ColorMatrix

Image processing is actually a very esoteric subject, fortunately, Android provides a color matrix ColorMatrix class, can achieve a lot of simple effects, with the gray-scale effect as an example:

Bitmap Graybitmap = Bitmap.createbitmap (
Originbitmap.getwidth (),
Originbitmap.getheight (),
Bitmap.Config.RGB_565);
Canvas canvas = new canvas (GRAYBITMAP);
Paint paint = new paint ();
ColorMatrix ColorMatrix = new ColorMatrix ();

// 设置饱和度为0,实现了灰阶效果colorMatrix.setSaturation(0);ColorMatrixColorFilter colorMatrixColorFilter =    new ColorMatrixColorFilter(colorMatrix);paint.setColorFilter(colorMatrixColorFilter);canvas.drawBitmap(originBitmap, 0, 0, paint);

In addition to saturation, we can adjust the contrast, hue changes and so on.

    1. Thumbnailutils anatomy

Thumbnailutils is a system provides a special way to generate thumbnails, I wrote a special article analysis, more content, please step: understand Thumbnailutils
http://www.jayfeng.com/2016/03/16/Understanding thumbnailutils/
14. Summary

Since we often deal with bitmap, it is necessary to clarify it all.

Inevitably there will be omissions, welcome message, I will add as appropriate.

This part of the code has been integrated into Lesscode, welcome to follow reference.
Https://github.com/openproject/LessCode

Android Bitmap All facets

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.