如何在 Android 中调整位图的大小?
Posted
技术标签:
【中文标题】如何在 Android 中调整位图的大小?【英文标题】:How to Resize a Bitmap in Android? 【发布时间】:2011-06-17 18:52:34 【问题描述】:我有一个从远程数据库中获取的 Base64 字符串的位图,(encodedImage
是表示带有 Base64 的图像的字符串):
profileImage = (ImageView)findViewById(R.id.profileImage);
byte[] imageAsBytes=null;
try
imageAsBytes = Base64.decode(encodedImage.getBytes());
catch (IOException e) e.printStackTrace();
profileImage.setImageBitmap(
BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)
);
profileImage 是我的 ImageView
好的,但我必须先调整此图像的大小,然后才能将其显示在我的布局的 ImageView
上。我必须将其调整为 120x120。
谁能告诉我调整大小的代码?
我找到的例子不能应用于base64字符串获取的位图。
【问题讨论】:
Resize Bitmap in android的可能重复 @SagarPilkhwal 这个是第一个被问到的 【参考方案1】:变化:
profileImage.setImageBitmap(
BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)
收件人:
Bitmap b = BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)
profileImage.setImageBitmap(Bitmap.createScaledBitmap(b, 120, 120, false));
【讨论】:
假设您有大分辨率图像,例如 1200x1200,当您显示此图像时,图像视图中将充满。如果我把它缩小说 75% 并且屏幕是这样它在 imageview 中也完全显示缩放的图像,对于这样的屏幕应该怎么做? createScaledBitmap 在我的 Galaxy Tab2 上抛出内存不足异常,这对我来说很奇怪,因为内存很大,并且没有其他特定的应用程序正在运行。 Matrix 解决方案虽然有效。 如果我们想保存纵横比怎么办?? 这个 dpi 缩放怎么样?我认为缩放的位图应该基于设备屏幕的高度和宽度? 使用 Bitmap.createScaledBitmap() 将图像缩小到原始大小的一半以上,会产生锯齿伪影。您可以查看我写的post,我在其中提出了一些替代方案并比较了质量和性能。【参考方案2】:import android.graphics.Matrix
public Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight)
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// CREATE A MATRIX FOR THE MANIPULATION
Matrix matrix = new Matrix();
// RESIZE THE BIT MAP
matrix.postScale(scaleWidth, scaleHeight);
// "RECREATE" THE NEW BITMAP
Bitmap resizedBitmap = Bitmap.createBitmap(
bm, 0, 0, width, height, matrix, false);
bm.recycle();
return resizedBitmap;
编辑:正如@aveschini 所建议的,我添加了bm.recycle();
以避免内存泄漏。请注意,如果您将前一个对象用于其他目的,请进行相应处理。
【讨论】:
我尝试了 bitmap.createscaledbitmap 和这种矩阵方法。我发现使用矩阵方法的图像更加清晰。我不知道这是否很常见,或者仅仅是因为我使用的是模拟器而不是手机。只是对像我一样遇到同样麻烦的人的提示。 这里你也必须添加 bm.recycle() 以获得更好的内存性能 感谢您的解决方案,但如果重新排序参数会更好;public Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight)
。我花了很长时间才弄清楚。 ;P
请注意,Matrix 的正确导入是 android.graphics.Matrix。
这与调用 Bitmap.createScaledBitmap() 相同。见android.googlesource.com/platform/frameworks/base/+/refs/heads/…【参考方案3】:
如果您已经有位图,可以使用以下代码调整大小:
Bitmap originalBitmap = <original initialization>;
Bitmap resizedBitmap = Bitmap.createScaledBitmap(
originalBitmap, newWidth, newHeight, false);
【讨论】:
@beginner 如果您调整图像大小,您可能会根据不同的尺寸进行缩放,从而将位图转换为不正确的比例或删除一些位图信息。 我尝试根据比例调整位图大小,但随后出现此错误。引起:java.lang.RuntimeException:Canvas:试图使用回收的位图android.graphics.Bitmap@2291dd13 @beginner 每次调整位图大小时,根据您的操作,您通常需要创建一个新大小的副本,而不是调整现有位图的大小(因为在这种情况下它看起来对位图的引用已经在内存中回收了)。 正确..我试过了,现在可以正常工作了。谢谢【参考方案4】:profileImage.setImageBitmap(
Bitmap.createScaledBitmap(
BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length),
80, 80, false
)
);
【讨论】:
【参考方案5】:试试这个代码:
BitmapDrawable drawable = (BitmapDrawable) imgview.getDrawable();
Bitmap bmp = drawable.getBitmap();
Bitmap b = Bitmap.createScaledBitmap(bmp, 120, 120, false);
希望对你有用。
【讨论】:
【参考方案6】:有人问这种情况下如何保持纵横比:
计算用于缩放的因子并将其用于两个维度。 假设您希望图像的高度为屏幕的 20%
int scaleToUse = 20; // this will be our percentage
Bitmap bmp = BitmapFactory.decodeResource(
context.getResources(), R.drawable.mypng);
int sizeY = screenResolution.y * scaleToUse / 100;
int sizeX = bmp.getWidth() * sizeY / bmp.getHeight();
Bitmap scaled = Bitmap.createScaledBitmap(bmp, sizeX, sizeY, false);
要获得屏幕分辨率,您有以下解决方案: Get screen dimensions in pixels
【讨论】:
【参考方案7】:基于纵横比的比例:
float aspectRatio = yourSelectedImage.getWidth() /
(float) yourSelectedImage.getHeight();
int width = 480;
int height = Math.round(width / aspectRatio);
yourSelectedImage = Bitmap.createScaledBitmap(
yourSelectedImage, width, height, false);
使用高度作为基础而不是宽度更改为:
int height = 480;
int width = Math.round(height * aspectRatio);
【讨论】:
【参考方案8】:试试这个:
此函数按比例调整位图大小。当最后一个参数设置为“X”时,newDimensionXorY
被视为新宽度,而当设置为“Y”时,新高度。
public Bitmap getProportionalBitmap(Bitmap bitmap,
int newDimensionXorY,
String XorY)
if (bitmap == null)
return null;
float xyRatio = 0;
int newWidth = 0;
int newHeight = 0;
if (XorY.toLowerCase().equals("x"))
xyRatio = (float) newDimensionXorY / bitmap.getWidth();
newHeight = (int) (bitmap.getHeight() * xyRatio);
bitmap = Bitmap.createScaledBitmap(
bitmap, newDimensionXorY, newHeight, true);
else if (XorY.toLowerCase().equals("y"))
xyRatio = (float) newDimensionXorY / bitmap.getHeight();
newWidth = (int) (bitmap.getWidth() * xyRatio);
bitmap = Bitmap.createScaledBitmap(
bitmap, newWidth, newDimensionXorY, true);
return bitmap;
【讨论】:
【参考方案9】:使用目标最大尺寸和宽度缩放位图,同时保持纵横比:
int maxHeight = 2000;
int maxWidth = 2000;
float scale = Math.min(((float)maxHeight / bitmap.getWidth()), ((float)maxWidth / bitmap.getHeight()));
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
【讨论】:
【参考方案10】:从 API 19 开始,存在位图 setWidth(int width) 和 setHeight(int height)。 http://developer.android.com/reference/android/graphics/Bitmap.html
【讨论】:
【参考方案11】: public Bitmap scaleBitmap(Bitmap mBitmap)
int ScaleSize = 250;//max Height or width to Scale
int width = mBitmap.getWidth();
int height = mBitmap.getHeight();
float excessSizeRatio = width > height ? width / ScaleSize : height / ScaleSize;
Bitmap bitmap = Bitmap.createBitmap(
mBitmap, 0, 0,(int) (width/excessSizeRatio),(int) (height/excessSizeRatio));
//mBitmap.recycle(); if you are not using mBitmap Obj
return bitmap;
【讨论】:
对我来说,它在重新输入 float extraSizeRatio = width > height 后工作了? (float)( (float)width / (float)ScaleSize) : (float)((float)height / (float)ScaleSize);【参考方案12】:根据任何显示尺寸调整位图大小
public Bitmap bitmapResize(Bitmap imageBitmap)
Bitmap bitmap = imageBitmap;
float heightbmp = bitmap.getHeight();
float widthbmp = bitmap.getWidth();
// Get Screen width
DisplayMetrics displaymetrics = new DisplayMetrics();
this.getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
float height = displaymetrics.heightPixels / 3;
float width = displaymetrics.widthPixels / 3;
int convertHeight = (int) hight, convertWidth = (int) width;
// higher
if (heightbmp > height)
convertHeight = (int) height - 20;
bitmap = Bitmap.createScaledBitmap(bitmap, convertWidth,
convertHighet, true);
// wider
if (widthbmp > width)
convertWidth = (int) width - 20;
bitmap = Bitmap.createScaledBitmap(bitmap, convertWidth,
convertHeight, true);
return bitmap;
【讨论】:
【参考方案13】:public static Bitmap resizeBitmapByScale(
Bitmap bitmap, float scale, boolean recycle)
int width = Math.round(bitmap.getWidth() * scale);
int height = Math.round(bitmap.getHeight() * scale);
if (width == bitmap.getWidth()
&& height == bitmap.getHeight()) return bitmap;
Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap));
Canvas canvas = new Canvas(target);
canvas.scale(scale, scale);
Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
canvas.drawBitmap(bitmap, 0, 0, paint);
if (recycle) bitmap.recycle();
return target;
private static Bitmap.Config getConfig(Bitmap bitmap)
Bitmap.Config config = bitmap.getConfig();
if (config == null)
config = Bitmap.Config.ARGB_8888;
return config;
【讨论】:
【参考方案14】:虽然接受的答案是正确的,但它不会通过保持相同的纵横比来调整Bitmap
的大小。如果您正在寻找一种通过保持相同纵横比来调整 Bitmap
大小的方法,您可以使用以下实用程序函数。函数的使用细节和解释见this link。
public static Bitmap resizeBitmap(Bitmap source, int maxLength)
try
if (source.getHeight() >= source.getWidth())
int targetHeight = maxLength;
if (source.getHeight() <= targetHeight) // if image already smaller than the required height
return source;
double aspectRatio = (double) source.getWidth() / (double) source.getHeight();
int targetWidth = (int) (targetHeight * aspectRatio);
Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
if (result != source)
return result;
else
int targetWidth = maxLength;
if (source.getWidth() <= targetWidth) // if image already smaller than the required height
return source;
double aspectRatio = ((double) source.getHeight()) / ((double) source.getWidth());
int targetHeight = (int) (targetWidth * aspectRatio);
Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
if (result != source)
return result;
catch (Exception e)
return source;
【讨论】:
【参考方案15】:/**
* Kotlin method for Bitmap scaling
* @param bitmap the bitmap to be scaled
* @param pixel the target pixel size
* @param width the width
* @param height the height
* @param max the max(height, width)
* @return the scaled bitmap
*/
fun scaleBitmap(bitmap:Bitmap, pixel:Float, width:Int, height:Int, max:Int):Bitmap
val scale = px / max
val h = Math.round(scale * height)
val w = Math.round(scale * width)
return Bitmap.createScaledBitmap(bitmap, w, h, true)
【讨论】:
【参考方案16】:保持纵横比,
public Bitmap resizeBitmap(Bitmap source, int width,int height)
if(source.getHeight() == height && source.getWidth() == width) return source;
int maxLength=Math.min(width,height);
try
source=source.copy(source.getConfig(),true);
if (source.getHeight() <= source.getWidth())
if (source.getHeight() <= maxLength) // if image already smaller than the required height
return source;
double aspectRatio = (double) source.getWidth() / (double) source.getHeight();
int targetWidth = (int) (maxLength * aspectRatio);
return Bitmap.createScaledBitmap(source, targetWidth, maxLength, false);
else
if (source.getWidth() <= maxLength) // if image already smaller than the required height
return source;
double aspectRatio = ((double) source.getHeight()) / ((double) source.getWidth());
int targetHeight = (int) (maxLength * aspectRatio);
return Bitmap.createScaledBitmap(source, maxLength, targetHeight, false);
catch (Exception e)
return source;
【讨论】:
【参考方案17】:虽然前面的答案确实会缩放图像并注意纵横比,但应该重新采样本身,以免出现锯齿。照顾规模是正确解决论点的问题。有许多关于标准缩放调用的输出图像质量的 cmets。为了保持图像质量,应该使用标准调用:
Bitmap resizedBitmap = Bitmap.createScaledBitmap(originalBitmap, newWidth, newHeight, true);
将最后一个参数设置为true
,因为它会对重采样进行双线性过滤以防止混叠。在此处阅读有关别名的更多信息:https://en.wikipedia.org/wiki/Aliasing
来自安卓文档:
https://developer.android.com/reference/android/graphics/Bitmap#createScaledBitmap(android.graphics.Bitmap,%20int,%20int,%20boolean)
public static Bitmap createScaledBitmap (Bitmap src,
int dstWidth,
int dstHeight,
boolean filter)
filter:布尔值,缩放位图时是否应使用双线性过滤。如果这是真的,那么在缩放时将使用双线性滤波,这会以更差的性能为代价获得更好的图像质量。如果这是错误的,则使用最近邻缩放代替,这将具有更差的图像质量但更快。推荐的默认设置是将过滤器设置为“真”,因为双线性过滤的成本通常是最小的,并且图像质量的提高是显着的。
【讨论】:
【参考方案18】:* For resize bitmap with width and height ratio.
public static Bitmap getResizedBitmap(Bitmap image, int maxSize)
int width = image.getWidth();
int height = image.getHeight();
float bitmapRatio = (float) width / (float) height;
if (bitmapRatio > 1)
width = maxSize;
height = (int) (width / bitmapRatio);
else
height = maxSize;
width = (int) (height * bitmapRatio);
return Bitmap.createScaledBitmap(image, width, height, true);
【讨论】:
【参考方案19】:应用 Matrix.ScaleToFit.CENTER) 获取新的位图保持纵横比。
public static Bitmap getScaledwonBitmap(Bitmap srcBmp, int deisredWidth, int desiredHeight)
Matrix matrix = new Matrix();
matrix.setRectToRect(new RectF(0, 0, srcBmp.getWidth(), srcBmp.getHeight()),
new RectF(0, 0, deisredWidth, desiredHeight),
Matrix.ScaleToFit.CENTER);
return Bitmap.createBitmap(srcBmp, 0, 0, srcBmp.getWidth(), srcBmp.getHeight(), matrix, true);
【讨论】:
以上是关于如何在 Android 中调整位图的大小?的主要内容,如果未能解决你的问题,请参考以下文章