5
votes

I'm scaling down some bitmaps and getting low quality results. I tried the Bitmap#createScaledBitmap and the Canvas#drawBitmap method. Setting the filter parameter in the first and the filter flag in the Paint object of the second have shown no visible difference.

I tried solutions founded in these questions:

Bad image quality after resizing/scaling bitmap

Quality problems when resizing an image at runtime

Drawing scaled bitmaps on a SurfaceView -- no antialiasing

And some others.

As someone said somewhere, the filter flag in createScaledBitmap or in a Paint object enables the bicubic interpolation algorithm. However, it makes no difference. Using GIMP cubic, which is in fact bicubic, the resulting image is much better than the Android implementation.

API level here is 19.

2

2 Answers

0
votes

Try this, May it help You.

public static Bitmap scaleCenterCrop(Bitmap source, int newHeight, int newWidth)
    {
        int sourceWidth = source.getWidth();
        int sourceHeight = source.getHeight();
        float xScale = (float) newWidth / sourceWidth;
        float yScale = (float) newHeight / sourceHeight;
        float scale = Math.max(xScale, yScale);

        //get the resulting size after scaling
        float scaledWidth = scale * sourceWidth;
        float scaledHeight = scale * sourceHeight;

        //figure out where we should translate to
        float dx = (newWidth - scaledWidth) / 2;
        float dy = (newHeight - scaledHeight) / 2;

        Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, source.getConfig());
        Canvas canvas = new Canvas(dest);
        Matrix matrix = new Matrix();
        matrix.postScale(scale, scale);
        matrix.postTranslate(dx, dy);
        canvas.drawBitmap(source, matrix, null);
        return dest;
    }
0
votes

Try this one..

private Bitmap performResize(Bitmap bitmap, int requiredWidth,
            int requiredHeight) {
        int imageWidth = bitmap.getWidth();
        int imageHeight = bitmap.getHeight();
        float differenceWidth = requiredWidth - imageWidth;
        float percentage = differenceWidth / imageWidth * 100;
        float estimatedheight = imageHeight + (percentage * imageHeight / 100);
        float estimatedwidth = requiredWidth;

        if (estimatedheight < requiredHeight) {
            float incresePercentage = (float) (requiredHeight - estimatedheight);
            percentage += (incresePercentage / imageHeight * 100);
            estimatedheight = imageHeight + (percentage * imageHeight / 100);
            estimatedwidth = imageWidth + (percentage * imageWidth / 100);
        }

        bitmap = ScalingUtilities.performResize(bitmap, (int) estimatedheight,
                (int) estimatedwidth);

        if (bitmap.getHeight() < requiredHeight) // if calculate height is
                                                    // smaller then the required
                                                    // Height
        {
        } else {
            int xCropPosition = (int) ((bitmap.getWidth() - requiredWidth) / 2);
            int yCropPosition = (int) ((bitmap.getHeight() - requiredHeight) / 2);

            bitmap = Bitmap.createBitmap(bitmap, xCropPosition, yCropPosition,
                    (int) requiredWidth, (int) requiredHeight);
        }
        return bitmap;
    }

utility file

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.util.Log;

/**
 * Class containing static utility methods for bitmap decoding and scaling
 *
 * @author Andreas Agvard ([email protected])
 */
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, String path, 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.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);
        }
    }


    public static Bitmap performResize(Bitmap unscaledBitmap,int height,int width)
    {
 //Log.e("Scaling Bitmap",unscaledBitmap.toString() + " height" +height +" w="+width );
        Bitmap scaledBitmap = ScalingUtilities.createScaledBitmap(unscaledBitmap,  width, height, ScalingUtilities.ScalingLogic.FIT);
//        if(scaledBitmap != null )
//          scaledBitmap = ImageBlurUtility.fastblur(LiveWallpaperService.bitmap, LiveWallpaperService.imageBlurAmount);
//          

        unscaledBitmap.recycle();

        return scaledBitmap;
    }

   public static Bitmap updateImageFromGallary(Context ctx,String imgPath,int reqWidth, int reqHeight)
    {
        Bitmap cameraBitmap=null; 
        try
        {     
            cameraBitmap = decodeSampledBitmapFromResource(ctx.getResources(),imgPath,reqWidth,reqHeight);
            //imgEdit.setImageBitmap(cameraBitmap); 
        }
        catch(OutOfMemoryError outMemeoryError)
        {
           // Toast.makeText(this, "Unable to Load Image", Toast.LENGTH_SHORT).show(); 
        }  
        return cameraBitmap;
    }

    public static Bitmap decodeSampledBitmapFromResource(Resources res, String path,int reqWidth, int reqHeight) 
    {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
      options.inPurgeable = true;
        BitmapFactory.decodeFile(path, options);

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


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

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
       //return BitmapFactory.decodeResource(res, resId, options);

       // return  BitmapFactory.decodeFile(path, options);

          return  BitmapFactory.decodeFile(path, options);   
    }

    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) 
    {
        // 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;
    }

    return inSampleSize;
    }



/**
 * This method converts dp unit to equivalent pixels, depending on device density. 
 * 
 * @param dp A value in dp (density independent pixels) unit. Which we need to convert into pixels
 * @param context Context to get resources and device specific display metrics
 * @return A float value to represent px equivalent to dp depending on device density
 */
public static float convertDpToPixel(float dp, Context context){
    Resources resources = context.getResources();
    DisplayMetrics metrics = resources.getDisplayMetrics();
    float px = dp * (metrics.densityDpi / 160f);
    return px;
}

/**
 * This method converts device specific pixels to density independent pixels.
 * 
 * @param px A value in px (pixels) unit. Which we need to convert into db
 * @param context Context to get resources and device specific display metrics
 * @return A float value to represent dp equivalent to px value
 */
public static float convertPixelsToDp(float px, Context context) {
    Resources resources = context.getResources();
    DisplayMetrics metrics = resources.getDisplayMetrics();
    float dp = px / (metrics.densityDpi / 160f);
    return dp;
}


public static int convertToPx(int input,Context context) {
    // Get the screen's density scale
    final float scale = context.getResources().getDisplayMetrics().density;
    // Convert the dps to pixels, based on density scale
    Log.e("textSize","textSize scale value "+scale);
    return (int) (input * scale + 0.5f);
}

}