Android - Scale and compress a bitmap

42,496

Solution 1

  1. You need to decide on a limit for either your width or height (not both, obviously). Then replace those fixed image sizes with calculated ones, say:

    int targetWidth = 640; // your arbitrary fixed limit
    int targetHeight = (int) (originalHeight * targetWidth / (double) originalWidth); // casts to avoid truncating
    

    (Add checks and calculation alternatives for landscape / portrait orientation, as needed.)

  2. As @harism also commented: the large size you mentioned is the raw size of that 480x800 bitmap, not the file size, which should be a JPEG in your case. How are you going about saving that bitmap, BTW? Your code doesn't seem to contain the saving part.

    See this question here for help on that, with the key being something like:

    OutputStream imagefile = new FileOutputStream("/your/file/name.jpg");
    // Write 'bitmap' to file using JPEG and 80% quality hint for JPEG:
    bitmap.compress(CompressFormat.JPEG, 80, imagefile);
    

Solution 2

Firstly i check the size of image then i compress image according to size and get compressed bitmap then send that bitmap to server For Compressed bitmap call below funtion we have to pass image path in below funtion

public Bitmap get_Picture_bitmap(String imagePath) {

    long size_file = getFileSize(new File(imagePath));

    size_file = (size_file) / 1000;// in Kb now
    int ample_size = 1;

    if (size_file <= 250) {

        System.out.println("SSSSS1111= " + size_file);
        ample_size = 2;

    } else if (size_file > 251 && size_file < 1500) {

        System.out.println("SSSSS2222= " + size_file);
        ample_size = 4;

    } else if (size_file >= 1500 && size_file < 3000) {

        System.out.println("SSSSS3333= " + size_file);
        ample_size = 8;

    } else if (size_file >= 3000 && size_file <= 4500) {

        System.out.println("SSSSS4444= " + size_file);
        ample_size = 12;

    } else if (size_file >= 4500) {

        System.out.println("SSSSS4444= " + size_file);
        ample_size = 16;
    }

    Bitmap bitmap = null;

    BitmapFactory.Options bitoption = new BitmapFactory.Options();
    bitoption.inSampleSize = ample_size;

    Bitmap bitmapPhoto = BitmapFactory.decodeFile(imagePath, bitoption);

    ExifInterface exif = null;
    try {
        exif = new ExifInterface(imagePath);
    } catch (IOException e) {
        // Auto-generated catch block
        e.printStackTrace();
    }
    int orientation = exif
            .getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
    Matrix matrix = new Matrix();

    if ((orientation == 3)) {
        matrix.postRotate(180);
        bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0,
                bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix,
                true);

    } else if (orientation == 6) {
        matrix.postRotate(90);
        bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0,
                bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix,
                true);

    } else if (orientation == 8) {
        matrix.postRotate(270);
        bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0,
                bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix,
                true);

    } else {
        matrix.postRotate(0);
        bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0,
                bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix,
                true);

    }

    return bitmap;

}

getFileSize funtion for getting the size of image

    public long getFileSize(final File file) {
    if (file == null || !file.exists())
        return 0;
    if (!file.isDirectory())
        return file.length();
    final List<File> dirs = new LinkedList<File>();
    dirs.add(file);
    long result = 0;
    while (!dirs.isEmpty()) {
        final File dir = dirs.remove(0);
        if (!dir.exists())
            continue;
        final File[] listFiles = dir.listFiles();
        if (listFiles == null || listFiles.length == 0)
            continue;
        for (final File child : listFiles) {
            result += child.length();
            if (child.isDirectory())
                dirs.add(child);
        }
    }

    return result;
}
Share:
42,496
Allan Jiang
Author by

Allan Jiang

Updated on July 09, 2022

Comments

  • Allan Jiang
    Allan Jiang almost 2 years

    I am working on an android app, which has camera capture and photo uploading feature. If the device has a high resolution camera, the captured image size will be really large (1~3MB or more).
    Since the app will need to upload this image to server, I will need to compress the image before uploading. If the camera captured a 1920x1080 full-res photo for example, the ideal output is to keep a 16:9 ratio of the image, compress it to be a 640x360 image to reduce some image quality and make it a smaller size in bytes.

    Here is my code (referenced from google):

    /**
     * this class provide methods that can help compress the image size.
     *
     */
    public class ImageCompressHelper {
    
    /**
     * Calcuate how much to compress the image
     * @param options
     * @param reqWidth
     * @param reqHeight
     * @return
     */
    public 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;
    }
    
    /**
     * resize image to 480x800
     * @param filePath
     * @return
     */
    public static Bitmap getSmallBitmap(String filePath) {
    
        File file = new File(filePath);
        long originalSize = file.length();
    
        MyLogger.Verbose("Original image size is: " + originalSize + " bytes.");
    
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filePath, options);
    
        // Calculate inSampleSize based on a preset ratio
        options.inSampleSize = calculateInSampleSize(options, 480, 800);
    
        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
    
        Bitmap compressedImage = BitmapFactory.decodeFile(filePath, options);
    
        MyLogger.Verbose("Compressed image size is " + sizeOf(compressedImage) + " bytes");
    
        return compressedImage;
    }
    

    The problem with the above code is:

    1. It cannot keep the ratio, the code is forcing the image to resized to 480x800. if user captured a image in another ratio, the image will not look good after compress.
    2. It doesn't functioning well. The code will always change the image size to 7990272byte no matter what the original file size is. If the original image size is pretty small already, it will make it big (my test result to take a picture of my wall, which is pretty much mono-colored):

      Original image size is: 990092 bytes.
      Compressed image size is 7990272 bytes

    I am asking if there's suggestion of a better way to compress photo so it can be uploaded smoothly?