我在SD卡上有一个图像,需要在图像视图上显示 问题是,在解码之后,质量似乎恶化了.有没有什么方法可以保持质量,同时保留记忆? 或者,如果我使用更大的图像,是否有任何方法可以保留
问题是,在解码之后,质量似乎恶化了.有没有什么方法可以保持质量,同时保留记忆?
或者,如果我使用更大的图像,是否有任何方法可以保留内存(避免加载太大的位图)和缩放? (我需要保持原始图像的大小)
谢谢你的帮助.
public Bitmap decodeFile(String pubKey, int bookPageID, int type) throws IOException { Bitmap b = null; File f = null; String uri = null; FileInputStream fis = null; Log.d(TAG,"pageID to read: " + bookPageID); IRIssue issue = Broker.model.issueDataStore.getIRIssue(pubKey); String imageFolder = IRConstant.issueFolder(issue.year, issue.month, issue.day, issue.pubKey); // pageID - 1 since the page is an array (start at 0) , but page ID start at 1 if (type == 2){ uri = imageFolder + issue.vol[0].pages[bookPageID - 1].graphicUri; }else { uri = imageFolder + issue.vol[0].pages[bookPageID - 1].textUri; } f = new File(uri); Log.d(TAG,"is file: " + uri + " exist?" + f.exists()); BitmapFactory.Options options = new BitmapFactory.Options(); options.inPurgeable = true; options.inInputShareable = true; options.inJustDecodeBounds = false; options.inPreferredConfig = Bitmap.Config.ARGB_8888; fis = new FileInputStream(f); b = BitmapFactory.decodeStream(fis, null, options); fis.close(); return b; }以下代码使用 Displaying Bitmaps Efficiently中的几个概念
首先关闭位图读取是在后台线程中完成的,我在inputStream上使用mark / reset(用BufferedInputstream包装),当我们试图找出计算尺度时要使用的图像大小时,不要从流中读取更多内容因子.下面的示例代码对图像进行子采样,以匹配320×240像素的大小.在非示例代码中,可以使用简单的回调接口将位图从onPostExecute发送到实现类(回调接口实现器).或者直接将视图作为AsyncTask的成员提供,并在onPostExecute中设置位图.
使用(我的设备上的示例下载图像)调用代码:
BitmapTask task = new BitmapTask(getContentResolver()); task.execute(Uri.parse("file:///storage/emulated/0/Download/download.jpg"));
有问题的课程
private static class BitmapTask extends AsyncTask<Uri, Void, Bitmap> { // prevent mem leaks private WeakReference<ContentResolver> mWeakContentResolver; public BitmapTask(ContentResolver resolver) { mWeakContentResolver = new WeakReference<ContentResolver>(resolver); } @Override protected Bitmap doInBackground(Uri... params) { Bitmap bitmap = null; ContentResolver resolver = mWeakContentResolver.get(); if (resolver != null) { BufferedInputStream stream = null; try { stream = new BufferedInputStream( resolver.openInputStream(params[0])); stream.mark(1 * 1024); BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; // Find out size of image BitmapFactory.decodeStream(stream, null, options); try { stream.reset(); } catch (IOException e) { Log.d(TAG, "reset failed"); } int imageHeight = options.outHeight; int imageWidth = options.outWidth; String imageType = options.outMimeType; Log.d(TAG, "w, h, mime " + imageWidth + " , " + imageHeight + " , " + imageType); options.inJustDecodeBounds = false; // Calculate down scale factor options.inSampleSize = calculateInSampleSize(options, 320, 240); return BitmapFactory.decodeStream(stream, null, options); } catch (FileNotFoundException e) { bitmap = null; } finally { IOUtils.closeStreamSilently(stream); } } return bitmap; } @Override protected void onPostExecute(Bitmap result) { Log.d(TAG, "bitmap result: " + ((result != null) ? "" + result.getByteCount() : "0")); result.recycle(); } } 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; }
编辑:对于大型输入流可能存在标记/重置技术的问题,SkImageDecoder :: Factory返回null有时可以在日志中看到,导致空位图,关于此问题的其他SO问题:SkImageDecoder::Factory returned null.它可以通过以下方式修复:再次重新启动流变量stream = new resolver.openInputStream(params [0]));在doInBackground中返回之前
编辑2:如果你必须保留图像大小但不想限制内存使用,你可以使用options.inPreferredConfig = Bitmap.Config.RGB_565;将每个像素的内存减半,但要记住图像可能不再具有高质量(实验!).