Android:位图向下缩放低质量

时间:2014-03-24 18:23:11

标签: android image bitmap scale

我缩小了一些位图并获得了低质量的结果。我尝试了Bitmap#createScaledBitmap和Canvas#drawBitmap方法。在第一个中设置过滤器参数,在第二个的Paint对象中设置过滤器标志,但没有显示出明显的差异。

我尝试了在这些问题中找到的解决方案:

Bad image quality after resizing/scaling bitmap

Quality problems when resizing an image at runtime

Drawing scaled bitmaps on a SurfaceView -- no antialiasing

还有其他人。

正如某人所说,createScaledBitmap或Paint对象中的过滤器标志启用了双三次插值算法。但是,它没有任何区别。使用GIMP cubic(实际上是双三次),得到的图像比Android实现要好得多。

此处的API级别为19。

2 个答案:

答案 0 :(得分:0)

  

试试这个,愿它帮助你。

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

答案 1 :(得分:0)

  

试试这个..

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

实用程序文件

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 (andreas.agvard@sonyericsson.com)
 */
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);
}

}