android减少摄像头捕获图像的文件大小小于500 kb

时间:2016-05-18 12:21:37

标签: android image filesize android-camera-intent onactivityresult

我的要求是将摄像头捕获的图像上传到服务器,但它应该小于500 KB。如果它大于500 KB,则需要将其缩小到小于500 KB (但稍微靠近它)

为此,我使用以下代码 -

import sys

while True:
    print sys.argv

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        try {
            super.onActivityResult(requestCode, resultCode, data);
            if (resultCode == getActivity().RESULT_OK) {

                    if (requestCode == REQUEST_CODE_CAMERA) {

                        try {

                            photo = MediaStore.Images.Media.getBitmap(
                                    ctx.getContentResolver(), capturedImageUri);
                            String selectedImagePath = getRealPathFromURI(capturedImageUri);

                            img_file = new File(selectedImagePath);

                            Log.d("img_file_size", "file size in KBs (initially): " + (img_file.length()/1000));

                            if(CommonUtilities.isImageFileSizeGreaterThan500KB(img_file)) {
                                photo = CommonUtilities.getResizedBitmapLessThan500KB(photo, 500);
                            }
                            photo = CommonUtilities.getCorrectBitmap(photo, selectedImagePath);


//  // CALL THIS METHOD TO GET THE URI FROM THE BITMAP

                            img_file = new File(ctx.getCacheDir(), "image.jpg");
                            img_file.createNewFile();

//Convert bitmap to byte array
                            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
                            photo.compress(Bitmap.CompressFormat.JPEG, 100, bytes);

//write the bytes in file
                            FileOutputStream fo = new FileOutputStream(img_file);
                            fo.write(bytes.toByteArray());

// remember close de FileOutput
                            fo.close();
                            Log.d("img_file_size", "file size in KBs after image manipulations: " + (img_file.length()/1000));


                        } catch (Exception e) {
                            Logs.setLogException(class_name, "onActivityResult(), when captured from camera", e);
                        }


                    } 

            }
        } catch (Exception e) {
            Logs.setLogException(class_name, "onActivityResult()", e);
        } catch (OutOfMemoryError e) {
            Logs.setLogError(class_name, "onActivityResult()", e);

        }
    }

如果需要,旋转图像。

public static Bitmap getResizedBitmapLessThan500KB(Bitmap image, int maxSize) {
        int width = image.getWidth();
        int height = image.getHeight();



        float bitmapRatio = (float)width / (float) height;
        if (bitmapRatio > 0) {
            width = maxSize;
            height = (int) (width / bitmapRatio);
        } else {
            height = maxSize;
            width = (int) (height * bitmapRatio);
        }
        Bitmap reduced_bitmap = Bitmap.createScaledBitmap(image, width, height, true);
        if(sizeOf(reduced_bitmap) > (500 * 1000)) {
            return getResizedBitmap(reduced_bitmap, maxSize);
        } else {
            return reduced_bitmap;
        }
    }

这是最初和在减少文件大小的所有操作之后输出的图像文件大小。

  

img_file_size:文件大小(KBs)(最初):3294

     

img_file_size:图像处理后的文件大小(KB):235

查看上面的差异(在输出中)。没有那些操作的初始文件大小,以及那些压缩和其他操作之后。我需要这个尺寸接近500 kb。

上面的代码对我来说有点好处,因为它减少了图像文件的大小,使其小于500 KB。

但是,以下是上述代码的问题 -

  • 此代码即使小于500 KB

  • ,也会缩小文件大小
  • 如果它超过500 KB,减小的文件大小会从500 KB变得太小,尽管我需要它更接近。

我需要摆脱2个问题。所以,需要知道我应该在上面的代码中操作什么。

因为我还想纠正EXIF方向(旋转图像),以及我上面提到的要求。

8 个答案:

答案 0 :(得分:4)

您可以在调整大小之前检查大小。如果位图的大小超过500kb,则调整其大小。

另外,为了使更大的位图接近500kb尺寸,请检查尺寸和压缩之间的差异。

if(sizeOf(reduced_bitmap) > (500 * 1024)) {
    return getResizedBitmap(reduced_bitmap, maxSize, sizeOf(reduced_bitmap));
} else {
    return reduced_bitmap;
}

并在调整大小时Bitmap计算大小差异并相应地压缩

答案 1 :(得分:1)

这不是您的问题的解决方案,而是您获取非常小的文件的错误。

getResizedBitmapLessThan500KB(photo, 500)中,500是图像像素的最大值/高度,而不是kb中的最大尺寸。

因此所有压缩文件都少于500x500像素

答案 2 :(得分:1)

您遇到的另一个问题是,您正在测量位图的大小(未经过压缩),然后将其转换为JPG并进行测量。 JPG可能总是会变小,而压缩的程度将是图像的一个因素。有很多相同颜色的大区域?大!非常忙碌的#34;图案?压缩不会很好。

好的,进一步澄清:

如果您要定位某个文件大小,则无法通过查看压缩前的大小来执行此操作。你可以得到一个大概的想法(例如,这些照片的JPEG压缩系数约为15),那么你可以为位图设定500k * 15的目标。但根据照片中的内容,您可能无法完全达到目标。所以你可能想这样做:

  1. 选择jpegFactor
  2. bitMapTarget = target * jpegFactor
  3. adjustBitmap大小以适合bitMapTarget
  4. 将位图压缩为JPEG
  5. 如果仍然高于目标,请调整jpegFactor并重试。
  6. 您可以在#5上采取一些措施来确定您的距离,并尝试将其考虑在内。

答案 3 :(得分:1)

为了减少Image的大小我已经使用过这段代码..它的工作对我来说.. 请检查一下..它可能对你有所帮助..

Bitmap photo1 ;
private byte[] imageByteArray1 ;


BitmapFactory.Options opt1 = new BitmapFactory.Options();
opt1.inJustDecodeBounds=true;
BitmapFactory.decodeFile(imageUrl.get(imgCount).toString(),opt1);

// The new size we want to scale to
final int REQUIRED_SIZE=320;

// Find the correct scale value. It should be the power of 2.
int width_tmp=opt1.outWidth,height_tmp=opt1.outHeight;
int scale=2;
while(true){
    if(width_tmp>REQUIRED_SIZE||height_tmp>REQUIRED_SIZE)
        break;
    width_tmp/=2;
    height_tmp/=2;
    scale*=2;
}
// Decode with inSampleSize
BitmapFactory.Options o2=new BitmapFactory.Options();
o2.inSampleSize=scale;
o2.inJustDecodeBounds=false;
photo1=BitmapFactory.decodeFile(imageUrl.get(imgCount).toString(),o2);

ByteArrayOutputStream baos1=new ByteArrayOutputStream();
photo1.compress(Bitmap.CompressFormat.JPEG,60,baos1);
imageByteArray1=baos1.toByteArray();

答案 4 :(得分:1)

将我的 getResizedBitmapLessThan500KB()自定义为以下内容,对我有用。

    public static final long CAMERA_IMAGE_MAX_DESIRED_SIZE_IN_BYTES = 2524970;
        public static final double CAMERA_IMAGE_MAX_SIZE_AFTER_COMPRESSSION_IN_BYTES = 1893729.0;

 public static Bitmap getResizedBitmapLessThan500KB(Bitmap image, int maxSize, long file_size_in_bytes) {
                int width = image.getWidth();
                int height = image.getHeight();


                if(file_size_in_bytes <= AppGlobalConstants.CAMERA_IMAGE_MAX_DESIRED_SIZE_IN_BYTES) {
                    if (width > height) {
                        if (width > 500)
                            maxSize = width * 75 / 100;
                    } else {
                        if (height > 500)
                            maxSize = height * 75 / 100;
                    }
                } else {
                    double percentage = ((AppGlobalConstants.CAMERA_IMAGE_MAX_SIZE_AFTER_COMPRESSSION_IN_BYTES/file_size_in_bytes)*100);
                    if (width > height) {
                        if (width > 500)
                            maxSize = width * (int)percentage / 100;
                    } else {
                        if (height > 500)
                            maxSize = height * (int)percentage / 100;
                    }

                    if(maxSize > 600) {
                        maxSize = 600;
                    }

                }

                float bitmapRatio = (float)width / (float) height;
                if (bitmapRatio > 0) {
                    width = maxSize;
                    height = (int) (width / bitmapRatio);
                } else {
                    height = maxSize;
                    width = (int) (height * bitmapRatio);
                }
                Bitmap reduced_bitmap = Bitmap.createScaledBitmap(image, width, height, true);
        //        Log.d("file_size","file_size_during_manipulation: "+String.valueOf(sizeOf(reduced_bitmap)));
                if(sizeOf(reduced_bitmap) > (500 * 1000)) {
                    return getResizedBitmap(reduced_bitmap, maxSize, sizeOf(reduced_bitmap));
                } else {
                    return reduced_bitmap;
                }
            }

答案 5 :(得分:1)

你可以尝试这种方法

    public static Bitmap getScaledBitmap(Bitmap b, int reqWidth, int reqHeight)
        {
            Matrix m = new Matrix();
            m.setRectToRect(new RectF(0, 0, b.getWidth(), b.getHeight()), new RectF(0, 0, reqWidth, reqHeight), Matrix.ScaleToFit.CENTER);
            return Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), m, true);
        }

//call this method like
    Bitmap bm400=getScaledBitmap(bm,500,500);

对你有帮助。

答案 6 :(得分:0)

请检查此代码是否有用:

    final static int COMPRESSED_RATIO = 13;
    final static int perPixelDataSize = 4;
    public byte[] getJPGLessThanMaxSize(Bitmap image, int maxSize){
        int maxPixelCount = maxSize *1024 * COMPRESSED_RATIO / perPixelDataSize;
        int imagePixelCount = image.getWidth() * image.getHeight();
        Bitmap reducedBitmap;
        // Adjust Bitmap Dimensions if necessary.
        if(imagePixelCount > maxPixelCount) reducedBitmap = getResizedBitmapLessThanMaxSize(image, maxSize);
        else reducedBitmap = image;

        float compressedRatio = 1;
        byte[] resultBitmap;
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        int jpgQuality = 100;
        // Adjust Quality until file size is less than maxSize.
        do{
            reducedBitmap.compress(Bitmap.CompressFormat.JPEG, jpgQuality, outStream);
            resultBitmap = outStream.toByteArray();
            compressedRatio = resultBitmap.length / (reducedBitmap.getWidth() * reducedBitmap.getHeight() * perPixelDataSize);
            if(compressedRatio > (COMPRESSED_RATIO-1)){
                jpgQuality -= 1;
            }else if(compressedRatio > (COMPRESSED_RATIO*0.8)){
                jpgQuality -= 5;
            }else{
                jpgQuality -= 10;
            }
        }while(resultBitmap.length > (maxSize * 1024));
        return resultBitmap;
    }

    public Bitmap getResizedBitmapLessThanMaxSize(Bitmap image, int maxSize) {
        int width = image.getWidth();
        int height = image.getHeight();
        float bitmapRatio = (float)width / (float) height;

        // For uncompressed bitmap, the data size is:
        // H * W * perPixelDataSize = H * H * bitmapRatio * perPixelDataSize
        // 
        height = (int) Math.sqrt(maxSize * 1024 * COMPRESSED_RATIO / perPixelDataSize / bitmapRatio);
        width = (int) (height * bitmapRatio);
        Bitmap reduced_bitmap = Bitmap.createScaledBitmap(image, width, height, true);
        return reduced_bitmap;
    }

答案 7 :(得分:0)

我假设你想使用图库或系统相机来获取图像。请注意,通过Intent传输的最大数据有一个上限,这就是为什么您总是会缩小版图像的原因。

您可以参考https://developer.android.com/training/camera/photobasics.html获取标准解决方案。总之,您应该获得对外部存储的访问权限并为相机生成URI或从图库应用获取URI。然后使用ContentResolver获取图像。

InputStream inputStream = mContentResolver.openInputStream(mUri);

您可能希望为其他应用程序实现内容解析程序以访问您的数据,这是标准做法。