BitmapRegionDecoder加载超大图片

1.BitmapRegionDecoder提供了一系列的newInstance方法来构造对象,支持传入文件路径,文件描述符,文件的inputstrem等

if (o instanceof String) {
    inputStream = new FileInputStream((String) o);
    // 根据图片对应的BitmapRegionDecoder对象
    mBitmapRegionDecoder = BitmapRegionDecoder.newInstance((String) o, false);
} else if (o instanceof InputStream) {
    inputStream = (InputStream) o;
    mBitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, false);
}

2.加载部分区域,手势的滑动加载其他部分

public class BigImageView extends View {
    private Context mContext;
    private BitmapRegionDecoder mBitmapRegionDecoder;
    private Rect mRect = new Rect();
    private int mImageWidth = 0;
    private int mImageHeight = 0;
    private BitmapFactory.Options mOptions;

    public BigImageView(Context context) {
        this(context, null);
    }

    public BigImageView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BigImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        init();
    }

    private void init() {
        // 指定图片的解码格式为RGB_565
        mOptions = new BitmapFactory.Options();
        mOptions.inPreferredConfig = Bitmap.Config.RGB_565;
    }

    // 传入需要加载的图片的inputStream
    public void setInputStream(Object o) {
        InputStream inputStream = null;
        try {
            if (o instanceof String) {
                inputStream = new FileInputStream((String) o);
                // 根据图片对应的BitmapRegionDecoder对象
                mBitmapRegionDecoder = BitmapRegionDecoder.newInstance((String) o, false);
            } else if (o instanceof InputStream) {
                inputStream = (InputStream) o;
                mBitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, false);
            }
            // 获得图片的宽高
            BitmapFactory.Options tmpOptions = new BitmapFactory.Options();
            tmpOptions.inJustDecodeBounds = true; // 将inJuestDecodeBounds设为true,这样BitmapFactory只会解析图片的原始宽/高信息,并不会真正的去加载图片
            BitmapFactory.decodeStream(inputStream, null, tmpOptions); // 解析图片获得图片的宽高
            mImageWidth = tmpOptions.outWidth; // 保存图片的宽
            mImageHeight = tmpOptions.outHeight; // 保存图片的搞

            requestLayout(); // 这里调用requestLayout方法,请求重新布局,触发调用控件的onMeasure,初始化加载区域
            invalidate(); // 调用invalidate方法,请求重绘
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 保存上一次事件的发生位置
    float lastEventX = 0;
    float lastEventY = 0;
    // 保存当前事件的发生位置
    float eventX = 0;
    float eventY = 0;

    // 重载控件的onTouchEvent方法,监控控件的事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 这里只处理了控件的Move事件,如果有更复杂需求,比如说根据手势缩放图片,可以将事件交由给GestureDetector处理
        if (event != null) {
            // 得到当前事件的发生位置
            eventX = event.getX();
            eventY = event.getY();
            switch (event.getAction()) {
                case MotionEvent.ACTION_MOVE: // move事件
                    // 根据当前事件的发生位置和上一次事件的发生位置计算出用户的滑动距离,并调整图片的加载区域
                    move((int) (lastEventX - eventX), (int) (lastEventY - eventY));
                    break;
            }
            // 保存上一次事件的发生位置
            lastEventX = event.getX();
            lastEventY = event.getY();
        }
        return true;
    }

    // 根据滑动距离调整图片的加载区域
    private void move(int moveX, int moveY) {
        // 只有当图片的高大于控件的高,控件纵向显示不下图片时,才需要调整加载区域的上下位置
        if (mImageHeight > getHeight()) {
            mRect.top = mRect.top + moveY;
            mRect.bottom = mRect.top + getHeight();
        }
        // 只有当图片的宽大于控件的宽,控件横向显示不下图片时,才需要调整加载区域的左右位置
        if (mImageWidth > getWidth()) {
            mRect.left = mRect.left + moveX;
            mRect.right = mRect.left + getWidth();
        }

        invalidate();
    }

    // 重写onDraw方法,绘制图片的局部
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mBitmapRegionDecoder != null) {
            // 检查绘制区域的宽高,以免绘制到图片以为的区域
            checkHeight();
            checkWidth();
            // 加载图片的指定区域
            Bitmap bitmap = mBitmapRegionDecoder.decodeRegion(mRect, mOptions);
            // 绘制图片的局部到控件上
            if (bitmap != null) {
                canvas.drawBitmap(bitmap, 0, 0, null);
            }
        }
    }

    /**
     * 检查加载区域是否超出图片范围
     */
    private void checkWidth() {
        // 只有当图片的宽大于控件的宽,控件横向显示不下图片时,才需要调整加载区域的左右位置
        if (mImageWidth > getWidth()) {
            if (mRect.right > mImageWidth) {
                mRect.right = mImageWidth;
                mRect.left = mRect.right - getWidth();
            }

            if (mRect.left < 0) {
                mRect.left = 0;
                mRect.right = getWidth();
            }
        } else {
            mRect.left = (mImageWidth - getWidth()) / 2;
            mRect.right = mRect.left + getWidth();
        }
    }

    /**
     * 检查加载区域是否超出图片范围
     */
    private void checkHeight() {
        // 只有当图片的高大于控件的高,控件纵向显示不下图片时,才需要调整加载区域的上下位置
        if (mImageHeight > getHeight()) {
            if (mRect.bottom > mImageHeight) {
                mRect.bottom = mImageHeight;
                mRect.top = mRect.bottom - getHeight();
            }
            if (mRect.top < 0) {
                mRect.top = 0;
                mRect.bottom = getHeight();
            }
        } else {
            mRect.top = (mImageHeight - getHeight()) / 2;
            mRect.bottom = mRect.top + getHeight();
        }
    }

    /**
     * 重写测量控件大小的方法,初始化图片的加载区域
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // 得到控件的宽高
        int width = getMeasuredWidth();
        int height = getHeight();

        // 初始化图片的加载区域为图片的中心,可以自行根据需求调整
        mRect.left = (mImageWidth - width) / 2;
        mRect.right = mRect.left + width;
        mRect.top = (mImageHeight - height) / 2;
        mRect.bottom = mRect.top + height;
    }
}

Demo下载地址:https://download.csdn.net/download/qq_39735504/10357041

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 BitmapRegionDecoder 技术可以实现分块加载图片数据,从而避免因图片数据过大而导致的内存溢出等问题。以下是一个简单的示例代码,它使用了 Android 的 BitmapRegionDecoder 类来加载图片数据: ```java // 假设你已经获取了一个 SQLiteDatabase 对象 SQLiteDatabase db = ...; // 假设你要查询的图片 ID 为 123 int imageId = 123; // 执行查询操作,获取图片数据 Cursor cursor = db.rawQuery("SELECT data FROM images WHERE id = ?", new String[] { String.valueOf(imageId) }); if (cursor.moveToFirst()) { byte[] imageData = cursor.getBlob(0); // 加载图片数据 BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(imageData, 0, imageData.length, true); // 计算要加载图片块的位置和大小 int width = decoder.getWidth(); int height = decoder.getHeight(); Rect rect = new Rect(0, 0, width, height); int sampleSize = 1; while (width / sampleSize > MAX_DIMENSION || height / sampleSize > MAX_DIMENSION) { sampleSize *= 2; } rect.right /= sampleSize; rect.bottom /= sampleSize; // 加载图片块并显示 Bitmap bitmap = decoder.decodeRegion(rect, null); ImageView imageView = findViewById(R.id.imageView); imageView.setImageBitmap(bitmap); } // 关闭游标和数据库连接 cursor.close(); db.close(); ``` 在这个示例代码中,我们首先使用 BitmapRegionDecoder.newInstance() 方法来加载图片数据,然后计算要加载图片块的位置和大小,最后使用 decodeRegion() 方法来加载并显示图片块。需要注意的是,为了避免图片块过大导致的内存溢出等问题,我们在计算要加载图片块的大小时使用了一个 sampleSize 参数来控制缩小比例。MAX_DIMENSION 常量可以根据你的应用程序需求进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值