简体   繁体   English

在android中减少摄像头捕获图像的大小

[英]Reduce size of captured image from camera in android

Here, I am saving the captured image on sdcard from camera. 在这里,我将摄像头上的捕获图像保存在SD卡上。 Here, captured image size is greater than 1 MB . 这里,捕获的图像大小大于1 MB I want to reduce this size to nearly 500kb to 600kb before saving to sdcard. 我希望在保存到SD卡之前将此大小减小到接近500kb到600kb。 How could I do that? 我怎么能这样做?

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();
        }
mPhoto.compress(Bitmap.CompressFormat.PNG, 100, bytes);

100 in this is the best quality. 100这是最好的品质。 If u want reduce size, then try to decrase that value 如果你想减小尺寸,那么试着去掉那个值

Other way may be to use inSampleSize parameters of BitmapFactory.Options(). 其他方法可能是使用BitmapFactory.Options()的inSampleSize参数。 That should reduce size too. 这也应该减小尺寸。 You can read abut that here 你可以在这里阅读

edit: Some code 编辑:一些代码

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);

That should load image with little worse quality. 这应该加载质量稍差的图像。

then save image 然后保存图像

bmp.compress(Bitmap.CompressFormat.PNG, 70, bytes);

Set height and width of your bitmap is device specific... 设置位图的高度和宽度是特定于设备的......

@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;
    }

this method reduce image size .its work in my project. 这种方法减少了图像尺寸。在我的项目中工作。

**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();
        }

    }

After reading the other answers and not finding exactly what I wanted, here's my approach at acquiring an appropriately scaled bitmap. 在阅读了其他答案而没有找到我想要的内容之后,这是我获取适当​​缩放位图的方法。 This is an adaptation of Prabu's answer. 这是对Prabu答案的改编。

It makes sure your picture is scaled in a way that does not deform the dimensions of the photo: 它确保您的图片以不会使照片尺寸变形的方式缩放:

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;
}

Here's a corresponding link to my GitHub Gist: https://gist.github.com/Lwdthe1/2d1cd0a12f30c18db698 这是我的GitHub Gist的相应链接: https//gist.github.com/Lwdthe1/2d1cd0a12f30c18db698

This is what worked for me. 这对我有用。

    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;
}

On a Samusung Galaxy S7, i was able to reduce the size down to 300kb. 在Samusung Galaxy S7上,我能够将尺寸减小到300kb。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM