How to prevent memory increase on Image Compression

332 views Asked by At

I am trying to do Capture Image, compress to a file & upload it to my server. But, when I am doing that, my memory size suddenly increases by 60 MB.

enter image description here

I am doing the following approach to get compress image file path. During this process only,memory size increases suddenly & sometimes I am getting out of memory issue also.

public String getScaledPic(String path)
    {
        Bitmap img;
        try {
            String filePath =path;;

            String folderName = filePath.substring(0, filePath.lastIndexOf("/")+1);

            String tmpFileName = (filePath.substring(filePath.lastIndexOf("/")+1)).split("\\.")[0]+"_tmp.jpg";
            File from = new File(filePath);
            folderName=getActivity().getFilesDir()+"/";
            File to = new File(folderName+tmpFileName);
            try {

                copy(from, to);
                compress(folderName+tmpFileName);
            } catch (IOException io){

                return path;
            }
            return  folderName+tmpFileName;

        }
        catch(Exception e)
        {
            return path;

        }

    }


    public void copy(File src, File dst) throws IOException {
        InputStream in = new FileInputStream(src);
        OutputStream out = new FileOutputStream(dst);

        // Transfer bytes from in to out
        byte[] buf = new byte[1024];
        int len;
        while ((len = in.read(buf)) > 0) {
            out.write(buf, 0, len);
        }
        in.close();
        out.close();
    }


    public void compress(String comp) {
        try {

            String path = comp;
            BitmapFactory.Options buffer = new BitmapFactory.Options();
            Bitmap bmp = BitmapFactory.decodeFile(path, buffer);

            if (bmp.getWidth() > 768 && bmp.getHeight() > 768){

                float widthCompression = 768.0f/bmp.getWidth();
                float heightCompression = 768.0f/bmp.getHeight();
                if (widthCompression>=heightCompression)
                {
                    Bitmap resized = Bitmap.createScaledBitmap(bmp,(int)(bmp.getWidth()*widthCompression), (int)(bmp.getHeight()*widthCompression), true);
                    bmp.recycle();
                    FileOutputStream out = new FileOutputStream(path);
                    resized.compress(CompressFormat.JPEG, 100, out);
                    resized.recycle();
                    out.flush();
                    out.close();
                }
                else
                {
                    Bitmap resized = Bitmap.createScaledBitmap(bmp,(int)(bmp.getWidth()*heightCompression), (int)(bmp.getHeight()*heightCompression), true);
                    bmp.recycle();
                    FileOutputStream out = new FileOutputStream(path);
                    resized.compress(CompressFormat.JPEG, 100, out);
                    resized.recycle();
                    out.flush();
                    out.close();
                }

            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Is there any mistake my approach? Also, from the image, how to handle the memory leaks or heavy memory usage caused by the bitmaps?

1

There are 1 answers

0
Nitesh On

Hey I use the following code to reduce the file size.

===================== Add this class ================================

public class ScalingUtilities {

/**
 * Utility function for decoding an image resource. The decoded bitmap will
 * be optimized for further scaling to the requested destination dimensions
 * and scaling logic.
 *
 * @param res The resources object containing the image data
 * @param resId The resource id of the image data
 * @param dstWidth Width of destination area
 * @param dstHeight Height of destination area
 * @param scalingLogic Logic to use to avoid image stretching
 * @return Decoded bitmap
 */
public static Bitmap decodeResource(Resources res, int resId, int dstWidth, int dstHeight,
        ScalingLogic scalingLogic) {
    Options options = new Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);
    options.inJustDecodeBounds = false;
    options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, dstWidth,
            dstHeight, scalingLogic);
    Bitmap unscaledBitmap = BitmapFactory.decodeResource(res, resId, options);

    return unscaledBitmap;
}
public static Bitmap decodeFile(String path, int dstWidth, int dstHeight,
        ScalingLogic scalingLogic) {
    Options options = new Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(path, options);
    options.inJustDecodeBounds = false;
    options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, dstWidth,
            dstHeight, scalingLogic);
    Bitmap unscaledBitmap = BitmapFactory.decodeFile(path, options);

    return unscaledBitmap;
}

/**
 * Utility function for creating a scaled version of an existing bitmap
 *
 * @param unscaledBitmap Bitmap to scale
 * @param dstWidth Wanted width of destination bitmap
 * @param dstHeight Wanted height of destination bitmap
 * @param scalingLogic Logic to use to avoid image stretching
 * @return New scaled bitmap object
 */
public static Bitmap createScaledBitmap(Bitmap unscaledBitmap, int dstWidth, int dstHeight,
        ScalingLogic scalingLogic) {
    Rect srcRect = calculateSrcRect(unscaledBitmap.getWidth(), unscaledBitmap.getHeight(),
            dstWidth, dstHeight, scalingLogic);
    Rect dstRect = calculateDstRect(unscaledBitmap.getWidth(), unscaledBitmap.getHeight(),
            dstWidth, dstHeight, scalingLogic);
    Bitmap scaledBitmap = Bitmap.createBitmap(dstRect.width(), dstRect.height(),
            Config.ARGB_8888);
    Canvas canvas = new Canvas(scaledBitmap);
    canvas.drawBitmap(unscaledBitmap, srcRect, dstRect, new Paint(Paint.FILTER_BITMAP_FLAG));

    return scaledBitmap;
}

/**
 * ScalingLogic defines how scaling should be carried out if source and
 * destination image has different aspect ratio.
 *
 * CROP: Scales the image the minimum amount while making sure that at least
 * one of the two dimensions fit inside the requested destination area.
 * Parts of the source image will be cropped to realize this.
 *
 * FIT: Scales the image the minimum amount while making sure both
 * dimensions fit inside the requested destination area. The resulting
 * destination dimensions might be adjusted to a smaller size than
 * requested.
 */
public static enum ScalingLogic {
    CROP, FIT
}

/**
 * Calculate optimal down-sampling factor given the dimensions of a source
 * image, the dimensions of a destination area and a scaling logic.
 *
 * @param srcWidth Width of source image
 * @param srcHeight Height of source image
 * @param dstWidth Width of destination area
 * @param dstHeight Height of destination area
 * @param scalingLogic Logic to use to avoid image stretching
 * @return Optimal down scaling sample size for decoding
 */
public static int calculateSampleSize(int srcWidth, int srcHeight, int dstWidth, int dstHeight,
        ScalingLogic scalingLogic) {
    if (scalingLogic == ScalingLogic.FIT) {
        final float srcAspect = (float)srcWidth / (float)srcHeight;
        final float dstAspect = (float)dstWidth / (float)dstHeight;

        if (srcAspect > dstAspect) {
            return srcWidth / dstWidth;
        } else {
            return srcHeight / dstHeight;
        }
    } else {
        final float srcAspect = (float)srcWidth / (float)srcHeight;
        final float dstAspect = (float)dstWidth / (float)dstHeight;

        if (srcAspect > dstAspect) {
            return srcHeight / dstHeight;
        } else {
            return srcWidth / dstWidth;
        }
    }
}

/**
 * Calculates source rectangle for scaling bitmap
 *
 * @param srcWidth Width of source image
 * @param srcHeight Height of source image
 * @param dstWidth Width of destination area
 * @param dstHeight Height of destination area
 * @param scalingLogic Logic to use to avoid image stretching
 * @return Optimal source rectangle
 */
public static Rect calculateSrcRect(int srcWidth, int srcHeight, int dstWidth, int dstHeight,
        ScalingLogic scalingLogic) {
    if (scalingLogic == ScalingLogic.CROP) {
        final float srcAspect = (float)srcWidth / (float)srcHeight;
        final float dstAspect = (float)dstWidth / (float)dstHeight;

        if (srcAspect > dstAspect) {
            final int srcRectWidth = (int)(srcHeight * dstAspect);
            final int srcRectLeft = (srcWidth - srcRectWidth) / 2;
            return new Rect(srcRectLeft, 0, srcRectLeft + srcRectWidth, srcHeight);
        } else {
            final int srcRectHeight = (int)(srcWidth / dstAspect);
            final int scrRectTop = (int)(srcHeight - srcRectHeight) / 2;
            return new Rect(0, scrRectTop, srcWidth, scrRectTop + srcRectHeight);
        }
    } else {
        return new Rect(0, 0, srcWidth, srcHeight);
    }
}

/**
 * Calculates destination rectangle for scaling bitmap
 *
 * @param srcWidth Width of source image
 * @param srcHeight Height of source image
 * @param dstWidth Width of destination area
 * @param dstHeight Height of destination area
 * @param scalingLogic Logic to use to avoid image stretching
 * @return Optimal destination rectangle
 */
public static Rect calculateDstRect(int srcWidth, int srcHeight, int dstWidth, int dstHeight,
        ScalingLogic scalingLogic) {
    if (scalingLogic == ScalingLogic.FIT) {
        final float srcAspect = (float)srcWidth / (float)srcHeight;
        final float dstAspect = (float)dstWidth / (float)dstHeight;

        if (srcAspect > dstAspect) {
            return new Rect(0, 0, dstWidth, (int)(dstWidth / srcAspect));
        } else {
            return new Rect(0, 0, (int)(dstHeight * srcAspect), dstHeight);
        }
    } else {
        return new Rect(0, 0, dstWidth, dstHeight);
    }
}

}

============= use this method to resize the image ==================

private String decodeFile(String path, int DESIREDWIDTH, int DESIREDHEIGHT) {
    String strMyImagePath = null;
    Bitmap scaledBitmap = null;

    try {
        // Part 1: Decode image
        Bitmap unscaledBitmap = ScalingUtilities.decodeFile(path, DESIREDWIDTH, DESIREDHEIGHT, ScalingLogic.FIT);

        if (!(unscaledBitmap.getWidth() <= DESIREDWIDTH && unscaledBitmap.getHeight() <= DESIREDHEIGHT)) {
            // Part 2: Scale image
            scaledBitmap = ScalingUtilities.createScaledBitmap(unscaledBitmap, DESIREDWIDTH, DESIREDHEIGHT, ScalingLogic.FIT);
        } else {
            unscaledBitmap.recycle();
            return path;
        }

        // Store to tmp file

        String extr = Environment.getExternalStorageDirectory().toString();
        File mFolder = new File(extr + "/TMMFOLDER");
        if (!mFolder.exists()) {
            mFolder.mkdir();
        }

        String s = "tmp.png";

        File f = new File(mFolder.getAbsolutePath(), s);

        strMyImagePath = f.getAbsolutePath();
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(f);
            scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 75, fos);
            fos.flush();
            fos.close();
        } catch (FileNotFoundException e) {

            e.printStackTrace();
        } catch (Exception e) {

            e.printStackTrace();
        }

        scaledBitmap.recycle();
    } catch (Throwable e) {
    }

    if (strMyImagePath == null) {
        return path;
    }
    return strMyImagePath;

}