美文网首页
Bitmap 之Mutable转化

Bitmap 之Mutable转化

作者: 空而小sao | 来源:发表于2018-01-02 19:10 被阅读0次

    踩的坑,奋笔记录一次

    在开发中,使用画布,直接用bitmap对象创立

    Bitmap tempBitmap = Bitmap.createBitmap(bitmap);
    
    Canvas canvas = new Canvas(tempBitmap);
    

    代码跟到这里,发现会报IllegalSatateException 异常,看了源码发现:

     /**
         * Construct a canvas with the specified bitmap to draw into. The bitmap
         * must be mutable.
         *
         * <p>The initial target density of the canvas is the same as the given
         * bitmap's density.
         *
         * @param bitmap Specifies a mutable bitmap for the canvas to draw into.
         */
        public Canvas(@NonNull Bitmap bitmap) {
            if (!bitmap.isMutable()) {
                throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
            }
            throwIfCannotDraw(bitmap);
            mNativeCanvasWrapper = initRaster(bitmap);
            mFinalizer = new CanvasFinalizer(mNativeCanvasWrapper);
            mBitmap = bitmap;
            mDensity = bitmap.mDensity;
    }
    

    发现这里的bitmap,需要有个属性 mutable 为true情况下才可以成功创建。
    然而并不了解这个属性的相关信息,源码中只有介绍

       /**
         * Returns true if the bitmap is marked as mutable (i.e.&nbsp;can be drawn into)
         */
        public final boolean isMutable() {
            return mIsMutable;
        }
    

    字面意思就是bitmap是否可变的,至少有道翻译是这样的。。。控制bitmap的setPixel方法能否使用,也就是外界能否修改bitmap的像素。那什么时候会造成bitmap不可变?焦点到Bitmap.createBitmap(bitmap);

    
     /**
         * Returns an immutable bitmap from the source bitmap. The new bitmap may
         * be the same object as source, or a copy may have been made.  It is
         * initialized with the same density as the original bitmap.
         */
        public static Bitmap createBitmap(Bitmap src) {
            return createBitmap(src, 0, 0, src.getWidth(), src.getHeight());
        }
    

    里面明确指出,返回的bitmap是不可变,而且有可能是和传入的对象是同一个。我的理解,该方法返回的bitmap mutable 是不确定的,当传入的src的mutable 属性为true时,经测试,返回出来的bitmap也是可操作的,既然它解释着may be the same object as source,还是有些依据。
    那既然这个方法不能保证创建的bitmap具有mutable 性,肯定有有创建具有mutable 性的方法。

     /**
         * Returns a mutable bitmap with the specified width and height.  Its
         * initial density is as per {@link #getDensity}.
         *
         * @param width    The width of the bitmap
         * @param height   The height of the bitmap
         * @param config   The bitmap config to create.
         * @throws IllegalArgumentException if the width or height are <= 0
         */
        public static Bitmap createBitmap(int width, int height, Config config) {
            return createBitmap(width, height, config, true);
        }
    

    只有这个方法返回的bitmap是mutable 的,总结下来:创建自图形的Bitmap是immutable,而给定宽高以及其他一些参数创建的Bitmap是mutable.
    当前的问题是,提供了一个immutable 的bitmap,如何将其转变为mutable 。

    /**
     * Converts a immutable bitmap to a mutable bitmap. This operation doesn't allocates
     * more memory that there is already allocated.
     * 
     * @param imgIn - Source image. It will be released, and should not be used more
     * @return a copy of imgIn, but muttable.
     */
    public static Bitmap convertToMutable(Bitmap imgIn) {
        try {
            //this is the file going to use temporally to save the bytes. 
            // This file will not be a image, it will store the raw image data.
            File file = new File(Environment.getExternalStorageDirectory() + File.separator + "temp.tmp");
    
            //Open an RandomAccessFile
            //Make sure you have added uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
            //into AndroidManifest.xml file
            RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
    
            // get the width and height of the source bitmap.
            int width = imgIn.getWidth();
            int height = imgIn.getHeight();
            Config type = imgIn.getConfig();
    
            //Copy the byte to the file
            //Assume source bitmap loaded using options.inPreferredConfig = Config.ARGB_8888;
            FileChannel channel = randomAccessFile.getChannel();
            MappedByteBuffer map = channel.map(MapMode.READ_WRITE, 0, imgIn.getRowBytes()*height);
            imgIn.copyPixelsToBuffer(map);
            //recycle the source bitmap, this will be no longer used.
            imgIn.recycle();
            System.gc();// try to force the bytes from the imgIn to be released
    
            //Create a new bitmap to load the bitmap again. Probably the memory will be available. 
            imgIn = Bitmap.createBitmap(width, height, type);
            map.position(0);
            //load it back from temporary 
            imgIn.copyPixelsFromBuffer(map);
            //close the temporary file and channel , then delete that also
            channel.close();
            randomAccessFile.close();
    
            // delete the temp file
            file.delete();
    
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } 
    
        return imgIn;
    }
    

    拿走不谢!

    相关文章

      网友评论

          本文标题:Bitmap 之Mutable转化

          本文链接:https://www.haomeiwen.com/subject/wqlqnxtx.html