Man*_*uel 214 android resize image bitmap
我在一个文件中有一个大位图(比如3888x2592).现在,我想将该位图的大小调整为800x533并将其保存到另一个文件中.我通常会通过调用Bitmap.createBitmap方法来缩放位图,但它需要一个源位图作为第一个参数,我无法提供,因为将原始图像加载到Bitmap对象当然会超出内存(例如,请参见此处).
我也无法读取位图,例如,BitmapFactory.decodeFile(file, options)提供a BitmapFactory.Options.inSampleSize,因为我想将其调整为精确的宽度和高度.使用inSampleSize会将位图的大小调整为972x648(如果我使用inSampleSize=4)或778x518(如果我使用inSampleSize=5,它甚至不是2的幂).
我还想避免使用inSampleSize在第一步中使用例如972x648读取图像,然后在第二步中将其大小调整为800x533,因为与直接调整原始图像大小相比,质量会很差.
总结我的问题:是否有办法读取10MP或更高的大图像文件并将其保存到新的图像文件,调整大小到特定的新宽度和高度,而不会得到OutOfMemory异常?
我也尝试BitmapFactory.decodeFile(file, options)手动将Options.outHeight和Options.outWidth值设置为800和533,但它不起作用.
Jus*_*tin 144
不, 我喜欢有人纠正我,但我接受了你尝试作为妥协的加载/调整大小的方法.
以下是任何人浏览的步骤:
inSampleSize仍然产生大于目标的图像的最大可能值.BitmapFactory.decodeFile(file, options)传入inSampleSize作为选项加载图像.Bitmap.createScaledBitmap().小智 96
贾斯汀回答翻译成代码(对我来说很完美):
private Bitmap getBitmap(String path) {
Uri uri = getImageUri(path);
InputStream in = null;
try {
final int IMAGE_MAX_SIZE = 1200000; // 1.2MP
in = mContentResolver.openInputStream(uri);
// Decode image size
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, options);
in.close();
int scale = 1;
while ((options.outWidth * options.outHeight) * (1 / Math.pow(scale, 2)) >
IMAGE_MAX_SIZE) {
scale++;
}
Log.d(TAG, "scale = " + scale + ", orig-width: " + options.outWidth + ",
orig-height: " + options.outHeight);
Bitmap resultBitmap = null;
in = mContentResolver.openInputStream(uri);
if (scale > 1) {
scale--;
// scale to max possible inSampleSize that still yields an image
// larger than target
options = new BitmapFactory.Options();
options.inSampleSize = scale;
resultBitmap = BitmapFactory.decodeStream(in, null, options);
// resize to desired dimensions
int height = resultBitmap.getHeight();
int width = resultBitmap.getWidth();
Log.d(TAG, "1th scale operation dimenions - width: " + width + ",
height: " + height);
double y = Math.sqrt(IMAGE_MAX_SIZE
/ (((double) width) / height));
double x = (y / height) * width;
Bitmap scaledBitmap = Bitmap.createScaledBitmap(resultBitmap, (int) x,
(int) y, true);
resultBitmap.recycle();
resultBitmap = scaledBitmap;
System.gc();
} else {
resultBitmap = BitmapFactory.decodeStream(in);
}
in.close();
Log.d(TAG, "bitmap size - width: " +resultBitmap.getWidth() + ", height: " +
resultBitmap.getHeight());
return resultBitmap;
} catch (IOException e) {
Log.e(TAG, e.getMessage(),e);
return null;
}
Run Code Online (Sandbox Code Playgroud)
小智 43
这是'Mojo Risin'和'Ofir'的解决方案"合并".这将为您提供按比例调整大小的图像,其中包含最大宽度和最大高度的边界.
对我而言,它在下面的5兆像素图像上表现良好.
try
{
int inWidth = 0;
int inHeight = 0;
InputStream in = new FileInputStream(pathOfInputImage);
// decode image size (decode metadata only, not the whole image)
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, options);
in.close();
in = null;
// save width and height
inWidth = options.outWidth;
inHeight = options.outHeight;
// decode full image pre-resized
in = new FileInputStream(pathOfInputImage);
options = new BitmapFactory.Options();
// calc rought re-size (this is no exact resize)
options.inSampleSize = Math.max(inWidth/dstWidth, inHeight/dstHeight);
// decode full image
Bitmap roughBitmap = BitmapFactory.decodeStream(in, null, options);
// calc exact destination size
Matrix m = new Matrix();
RectF inRect = new RectF(0, 0, roughBitmap.getWidth(), roughBitmap.getHeight());
RectF outRect = new RectF(0, 0, dstWidth, dstHeight);
m.setRectToRect(inRect, outRect, Matrix.ScaleToFit.CENTER);
float[] values = new float[9];
m.getValues(values);
// resize bitmap
Bitmap resizedBitmap = Bitmap.createScaledBitmap(roughBitmap, (int) (roughBitmap.getWidth() * values[0]), (int) (roughBitmap.getHeight() * values[4]), true);
// save image
try
{
FileOutputStream out = new FileOutputStream(pathOfOutputImage);
resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
}
catch (Exception e)
{
Log.e("Image", e.getMessage(), e);
}
}
catch (IOException e)
{
Log.e("Image", e.getMessage(), e);
}
Run Code Online (Sandbox Code Playgroud)
Ale*_*lex 22
到目前为止,承认另一个优秀的答案,我已经看到的最好的代码是在照片拍摄工具的文档中.
请参阅标题为"解码缩放图像"的部分.
http://developer.android.com/training/camera/photobasics.html
它提出的解决方案是像这里的其他解决方案那样调整大小的解决方案,但它非常整洁.
为方便起见,我将下面的代码复制为随时可用的功能.
private void setPic(String imagePath, ImageView destination) {
int targetW = destination.getWidth();
int targetH = destination.getHeight();
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imagePath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(imagePath, bmOptions);
destination.setImageBitmap(bitmap);
}
Run Code Online (Sandbox Code Playgroud)
Bos*_*one 21
为什么不使用API?
int h = 48; // height in pixels
int w = 48; // width in pixels
Bitmap scaled = Bitmap.createScaledBitmap(largeBitmap, w, h, true);
Run Code Online (Sandbox Code Playgroud)
pen*_*Dev 19
在阅读这些答案和Android文档后,这里是调整位图大小而不将其加载到内存中的代码:
public Bitmap getResizedBitmap(int targetW, int targetH, String imagePath) {
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
//inJustDecodeBounds = true <-- will not load the bitmap into memory
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imagePath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(imagePath, bmOptions);
return(bitmap);
}
Run Code Online (Sandbox Code Playgroud)
当我有大位图,我想解码它们调整大小时我使用以下
BitmapFactory.Options options = new BitmapFactory.Options();
InputStream is = null;
is = new FileInputStream(path_to_file);
BitmapFactory.decodeStream(is,null,options);
is.close();
is = new FileInputStream(path_to_file);
// here w and h are the desired width and height
options.inSampleSize = Math.max(options.outWidth/w, options.outHeight/h);
// bitmap is the resized bitmap
Bitmap bitmap = BitmapFactory.decodeStream(is,null,options);
Run Code Online (Sandbox Code Playgroud)
这对于查看此问题的其他人可能很有用.我重写了Justin的代码,以允许该方法接收所需的目标大小对象.这在使用Canvas时非常有效.所有的功劳都应归功于JUSTIN的优秀初始代码.
private Bitmap getBitmap(int path, Canvas canvas) {
Resources resource = null;
try {
final int IMAGE_MAX_SIZE = 1200000; // 1.2MP
resource = getResources();
// Decode image size
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(resource, path, options);
int scale = 1;
while ((options.outWidth * options.outHeight) * (1 / Math.pow(scale, 2)) >
IMAGE_MAX_SIZE) {
scale++;
}
Log.d("TAG", "scale = " + scale + ", orig-width: " + options.outWidth + ", orig-height: " + options.outHeight);
Bitmap pic = null;
if (scale > 1) {
scale--;
// scale to max possible inSampleSize that still yields an image
// larger than target
options = new BitmapFactory.Options();
options.inSampleSize = scale;
pic = BitmapFactory.decodeResource(resource, path, options);
// resize to desired dimensions
int height = canvas.getHeight();
int width = canvas.getWidth();
Log.d("TAG", "1th scale operation dimenions - width: " + width + ", height: " + height);
double y = Math.sqrt(IMAGE_MAX_SIZE
/ (((double) width) / height));
double x = (y / height) * width;
Bitmap scaledBitmap = Bitmap.createScaledBitmap(pic, (int) x, (int) y, true);
pic.recycle();
pic = scaledBitmap;
System.gc();
} else {
pic = BitmapFactory.decodeResource(resource, path);
}
Log.d("TAG", "bitmap size - width: " +pic.getWidth() + ", height: " + pic.getHeight());
return pic;
} catch (Exception e) {
Log.e("TAG", e.getMessage(),e);
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
Justin的代码非常有效地减少了使用大型Bitmaps的开销.