发布之前减少图片的大小

我有一个函数将文件(来自相机或图库的图片)发送到WebService。 我想在发布之前减少fileUri的图像大小(每个例子50%)。 该文件是图库或相机图像。

这是我的postFile函数:

 public static void postFile(Context context, String url, String fileUri, AsyncHttpResponseHandler responseHandler) { if (myCookieStore == null) { myCookieStore = new PersistentCookieStore(context); client.setCookieStore(myCookieStore); } File myFile = new File(Uri.parse(fileUri).getPath()); RequestParams params = new RequestParams(); try { params.put("profile_picture", myFile); } catch(FileNotFoundException e) { Log.d("error", "error catch"); } Log.d("absolute url", "" + "*" + getAbsoluteUrl(url) + "*"); client.post(context, getAbsoluteUrl(url), params, responseHandler); } 

我怎样才能做到这一点 ?

有这个库,可以将你的图像从mb压缩到kb,它非常强大,我已经使用了很多次,它的工作文件上传是超快的。 链接

Snippet: compressedImageFile = Compressor.getDefault(this).compressToFile(actualImageFile);

它内部使用谷歌webp格式,WebP是一种现代图像格式,可为网络上的图像提供卓越的无损和有损压缩。 使用WebP,网站管理员和Web开发人员可以创建更小,更丰富的图像,使网络更快。

该库非常适合大小压缩,它做得非常好,基于我的观察的大型文件,如2mb up,但是你需要解决一些内存泄漏,我通过使用泄漏金丝雀解决了我的问题,尽管每个开发人员都应该使用它。 总的来说,这是非常棒的叉子,请随便使用。

我们从图库中捕获或拍摄的图像太大。现在图像大小甚至超过10 MB。 因此,在应用程序中使用压缩图像非常重要,因为我们可能面临内存不足exception。

使用下面的代码来压缩图像

 // return file name of compressed image from imageUri public String compressImage(String imageUri) { String filePath = getRealPathFromURI(imageUri); Bitmap scaledBitmap = null; BitmapFactory.Options options = new BitmapFactory.Options(); // by setting this field as true, the actual bitmap pixels are not loaded in the memory. Just the bounds are loaded. If // you try the use the bitmap here, you will get null. options.inJustDecodeBounds = true; Bitmap bmp = BitmapFactory.decodeFile(filePath, options); int actualHeight = options.outHeight; int actualWidth = options.outWidth; // max Height and width values of the compressed image is taken as 816x612 float maxHeight = 816.0f; float maxWidth = 612.0f; float imgRatio = actualWidth / actualHeight; float maxRatio = maxWidth / maxHeight; // width and height values are set maintaining the aspect ratio of the image if (actualHeight > maxHeight || actualWidth > maxWidth) { if (imgRatio < maxRatio) { imgRatio = maxHeight / actualHeight; actualWidth = (int) (imgRatio * actualWidth); actualHeight = (int) maxHeight; } else if (imgRatio > maxRatio) { imgRatio = maxWidth / actualWidth; actualHeight = (int) (imgRatio * actualHeight); actualWidth = (int) maxWidth; } else { actualHeight = (int) maxHeight; actualWidth = (int) maxWidth; } } // setting inSampleSize value allows to load a scaled down version of the original image options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight); // inJustDecodeBounds set to false to load the actual bitmap options.inJustDecodeBounds = false; // this options allow android to claim the bitmap memory if it runs low on memory options.inPurgeable = true; options.inInputShareable = true; options.inTempStorage = new byte[16 * 1024]; try { // load the bitmap from its path bmp = BitmapFactory.decodeFile(filePath, options); } catch (OutOfMemoryError exception) { exception.printStackTrace(); } try { scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight,Bitmap.Config.ARGB_8888); } catch (OutOfMemoryError exception) { exception.printStackTrace(); } float ratioX = actualWidth / (float) options.outWidth; float ratioY = actualHeight / (float) options.outHeight; float middleX = actualWidth / 2.0f; float middleY = actualHeight / 2.0f; Matrix scaleMatrix = new Matrix(); scaleMatrix.setScale(ratioX, ratioY, middleX, middleY); Canvas canvas = new Canvas(scaledBitmap); canvas.setMatrix(scaleMatrix); canvas.drawBitmap(bmp, middleX - bmp.getWidth() / 2, middleY - bmp.getHeight() / 2, new Paint(Paint.FILTER_BITMAP_FLAG)); // check the rotation of the image and display it properly ExifInterface exif; try { exif = new ExifInterface(filePath); int orientation = exif.getAttributeInt( ExifInterface.TAG_ORIENTATION, 0); Log.d("EXIF", "Exif: " + orientation); Matrix matrix = new Matrix(); if (orientation == 6) { matrix.postRotate(90); Log.d("EXIF", "Exif: " + orientation); } else if (orientation == 3) { matrix.postRotate(180); Log.d("EXIF", "Exif: " + orientation); } else if (orientation == 8) { matrix.postRotate(270); Log.d("EXIF", "Exif: " + orientation); } scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true); } catch (IOException e) { e.printStackTrace(); } FileOutputStream out = null; String filename = getFilename(); try { out = new FileOutputStream(filename); // write the compressed bitmap at the destination specified by filename. scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out); } catch (FileNotFoundException e) { e.printStackTrace(); } return filename; } 

方法getFilename()::它在SDCard中创建一个用于存储图像的文件夹。

 public String getFilename() { File file = new File(Environment.getExternalStorageDirectory().getPath(), "MyFolder/Images"); if (!file.exists()) { file.mkdirs(); } String uriSting = (file.getAbsolutePath() + "/" + System.currentTimeMillis() + ".jpg"); return uriSting; } 

方法getRealPathFromURI(imageUri)::从其contentUri ::给出图像的实际文件路径::

 private String getRealPathFromURI(String contentURI) { Uri contentUri = Uri.parse(contentURI); Cursor cursor = getContentResolver().query(contentUri, null, null, null, null); if (cursor == null) { return contentUri.getPath(); } else { cursor.moveToFirst(); int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); return cursor.getString(index); } } 

方法calculateInSampleSize ::根据实际和所需维度计算inSampleSize的正确值:

 public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int heightRatio = Math.round((float) height/ (float) reqHeight); final int widthRatio = Math.round((float) width / (float) reqWidth); inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; } final float totalPixels = width * height; final float totalReqPixelsCap = reqWidth * reqHeight * 2; while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) { inSampleSize++; } return inSampleSize; } 

希望这些能帮到你。

我在许多项目中使用了这个代码并且它总是给我很好的结果,我记得如果我选择大小为5-7MB的图像(来自12/13 MP相机的图像),此代码返回大小为1MB或小于2MB的图像。

 public static boolean validateUri(Uri uri) { if (uri == null) return false; else { String path = uri.getPath(); return !(uri.equals(Uri.EMPTY) || path == null || path.equals("null")); } } 

首先,我们需要一个完整的图像并根据需要旋转。

 public static Bitmap getFullSizeImage(Context context, Uri uri) { String filePath; if (validateUri(uri) && uri.toString().contains("file")) filePath = uri.getPath(); else filePath = getRealPathFromURI(context, uri, MediaStore.Images.Media.DATA); if (filePath == null) return null; try { int rotation = 0; ExifInterface exifInterface = new ExifInterface(filePath); int exifRotation = exifInterface.getAttributeInt( ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); if (exifRotation != ExifInterface.ORIENTATION_UNDEFINED) { switch (exifRotation) { case ExifInterface.ORIENTATION_ROTATE_180: rotation = 180; break; case ExifInterface.ORIENTATION_ROTATE_270: rotation = 270; break; case ExifInterface.ORIENTATION_ROTATE_90: rotation = 90; break; } } Matrix matrix = new Matrix(); matrix.setRotate(rotation); // you can use other than 400 as required width/height Bitmap sourceBitmap = getBitmapFromPath(400, filePath); if (sourceBitmap == null) return null; return Bitmap.createBitmap(sourceBitmap, 0, 0, sourceBitmap.getWidth(), sourceBitmap.getHeight(), matrix, true); } catch (IOException e) { e.printStackTrace(); } return null; } 

现在我们需要一个来自URI的真实路径

 public static String getRealPathFromURI(Context context, Uri contentUri, String type) { Cursor cursor = null; String path = null; try { // String[] proj = { MediaStore.Images.Media.DATA }; String[] projection = {type}; cursor = context.getContentResolver().query(contentUri, projection, null, null, null); if (cursor == null) return null; int columnIndex = cursor.getColumnIndexOrThrow(type); cursor.moveToFirst(); path = cursor.getString(columnIndex); // we choose image from drive etc. if (path == null) path = getDocumentRealPathFromUri(context, contentUri); } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) cursor.close(); } return path; } 

如果我们从驱动器等中选择图片,我们仍然需要给定URI的真实路径

 public static String getDocumentRealPathFromUri(Context context, Uri contentUri) { Cursor cursor = context.getContentResolver().query(contentUri, null, null, null, null); if (cursor == null) return null; cursor.moveToFirst(); String documentId = cursor.getString(0); documentId = documentId.substring(documentId.lastIndexOf(":") + 1); cursor.close(); cursor = context.getContentResolver().query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Images.Media._ID + " = ? ", new String[]{documentId}, null); if (cursor == null) return null; cursor.moveToFirst(); String path = cursor.getString(cursor .getColumnIndex(MediaStore.Images.Media.DATA)); cursor.close(); return path; } 

现在我们有一个选定图像的真实路径,因此我们可以使用样本大小从此路径获取位图

 public static Bitmap getBitmapFromPath(int size, String realPathFromURI) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(realPathFromURI, options); options.inSampleSize = calculateInSampleSizeUsingPower2(options, size, size); options.inJustDecodeBounds = false; return BitmapFactory.decodeFile(realPathFromURI, options); } public static int calculateInSampleSizeUsingPower2(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; } 

此时我们有一个压缩位图,如果我们在给定位图上执行Base64操作,我们还可以再次压缩这个位图。

 public static String convertToBase64(Bitmap bitmap) { if (bitmap == null) return null; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream)) { String base64 = encodeToString(byteArrayOutputStream.toByteArray(), DEFAULT); try { byteArrayOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } return base64; } return null; } 

在服务器端,您可以解码Base64并转换回文件流并保存您的图像。

 Bitmap bitmap = getFullSizeImage(context, selectedPhotoUri); if(bitmap != null){ String base64Image = convertToBase64(bitmap); if (base64Image != null) { RequestParams params = new RequestParams(); try { params.put("title", "your_image_name"); params.put("profile_picture", base64Image); } catch(FileNotFoundException e) { Log.d("error", "error catch"); } } } 

注意如果您不想执行Base64,可以使用位图转换为流并将其发送到服务器。

使用此选项可更改图像宽度和高度

 public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) { int width = bm.getWidth(); int height = bm.getHeight(); float scaleWidth = ((float) newWidth) / width; float scaleHeight = ((float) newHeight) / height; Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false); return resizedBitmap; } 

你可以用这个改变大小…这是最好的例子…..

  private Bitmap decodeFile(File f){ try { //Decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeStream(new FileInputStream(f),null,o); //The new size we want to scale to final int REQUIRED_SIZE=70; //Find the correct scale value. It should be the power of 2. int scale=1; while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE) scale*=2; //Decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize=scale; return BitmapFactory.decodeStream(new FileInputStream(f), null, o2); } catch (FileNotFoundException e) {} return null; } 

试试这个函数。如果位图的宽度或高度大于512,它会将位图的大小减小到512

 public static Bitmap resizeBitmap(Bitmap bm) { if (bm.getWidth() > maxSize || bm.getHeight() > maxSize) { if (bm.getWidth() > bm.getHeight()) { newWidth = maxSize; newHeight = (bm.getHeight() * maxSize) / bm.getWidth(); bm = Bitmap.createScaledBitmap(bm, newHeight, newWidth, true); return bm; } else { newHeight = maxSize; newWidth = (bm.getWidth() * maxSize) / bm.getHeight(); bm = Bitmap.createScaledBitmap(bm, newHeight, newWidth, true); return bm; } } return bm; } 

您只需将位图传递给此方法即可。

从URI获取位图的方法是

 BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 8; bitmap = BitmapFactory.decodeFile(fileUri.getPath(), options); 

如果摄像机图像是JPEG,则可以使用位图压缩方法,如:

 Bitmap bitmap = BitmapFactory.decodeStream(...uri); ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { int compression_factor = 50; // represents 50% compression bitmap.compress(Bitmap.CompressFormat.JPEG, compression_factor, baos); byte[] image = baos.toByteArray(); // now update web service asynchronously... ... } finally { baos.close(); } 

将图像转换为位图,然后使用以下方法

  public static Bitmap scaleBitmap(Bitmap bitmap, int newWidth, int newHeight) { Bitmap scaledBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888); float scaleX = newWidth / (float) bitmap.getWidth(); float scaleY = newHeight / (float) bitmap.getHeight(); float pivotX = 0; float pivotY = 0; Matrix scaleMatrix = new Matrix(); scaleMatrix.setScale(scaleX, scaleY, pivotX, pivotY); Canvas canvas = new Canvas(scaledBitmap); canvas.setMatrix(scaleMatrix); canvas.drawBitmap(bitmap, 0, 0, new Paint(Paint.FILTER_BITMAP_FLAG)); return scaledBitmap; }