在android中减小从相机捕获的图像的大小
Posted
技术标签:
【中文标题】在android中减小从相机捕获的图像的大小【英文标题】:Reduce size of captured image from camera in android 【发布时间】:2014-01-03 15:54:59 【问题描述】:在这里,我将拍摄的图像从相机保存在 sdcard 上。在这里,捕获的图像大小大于1 MB
。在保存到 sdcard 之前,我想将此大小减小到近 500kb 到 600kb。我怎么能这样做?
try
Bitmap mPhoto;
mPhoto = android.provider.MediaStore.Images.Media.getBitmap(cr, CheckInGallery.mUri);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
mPhoto.compress(Bitmap.CompressFormat.PNG, 100, bytes);
File direct = new File(Environment.getExternalStorageDirectory() + "/RetailRun");
String mydate = java.text.DateFormat.getDateTimeInstance().format(Calendar.getInstance().getTime());
Toast.makeText(getBaseContext(), "Time :" + mydate, 5000).show();
if(!direct.exists())
direct.mkdir();
File file = new File(Environment.getExternalStorageDirectory()+File.separator + "/MyImage/image" + mydate +".jpg");
file.createNewFile();
FileOutputStream fo = new FileOutputStream(file);
fo.write(bytes.toByteArray());
fo.close();
else
File file = new File(Environment.getExternalStorageDirectory()+File.separator + "/MyImage/image" + mydate +".jpg");
file.createNewFile();
FileOutputStream fo = new FileOutputStream(file);
fo.write(bytes.toByteArray());
fo.close();
catch (Exception e)
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
【问题讨论】:
【参考方案1】:mPhoto.compress(Bitmap.CompressFormat.PNG, 100, bytes);
100 在这个是最好的质量。如果您想减小尺寸,请尝试减小该值
其他方法可能是使用 BitmapFactory.Options() 的 inSampleSize 参数。那也应该减小尺寸。你可以读到here
编辑: 一些代码
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize=2; //4, 8, etc. the more value, the worst quality of image
Bitmap bmp=BitmapFactory.decodeStream(getContentResolver().openInputStream(CheckInGallery.mUri), null, options);
这应该加载质量稍差的图像。
然后保存图片
bmp.compress(Bitmap.CompressFormat.PNG, 70, bytes);
【讨论】:
表示我应该尝试使用少于 100 个,例如 80 或 70 个?? 是的,这应该会有所帮助 所以尝试第二种方法并阅读 BitmapFactory.Options() 的 inSampleSize 参数。这也应该减少位图的大小。见我上面的编辑 来自 Bitmap.CompressFormat 文档 -> 一些格式,例如无损的 PNG,将忽略质量设置。尝试使用另一种格式,例如 JPEG【参考方案2】:这对我有用。
public void onImageSelected()
Uri uri=null; // get the uri of the image result from the intent
try
Bitmap bitmap = handleSamplingAndRotationBitmap(this, uri);
byte[] bytes = getBytesFromBitmap(bitmap);
//getPresenter.upload(bytes);
catch (IOException e)
e.printStackTrace();
/**
* returns an aligned bitmap with size not exceeding the MAX_HEIGHT
* @param context
* @param selectedImage
* @return
* @throws IOException
*/
public Bitmap handleSamplingAndRotationBitmap(Context context, Uri selectedImage)
throws IOException
Bitmap decoded = getImageSampleOutput(context,selectedImage);
decoded = rotateImageIfRequired(this, decoded, selectedImage);
return decoded;
public Bitmap getImageSampleOutput(Context context, Uri selectedImage) throws IOException
int MAX_HEIGHT = 1200;
int MAX_WIDTH = 1600;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
InputStream imageStream = context.getContentResolver().openInputStream(selectedImage);
BitmapFactory.decodeStream(imageStream, null, options);
imageStream.close();
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, MAX_WIDTH, MAX_HEIGHT);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
imageStream = context.getContentResolver().openInputStream(selectedImage);
Bitmap img = BitmapFactory.decodeStream(imageStream, null, options);
Bitmap decoded = compressImage(img);
return decoded;
/**
* Used to compress the image to prevent any Memory overflows.
* @param bitmap
* @return
*/
public Bitmap compressImage(Bitmap bitmap)
ByteArrayOutputStream out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
return BitmapFactory.decodeStream(new ByteArrayInputStream(out.toByteArray()));
private 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)
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee a final image
// with both dimensions larger than or equal to the requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
// This offers some additional logic in case the image has a strange
// aspect ratio. For example, a panorama may have a much larger
// width than height. In these cases the total pixels might still
// end up being too large to fit comfortably in memory, so we should
// be more aggressive with sample down the image (=larger inSampleSize).
final float totalPixels = width * height;
// Anything more than 2x the requested pixels we'll sample down further
final float totalReqPixelsCap = reqWidth * reqHeight * 2;
while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap)
inSampleSize++;
return inSampleSize;
private static Bitmap rotateImageIfRequired(Context context, Bitmap img, Uri selectedImage)
// Detect rotation
int rotation = getRotation(context, selectedImage);
if (rotation != 0)
Matrix matrix = new Matrix();
matrix.postRotate(rotation);
Bitmap rotatedImg = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);
img.recycle();
return rotatedImg;
else
return img;
/**
* Get the rotation of the last image added.
*
* @param context
* @param selectedImage
* @return
*/
private static int getRotation(Context context, Uri selectedImage)
int rotation = 0;
ContentResolver content = context.getContentResolver();
Cursor mediaCursor = content.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[]"orientation", "date_added",
null, null, "date_added desc");
if (mediaCursor != null && mediaCursor.getCount() != 0)
while (mediaCursor.moveToNext())
rotation = mediaCursor.getInt(0);
break;
mediaCursor.close();
return rotation;
public byte[] getBytesFromBitmap(Bitmap bmp)
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.JPEG,70,stream);
byte[] byteArray = stream.toByteArray();
return byteArray;
在三星 Galaxy S7 上,我能够将大小减小到 300kb。
【讨论】:
有时三星Galaxy S7是用来缩小身体部位的...所以我们应该在缩小尺寸之前检查一个条件以限制最小尺寸...【参考方案3】:设置位图的高度和宽度是特定于设备的...
@SuppressLint("NewApi")
public static int getDeviceWidth(Activity activity)
int deviceWidth = 0;
Point size = new Point();
WindowManager windowManager = activity.getWindowManager();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
windowManager.getDefaultDisplay().getSize(size);
deviceWidth = size.x;
else
Display display = windowManager.getDefaultDisplay();
deviceWidth = display.getWidth();
return deviceWidth;
@SuppressLint("NewApi")
public static int getDeviceHeight(Activity activity)
int deviceHeight = 0;
Point size = new Point();
WindowManager windowManager = activity.getWindowManager();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
windowManager.getDefaultDisplay().getSize(size);
deviceHeight = size.y;
else
Display display = windowManager.getDefaultDisplay();
deviceHeight = display.getHeight();
return deviceHeight;
此方法可减小图像大小。它在我的项目中起作用。
【讨论】:
请看这个问题:***.com/questions/31646619/…【参考方案4】:**Reduce captured image size and save ..in kb**
String imagePath = context.getFilesDir().getAbsolutePath() + File.separatorChar + "FolderName" + File.separatorChar + "ImageFolder" + File.separatorChar + imageName + ".jpg";
File prescImagefile = new File(imagePath);
try
if (prescImagefile.exists() == false)
prescImagefile.getParentFile().mkdirs();
prescImagefile.createNewFile();
catch (IOException e)
// Log.e("TAG", "Could not create file.", e);
if (prescImagefile != null)
mCapturedImageURI = Uri.fromFile(prescImagefile);
if (mCapturedImageURI != null)
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCapturedImageURI);
startActivityForResult(cameraIntent, CAMERA_REQUEST);
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
if (resultCode == RESULT_OK)
if (requestCode == CAMERA_REQUEST)
try
String path = mCapturedImageURI.getPath();
StoreImage(context, mCapturedImageURI, prescImagefile);
catch (Exception e)
e.printStackTrace();
public static void StoreImage(Context mContext, Uri imgUri, File imageDir)
Bitmap bm = null;
try
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
// bm = Media.getBitmap(mContext.getContentResolver(), imageLoc);
bm = BitmapFactory.decodeStream(mContext.getContentResolver().openInputStream(imgUri), null, options);
FileOutputStream out = new FileOutputStream(imageDir);
bm.compress(Bitmap.CompressFormat.JPEG, 20, out);
bm.recycle();
catch (Exception e)
e.printStackTrace();
【讨论】:
【参考方案5】:在阅读了其他答案并没有找到我想要的东西之后,这是我获取适当缩放位图的方法。这是对 Prabu 答案的改编。
它确保您的图片以不变形照片尺寸的方式缩放:
public saveScaledPhotoToFile()
//Convert your photo to a bitmap
Bitmap photoBm = (Bitmap) "your Bitmap image";
//get its orginal dimensions
int bmOriginalWidth = photoBm.getWidth();
int bmOriginalHeight = photoBm.getHeight();
double originalWidthToHeightRatio = 1.0 * bmOriginalWidth / bmOriginalHeight;
double originalHeightToWidthRatio = 1.0 * bmOriginalHeight / bmOriginalWidth;
//choose a maximum height
int maxHeight = 1024;
//choose a max width
int maxWidth = 1024;
//call the method to get the scaled bitmap
photoBm = getScaledBitmap(photoBm, bmOriginalWidth, bmOriginalHeight,
originalWidthToHeightRatio, originalHeightToWidthRatio,
maxHeight, maxWidth);
/**********THE REST OF THIS IS FROM Prabu's answer*******/
//create a byte array output stream to hold the photo's bytes
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
//compress the photo's bytes into the byte array output stream
photoBm.compress(Bitmap.CompressFormat.JPEG, 40, bytes);
//construct a File object to save the scaled file to
File f = new File(Environment.getExternalStorageDirectory()
+ File.separator + "Imagename.jpg");
//create the file
f.createNewFile();
//create an FileOutputStream on the created file
FileOutputStream fo = new FileOutputStream(f);
//write the photo's bytes to the file
fo.write(bytes.toByteArray());
//finish by closing the FileOutputStream
fo.close();
private static Bitmap getScaledBitmap(Bitmap bm, int bmOriginalWidth, int bmOriginalHeight, double originalWidthToHeightRatio, double originalHeightToWidthRatio, int maxHeight, int maxWidth)
if(bmOriginalWidth > maxWidth || bmOriginalHeight > maxHeight)
Log.v(TAG, format("RESIZING bitmap FROM %sx%s ", bmOriginalWidth, bmOriginalHeight));
if(bmOriginalWidth > bmOriginalHeight)
bm = scaleDeminsFromWidth(bm, maxWidth, bmOriginalHeight, originalHeightToWidthRatio);
else if (bmOriginalHeight > bmOriginalWidth)
bm = scaleDeminsFromHeight(bm, maxHeight, bmOriginalHeight, originalWidthToHeightRatio);
Log.v(TAG, format("RESIZED bitmap TO %sx%s ", bm.getWidth(), bm.getHeight()));
return bm;
private static Bitmap scaleDeminsFromHeight(Bitmap bm, int maxHeight, int bmOriginalHeight, double originalWidthToHeightRatio)
int newHeight = (int) Math.max(maxHeight, bmOriginalHeight * .55);
int newWidth = (int) (newHeight * originalWidthToHeightRatio);
bm = Bitmap.createScaledBitmap(bm, newWidth, newHeight, true);
return bm;
private static Bitmap scaleDeminsFromWidth(Bitmap bm, int maxWidth, int bmOriginalWidth, double originalHeightToWidthRatio)
//scale the width
int newWidth = (int) Math.max(maxWidth, bmOriginalWidth * .75);
int newHeight = (int) (newWidth * originalHeightToWidthRatio);
bm = Bitmap.createScaledBitmap(bm, newWidth, newHeight, true);
return bm;
这是我的 GitHub Gist 的相应链接:https://gist.github.com/Lwdthe1/2d1cd0a12f30c18db698
【讨论】:
以上是关于在android中减小从相机捕获的图像的大小的主要内容,如果未能解决你的问题,请参考以下文章
如何在不损失 Android 分辨率的情况下减小位图的大小?