zoukankan      html  css  js  c++  java
  • 关于android 图片加载压缩处理


    android应用对图片处理算是比较频繁的了,尤其是在程序加载大量图片和高分辨率图片时,最容易产生oom异常,下面是个人平时一些省内存加载方法

    resoursce加载

    public Bitmap ReadBitMap(Context context, int resId){    
            BitmapFactory.Options opt = new BitmapFactory.Options();    
            opt.inPreferredConfig = Bitmap.Config.RGB_565;   //小于ARGB_8888  样式大小
            opt.inPurgeable = true;    
            opt.inInputShareable = true;    
            //获取资源图片    
            InputStream is = context.getResources().openRawResource(resId);    
            return BitmapFactory.decodeStream(is,null,opt);    
      }   
    

     计算bitmap内存大小:

    int calculateBitmapSize(Bitmap candidate,Resources res, int resId){
    		BitmapFactory.Options targetOptions=new BitmapFactory.Options();
    		targetOptions.inJustDecodeBounds = true;
    		BitmapFactory.decodeResource(res, resId, targetOptions);
    		int width = targetOptions.outWidth / targetOptions.inSampleSize;
            int height = targetOptions.outHeight / targetOptions.inSampleSize;
            int byteCount = width * height * getBytesPerPixel(candidate.getConfig());
            return byteCount;
    	}
    	/**
    	 * A helper function to return the byte usage per pixel of a bitmap based on its configuration.
    	 */
    	static int getBytesPerPixel(Config config) {
    	    if (config == Config.ARGB_8888) {
    	        return 4;
    	    } else if (config == Config.RGB_565) {
    	        return 2;
    	    } else if (config == Config.ARGB_4444) {
    	        return 2;
    	    } else if (config == Config.ALPHA_8) {
    	        return 1;
    	    }
    	    return 1;
    	}
    

     

    指定尺寸压缩:

    public static int calculateInSampleSize(
                BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
    
        if (height > reqHeight || width > reqWidth) {
    
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;
    
            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }
    
        return inSampleSize;
    }
    
    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
            int reqWidth, int reqHeight) {
    
        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);
    
        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    
        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }
    

     

    如果你的控件大小小于原始图片大小,那么就需要对图片进行压缩处理,来减少内存使用。

    现在知道了原图片的尺寸,根据实际情况决定你要加载它缩小多少倍后的图片。例如你用一个128x96的ImageView显示一张1024x768的原图,根本没有必要把原图读加载到内存。
    加载一张缩小后的图片到内存,只需要把BitmapFactory.Options对象的inSampleSize设为true,
    然后给inSampleSize设一个值就行了(可以理解inSampleSize为n,图片就缩小到1/n大小)。

    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,  
            int reqWidth, int reqHeight) {  
      
        // First decode with inJustDecodeBounds=true to check dimensions  
        final BitmapFactory.Options options = new BitmapFactory.Options();  
        options.inJustDecodeBounds = true;  
        BitmapFactory.decodeResource(res, resId, options);  
      
        // Calculate inSampleSize  
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);  
      
        // Decode bitmap with inSampleSize set  
        options.inJustDecodeBounds = false;  
        return BitmapFactory.decodeResource(res, resId, options);  
    }  
    public static int calculateInSampleSize(  
                BitmapFactory.Options options, int reqWidth, int reqHeight) {  
        // Raw height and width of image  
        final int height = options.outHeight;  
        final int width = options.outWidth;  
        int inSampleSize = 1;  
      
        if (height > reqHeight || width > reqWidth) {  
            if (width > height) {  
                inSampleSize = Math.round((float)height / (float)reqHeight);  
            } else {  
                inSampleSize = Math.round((float)width / (float)reqWidth);  
            }  
        }  
        return inSampleSize;  
    }  
    

    官方压缩计算:更新2016-07-16

    public static int calculateInSampleSize(
                BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
    
        if (height > reqHeight || width > reqWidth) {
    
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;
    
            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) >= reqHeight
                    && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }
    
        return inSampleSize;
    }
    
    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
            int reqWidth, int reqHeight) {
    
        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);
    
        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    
        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }
    

     
    2017-5-26更新参考picasso计算图形拉伸处理

     static void calculateInSampleSize(int reqWidth, int reqHeight, BitmapFactory.Options options,
                                          boolean centerInside) {
            calculateInSampleSize(reqWidth, reqHeight, options.outWidth, options.outHeight, options,
                    centerInside);
        }
    
        static void calculateInSampleSize(int reqWidth, int reqHeight, int width, int height,
                                          BitmapFactory.Options options, boolean centerInside) {
            int sampleSize = 1;
            if (height > reqHeight || width > reqWidth) {
                final int heightRatio;
                final int widthRatio;
                if (reqHeight == 0) {
                    sampleSize = (int) Math.floor((float) width / (float) reqWidth);
                } else if (reqWidth == 0) {
                    sampleSize = (int) Math.floor((float) height / (float) reqHeight);
                } else {
                    heightRatio = (int) Math.floor((float) height / (float) reqHeight);
                    widthRatio = (int) Math.floor((float) width / (float) reqWidth);
                    sampleSize = centerInside
                            ? Math.max(heightRatio, widthRatio)
                            : Math.min(heightRatio, widthRatio);
                }
            }
            options.inSampleSize = sampleSize;
            options.inJustDecodeBounds = false;
        }
    

     use:

    void useCalucateBitmapCompress(){
            if (calculateSize) {
                BitmapFactory.decodeStream(stream, null, options);
                calculateInSampleSize(request.targetWidth, request.targetHeight, options,
                        true);
            }
            Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);
            if (bitmap == null) {
                // Treat null as an IO exception, we will eventually retry.
                throw new IOException("Failed to decode stream.");
            }
            return bitmap;
        }
    

    使用内存缓存

    对于缓存,没有大小或者规则适用于所有应用,它依赖于你分析自己应用的内存使用确定自己的方案。
    缓存太小可能只会增加额外的内存使用,缓存太大可能会导致内存溢出或者应用其它模块可使用内存太小

    private LruCache<String, Bitmap> mMemoryCache;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        // Get max available VM memory, exceeding this amount will throw an
        // OutOfMemory exception. Stored in kilobytes as LruCache takes an
        // int in its constructor.
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
    
        // Use 1/8th of the available memory for this memory cache.
        final int cacheSize = maxMemory / 8;
    
        mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                // The cache size will be measured in kilobytes rather than
                // number of items.
                return bitmap.getByteCount() / 1024;
            }
        };
        ...
    }
    
    public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
        if (getBitmapFromMemCache(key) == null) {
            mMemoryCache.put(key, bitmap);
        }
    }
    
    public Bitmap getBitmapFromMemCache(String key) {
        return mMemoryCache.get(key);
    }
    

    使用磁盘缓存

    你的应用也有可能被其他任务打断,如电话呼入,应用在后台有可能会被结束,这样缓存的数据也会丢失。
    当用户回到应用时,所有的图片还需要重新获取一遍。
    磁盘缓存可应用到这种场景中,它可以减少你获取图片的次数,当然,从磁盘获取图片比从内存中获取要慢的多,所以它需要在非UI线程中完成。
    示例代码中是磁盘缓存的一个实现,在Android4.0源码中(libcore/luni/src/main/java/libcore/io/DiskLruCache.java),
    有更加强大和推荐的一个实现,它的向后兼容使在已发布过的库中很方便使用它

    private DiskLruCache mDiskCache;
    private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB
    private static final String DISK_CACHE_SUBDIR = "thumbnails";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        // Initialize memory cache
        ...
        File cacheDir = getCacheDir(this, DISK_CACHE_SUBDIR);
        mDiskCache = DiskLruCache.openCache(this, cacheDir, DISK_CACHE_SIZE);
        ...
    }
    
    class BitmapWorkerTask extends AsyncTask {
        ...
        // Decode image in background.
        @Override
        protected Bitmap doInBackground(Integer... params) {
            final String imageKey = String.valueOf(params[0]);
    
            // Check disk cache in background thread
            Bitmap bitmap = getBitmapFromDiskCache(imageKey);
    
            if (bitmap == null) { // Not found in disk cache
                // Process as normal
                final Bitmap bitmap = decodeSampledBitmapFromResource(
                        getResources(), params[0], 100, 100));
            }
    
            // Add final bitmap to caches
            addBitmapToCache(String.valueOf(imageKey, bitmap);
    
            return bitmap;
        }
        ...
    }
    
    public void addBitmapToCache(String key, Bitmap bitmap) {
        // Add to memory cache as before
        if (getBitmapFromMemCache(key) == null) {
            mMemoryCache.put(key, bitmap);
        }
    
        // Also add to disk cache
        if (!mDiskCache.containsKey(key)) {
            mDiskCache.put(key, bitmap);
        }
    }
    
    public Bitmap getBitmapFromDiskCache(String key) {
        return mDiskCache.get(key);
    }
    
    // Creates a unique subdirectory of the designated app cache directory. Tries to use external
    // but if not mounted, falls back on internal storage.
    public static File getCacheDir(Context context, String uniqueName) {
        // Check if media is mounted or storage is built-in, if so, try and use external cache dir
        // otherwise use internal cache dir
        final String cachePath = Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED
                || !Environment.isExternalStorageRemovable() ?
                        context.getExternalCacheDir().getPath() : context.getCacheDir().getPath();
    
        return new File(cachePath + File.separator + uniqueName);
    }
    

    2019-10-14,相机图片压缩并旋转

        private fun getBitmap(uri: Uri): Bitmap? {
            var ism: InputStream? = null
            var returnedBitmap: Bitmap? = null
            try {
    //            ism = mContentResolver!!.openInputStream(uri)
                val f = File(uri.path)
                if(false==f.exists()){
                    return null
                }
                ism = FileInputStream(f)
                //Decode image size
                val o = BitmapFactory.Options()
                o.inJustDecodeBounds = true
                BitmapFactory.decodeStream(ism, null, o)
                ism!!.close()
    //            BitmapFactory.decodeFile(f.path, o)
                var scale = 1
                if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) {
                    scale = Math.pow(2.0, Math.round(Math.log(IMAGE_MAX_SIZE / Math.max(o.outHeight, o.outWidth).toDouble()) / Math.log(0.5)).toInt().toDouble()).toInt()
                }
                o.inSampleSize = scale
                o.inJustDecodeBounds = false
    //            val o2 = BitmapFactory.Options()
    //            o2.inSampleSize = scale
    //            o2.inJustDecodeBounds = false
    //            ism = mContentResolver!!.openInputStream(uri)
    
    //            val inputStream = FileInputStream(f)
    //            val bytes = readStream(inputStream)
    //            val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size,o2)
    //            val bitmap = BitmapFactory.decodeStream(inputStream, null, o2)
                val loadBitmap = BitmapFactory.decodeFile(f.path, o)
    //            ism!!.close()
                returnedBitmap = fixOrientationBugOfProcessedBitmap(bitmap)
                return returnedBitmap
    //            return loadBitmap
            } catch (e: FileNotFoundException) {
                Log.d(TAG, "FileNotFoundException")
            } catch (e: IOException) {
                Log.d(TAG, "IOException")
            }
    
            return null
        }
    
        private fun fixOrientationBugOfProcessedBitmap(bitmap: Bitmap?): Bitmap? {
            try {
                if (getCameraPhotoOrientation(this, Uri.parse(mFileTemp!!.path)) == 0) {
                    return bitmap
                } else {
                    val matrix = Matrix()
                    matrix.postRotate(getCameraPhotoOrientation(this, Uri.parse(mFileTemp!!.path)).toFloat())
                    // recreate the new Bitmap and set it back
                    return Bitmap.createBitmap(bitmap!!, 0, 0, bitmap.width, bitmap.height, matrix, true)
                }
            } catch (ex: Exception) {
                ex.printStackTrace()
                return null
            }
    
        }
    
    
    
    
    





  • 相关阅读:
    XMLHttpRequest对象垃圾回收
    Stored XSS攻击
    重写setTimeout
    js instanceof Object Function
    maven的环境搭建
    Struts2整合json
    分页框架(Pager-taglib)的使用及sitemesh的简单使用
    首页文章标题分页
    在线HTML编辑器的引入
    Sparse PCA: reproduction of the synthetic example
  • 原文地址:https://www.cnblogs.com/happyxiaoyu02/p/6818953.html
Copyright © 2011-2022 走看看