简体   繁体   中英

Android compress image with small size and good quality from camera intent

In my app user can take picture from camera intent, then I save this image as full size image not thumbnail. Then what I want to do is use this saved image to compress it and send it over to server.

The image size from camera intent is around 7-8 MB and resolution of 5664x4248.

The requirements is to achieve is image of same size and quality of whatsapp which is 40-80KB

I tried different solution but I couldn't achieve the same good quality and size.

For this I used id.zelory:compressor:2.1.1 library

Any Idea?

Here I call this method after saving the image to resize it

private File customCompressImage (File imgFile) {
    String destinationDirectoryPath=  Environment.getExternalStorageDirectory().getPath() + "/Pictures/";
    try {
        return new CustomCompressor(context)
                 .setMaxWidth(612)
                 .setMaxHeight(816)
                 .setQuality(80)
                 .setCompressFormat(Bitmap.CompressFormat.JPEG)
                 .setDestinationDirectoryPath(destinationDirectoryPath)
                 .compressToFile(imgFile);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

CompressImage

static File compressImage(File imageFile, int reqWidth, int reqHeight, Bitmap.CompressFormat compressFormat, int quality, String destinationPath) throws IOException {
    FileOutputStream fileOutputStream = null;
    File file = new File(destinationPath).getParentFile();
    if (!file.exists()) {
        file.mkdirs();
    }
    try {
        fileOutputStream = new FileOutputStream(destinationPath);
        // write the compressed bitmap at the destination specified by destinationPath.
        decodeSampledBitmapFromFile(imageFile, reqWidth, reqHeight).compress(compressFormat, quality, fileOutputStream);
    } finally {
        if (fileOutputStream != null) {
            fileOutputStream.flush();
            fileOutputStream.close();
        }
    }

    return new File(destinationPath);
}


static Bitmap decodeSampledBitmapFromFile(File imageFile, int reqWidth, int reqHeight) throws IOException {
    // First decode with inJustDecodeBounds=true to check dimensions
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;

    Bitmap scaledBitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);

    //check the rotation of the image and display it properly
    ExifInterface exif;
    exif = new ExifInterface(imageFile.getAbsolutePath());
    int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
    Matrix matrix = new Matrix();
    if (orientation == 6) {
        matrix.postRotate(90);
    } else if (orientation == 3) {
        matrix.postRotate(180);
    } else if (orientation == 8) {
        matrix.postRotate(270);
    }
    scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
    return scaledBitmap;
}


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

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

I tried passing different max width and height and quality and I never achived both small size and good quality

You can try this piece of code.

public static Bitmap getCompressed( Bitmap imageBitmap) {
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
    return imageBitmap;
}

// 100 is quality, change it according to your need

@End User shouldn't it be like this instead (that's at least what I get from reading the documentation):

public static Bitmap getCompressed(Bitmap imageBitmap) {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    if (!imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out))
        throw new IllegalStateException("Unable to compress image");
    ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
    return BitmapFactory.decodeStream(in);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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