在没有 OutOfMemoryError 的情况下加载大图像 [英] Loading large images without OutOfMemoryError
问题描述
我有一个 5000 x 4000 像素的图像,我想将其绘制到画布上.
I have a 5000 x 4000 px image which I want to draw onto a canvas.
首先我尝试从资源中加载它.我把它放在 /res/drawable
中.
First I tried to load it from resources.
I put it in /res/drawable
.
我使用了以下方法:
InputStream input = getResources().openRawResource(R.drawable.huge_image);
Drawable d = Drawable.createFromStream(input, "image");
d.setBounds(...);
d.draw(canvas);
它就像一个魅力.
在这种情况下,InputStream
是一个 AssetManager.AssetInputStream
.
In this case the InputStream
is an AssetManager.AssetInputStream
.
所以现在我想从 sdcard 加载它.
So now I want to load it from the sdcard.
这是我尝试做的:
File f = new File(path);
Uri uri = Uri.fromFile(f);
InputStream input = mContext.getContentResolver().openInputStream(uri);
Drawable d = Drawable.createFromStream(input, "image");
在这种情况下,InputStream
是一个 FileInputStream
,我在创建 Drawable
时得到了一个 OutOfMemoryError
.
In this case the InputStream
is a FileInputStream
and I got an OutOfMemoryError
when creating the Drawable
.
所以我想知道:
有没有办法加载图像而不会出现该错误?或者有没有办法将 FileInputStream
转换为 AssetInputStream
?
Is there a way to load the image without getting that error? Or is there a way to convert a FileInputStream
to an AssetInputStream
?
注意:
我不想调整图像大小,因为我正在实现缩放/平移功能.请不要告诉我要阅读有效加载大位图.
I don't want to resize the image because I'm implementing zoom/pan functionality. Please don't tell me to read Loading Large Bitmaps Efficiently.
您可以在此处查看完整课程.使用 setImageUri()
时出现错误.
You can check out the full class here. The error occurs when using setImageUri()
.
这是我的错误日志:
08-13 11:57:54.180: E/AndroidRuntime(23763): FATAL EXCEPTION: main
08-13 11:57:54.180: E/AndroidRuntime(23763): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:468)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:332)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.graphics.drawable.Drawable.createFromStream(Drawable.java:657)
08-13 11:57:54.180: E/AndroidRuntime(23763): at com.benitobertoli.largeimagezoom.ZoomImageView.setDrawablefromUri(ZoomImageView.java:187)
08-13 11:57:54.180: E/AndroidRuntime(23763): at com.benitobertoli.largeimagezoom.ZoomImageView.setImageUri(ZoomImageView.java:588)
08-13 11:57:54.180: E/AndroidRuntime(23763): at com.benitobertoli.largeimagezoom.TestActivity.onKeyDown(TestActivity.java:30)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.view.KeyEvent.dispatch(KeyEvent.java:1257)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.app.Activity.dispatchKeyEvent(Activity.java:2075)
08-13 11:57:54.180: E/AndroidRuntime(23763): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1673)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.view.ViewRoot.deliverKeyEventToViewHierarchy(ViewRoot.java:2493)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.view.ViewRoot.handleFinishedEvent(ViewRoot.java:2463)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.view.ViewRoot.handleMessage(ViewRoot.java:1752)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.os.Handler.dispatchMessage(Handler.java:99)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.os.Looper.loop(Looper.java:144)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.app.ActivityThread.main(ActivityThread.java:4937)
08-13 11:57:54.180: E/AndroidRuntime(23763): at java.lang.reflect.Method.invokeNative(Native Method)
08-13 11:57:54.180: E/AndroidRuntime(23763): at java.lang.reflect.Method.invoke(Method.java:521)
08-13 11:57:54.180: E/AndroidRuntime(23763): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
08-13 11:57:54.180: E/AndroidRuntime(23763): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
08-13 11:57:54.180: E/AndroidRuntime(23763): at dalvik.system.NativeStart.main(Native Method)
我正在 HTC Desire A8181 上测试我的代码.在得知第一个代码片段在其他一些设备上不起作用后,我在三星 Galaxy S2 和模拟器上进行了测试.
I was testing my code on an HTC Desire A8181. After being told that the first code snippet wasn't working on some other devices, I tested on a Samsung Galaxy S2 and on the Emulator.
结果:从资源加载时,模拟器给出OutOfMemoryError
,Galaxy S2没有抛出异常但返回的Drawable
为空.
Results:
When loading from resources, the emulator gave an OutOfMemoryError
, the Galaxy S2 didn't throw an exception but the returned Drawable
was null.
所以我想暂时唯一的解决方案是对图像进行下采样.</p>
So I guess for the time being the only solution is to downsample the image.
推荐答案
看一看:
http://developer.android.com/reference/android/graphics/位图工厂.html
decodeStream (InputStream is, Rect outPadding, BitmapFactory.Options opts)
或
decodeFile (String pathName, BitmapFactory.Options opts)
通过这种方式,您可以加载整个位图并将其显示在屏幕上.
this way you can load your whole bitmap and show it on screen.
您需要设置正确的选项.
You need to set the correct options.
http://developer.android.com/reference/android/图形/BitmapFactory.Options.html
inSampleSize
我用你的代码试过了:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
Bitmap myBitmap = BitmapFactory.decodeFile(mUri.getPath(),options);
Drawable d = new BitmapDrawable(Resources.getSystem(),myBitmap);
updateDrawable(d);
对我有用.
这篇关于在没有 OutOfMemoryError 的情况下加载大图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!