有没有办法从 Android 中的文件加载并部分绘制位图?

发布于 2024-09-18 14:40:23 字数 154 浏览 6 评论 0原文

假设我在磁盘上有一个有点大(即不适合大多数手机的内存)的位图。我只想以不缩放的方式在屏幕上绘制它的一部分(即 inSampleSize == 1

有没有办法加载/绘制我想要的部分给定 Rect 指定区域而不加载整个位图内容?

Say I have a somewhat large (i.e. not fit in most phones' memory) bitmap on disk. I want to draw only parts of it on the screen in a way that isn't scaled (i.e. inSampleSize == 1)

Is there a way to load/draw just the part I want given a Rect specifying the area without loading the entire bitmap content?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

绝影如岚 2024-09-25 14:40:23

我非常有信心这是可能的,因为您可以毫无问题地将一个非常大的位图文件加载到 ImageView 中,因此必须有某种内置方法来处理大位图......然后经过几次尝试,我找到了一个解决方案:

不要加载整个位图并自己手动绘制它,而是将其加载为Drawable

InputStream mapInput = getResources().openRawResource(
        R.drawable.transit_map);
_map = Drawable.createFromStream(mapInput, "transit_map");

_map.setBounds(0, 0, _mapDimension.width(), _mapDimension.height());

我正在使用资源文件,但由于您可以使用 Drawable.createFromStream 从任何 InputStream 加载图像,因此它应该适用于任意位图。

然后,使用 Drawable.draw 方法将其绘制到所需的画布上,如下所示:

int left = -(int) contentOffset.x;
int top = -(int) contentOffset.y;
int right = (int) (zoom * _mapDimension.width() - contentOffset.x);
int bottom = (int) (zoom * _mapDimension.height() - contentOffset.y);

_map.setBounds(left, top, right, bottom);
_map.draw(canvas);

如上例所示,您还可以通过操作可绘制对象的边界来缩放和平移位图仅位图的相关部分会被加载并绘制到 Canvas 上。

结果是仅从一个 200KB 位图文件中获得可捏缩放视图。我还使用 22MB PNG 文件对此进行了测试,它仍然可以正常工作,没有任何 OutOfMemoryError ,包括当屏幕方向发生变化时。

I'm quite confident this is possible since you can load a really large bitmap file into an ImageView without problems so there must be some sort of a built-in way to handle large bitmaps... and after a few attempts, I've found a solution:

Instead of loading the entire bitmap and manually draw it yourself, load it as a Drawable instead:

InputStream mapInput = getResources().openRawResource(
        R.drawable.transit_map);
_map = Drawable.createFromStream(mapInput, "transit_map");

_map.setBounds(0, 0, _mapDimension.width(), _mapDimension.height());

I'm using a resource file but since you can use Drawable.createFromStream to load image from any InputStream, it should works with arbitrary bitmap.

Then, use the Drawable.draw method to draw it onto the desired canvas like so:

int left = -(int) contentOffset.x;
int top = -(int) contentOffset.y;
int right = (int) (zoom * _mapDimension.width() - contentOffset.x);
int bottom = (int) (zoom * _mapDimension.height() - contentOffset.y);

_map.setBounds(left, top, right, bottom);
_map.draw(canvas);

As in the above case, You can also scale and translate the bitmap as well by manipulating the drawable's bounds and only the relevant parts of the bitmap will be loaded and drawn onto the Canvas.

The result is a pinch-zoomable view from just one single 200KB bitmap file. I've also tested this with a 22MB PNG file and it still works without any OutOfMemoryError including when screen orientation changes.

巾帼英雄 2024-09-25 14:40:23

现在它非常相关:BitmapRegionDecoder

注意:自 Android SDK 10 起可用

Now it's very relevant: BitmapRegionDecoder.

Note: available since Android SDK 10

星星的軌跡 2024-09-25 14:40:23

使用 RapidDecoder 可以轻松完成此操作。

import rapid.decoder.BitmapDecoder;

Rect bounds = new Rect(10, 20, 30, 40);
Bitmap bitmap = BitmapDecoder.from("your-file.png")
                             .region(bounds)
                             .decode();
imageView.setImageBitmap(bitmap);

它支持低至 Android 2.2(API 级别 8)。

It can easily be done by using RapidDecoder.

import rapid.decoder.BitmapDecoder;

Rect bounds = new Rect(10, 20, 30, 40);
Bitmap bitmap = BitmapDecoder.from("your-file.png")
                             .region(bounds)
                             .decode();
imageView.setImageBitmap(bitmap);

It supports down to Android 2.2 (API Level 8).

落墨 2024-09-25 14:40:23

一般来说,这是不可能的,特别是因为大多数图像格式都是压缩的,因此在提取未压缩的形式之前,您甚至不知道要读取哪些字节。

将图像分成小图块,然后仅加载覆盖要在运行时显示的区域所需的图块。为了避免滚动抖动,您可能还需要在后台线程上预加载刚刚看不见的图块(与可见图块接壤的图块)。

Generally speaking, that isn't possible, particularly since most image formats are compressed, so you don't even know which bytes to read until you've extracted the uncompressed form.

Break your image up into small tiles and load just the tiles you need to cover the region you want to display at runtime. To avoid jittery scrolling, you might also want to preload tiles that are just out of sight (the ones that border the visible tiles) on a background thread.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文