2013-03-15 315 views
31

我想將Bitmap縮放到與運行時相關的寬度和高度,其中縱橫比保持不變,並且Bitmap填充整個寬度並垂直居中圖像,裁剪多餘部分或填充與0個alpha像素的差距。按比例縮放的位圖保持寬高比

我目前通過創建所有的α0的像素的Bitmap和在它上面繪製圖像Bitmap,縮放的確切指定的寬度和保持縱橫比重畫位圖自己,然而,它最終失去/擰緊像素數據。

這裏是我如何做它:

Bitmap background = Bitmap.createBitmap((int)width, (int)height, Config.ARGB_8888); 
float originalWidth = originalImage.getWidth(), originalHeight = originalImage.getHeight(); 
Canvas canvas = new Canvas(background); 
float scale = width/originalWidth; 
float xTranslation = 0.0f, yTranslation = (height - originalHeight * scale)/2.0f; 
Matrix transformation = new Matrix(); 
transformation.postTranslate(xTranslation, yTranslation); 
transformation.preScale(scale, scale); 
canvas.drawBitmap(originalImage, transformation, null); 
return background; 

是否有出有圖書館或一些更好的代碼,可以做到這一點更好?我希望圖像看起來儘可能清晰,但我知道我的功能不會提供很好的結果。

我知道我可以通過使用整數縮放,而不是浮點縮放,但我需要的寬度是100%填充保持良好。

此外,我知道ImageViewGravity.CENTER_CROP能力,但是,它也使用整數縮放,所以它切斷了圖像的寬度,當它不應該。

回答

53

這個怎麼樣:

Bitmap background = Bitmap.createBitmap((int)width, (int)height, Config.ARGB_8888); 

float originalWidth = originalImage.getWidth(); 
float originalHeight = originalImage.getHeight(); 

Canvas canvas = new Canvas(background); 

float scale = width/originalWidth; 

float xTranslation = 0.0f; 
float yTranslation = (height - originalHeight * scale)/2.0f; 

Matrix transformation = new Matrix(); 
transformation.postTranslate(xTranslation, yTranslation); 
transformation.preScale(scale, scale); 

Paint paint = new Paint(); 
paint.setFilterBitmap(true); 

canvas.drawBitmap(originalImage, transformation, paint); 

return background; 

我添加了一個paint過濾縮放位圖。

+0

那麼,規模不能改變,因爲我需要寬度被填充,它也不能裁剪寬度。然而,油漆做到了。謝謝!你可以編輯答案切換回我的縮放? – RileyE

+2

但如果縮減它裁剪圖像 –

3

它也可以通過自己計算比例來完成,就像這樣。

private Bitmap scaleBitmap(Bitmap bm) { 
    int width = bm.getWidth(); 
    int height = bm.getHeight(); 

    Log.v("Pictures", "Width and height are " + width + "--" + height); 

    if (width > height) { 
     // landscape 
     int ratio = width/maxWidth; 
     width = maxWidth; 
     height = height/ratio; 
    } else if (height > width) { 
     // portrait 
     int ratio = height/maxHeight; 
     height = maxHeight; 
     width = width/ratio; 
    } else { 
     // square 
     height = maxHeight; 
     width = maxWidth; 
    } 

    Log.v("Pictures", "after scaling Width and height are " + width + "--" + height); 

    bm = Bitmap.createScaledBitmap(bm, width, height, true); 
    return bm; 
} 
+0

,比例爲0,它拋出由0 –

+3

呀什麼的,它的唯一考慮的解決方案權的例外劃分?禿鷲總是準備降低想法在這裏....嘆:-) –

21

這裏我有一個測試解決方案,其中創建縮放的位圖出的位圖文件的:

int scaleSize =1024; 

    public Bitmap resizeImageForImageView(Bitmap bitmap) { 
     Bitmap resizedBitmap = null; 
     int originalWidth = bitmap.getWidth(); 
     int originalHeight = bitmap.getHeight(); 
     int newWidth = -1; 
     int newHeight = -1; 
     float multFactor = -1.0F; 
     if(originalHeight > originalWidth) { 
      newHeight = scaleSize ; 
      multFactor = (float) originalWidth/(float) originalHeight; 
      newWidth = (int) (newHeight*multFactor); 
     } else if(originalWidth > originalHeight) { 
      newWidth = scaleSize ; 
      multFactor = (float) originalHeight/ (float)originalWidth; 
      newHeight = (int) (newWidth*multFactor); 
     } else if(originalHeight == originalWidth) { 
      newHeight = scaleSize ; 
      newWidth = scaleSize ; 
     } 
     resizedBitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, false); 
     return resizedBitmap; 
    } 

注意,我需要具有4096×4096像素的最大尺寸,但縱橫比縮放的位圖在調整大小時需要保留。如果您需要寬度或高度的其他值,則只需替換值「4096」。

這只是Coen答案的補充,但他的代碼中的問題是他計算比率的線。劃分兩個整數給出一個整數,如果結果是< 1,它將被舍入爲0.所以這引發了「除以零」例外。

+1

我建議提取新的大小值的變量或參數,以避免重複。你也可以使用新的size值初始化newWidth和newHeight,並且只重新設置改變的變量以保持scale(也可以不需要預先初始化multFactor或resizedBitmap)。 – AlexGuti

+1

你肯定是對的@Christopher Reichel,上面的代碼不能縮放所有的尺寸,只是寬度高於高度的尺寸。這個答案更好,但由於代碼優化和方法參數,@ joaomgcd的答案比這更好。 – webmaster

2
public static Bitmap scaleBitmap(Bitmap bitmap, int wantedWidth, int wantedHeight) { 
    float originalWidth = bitmap.getWidth(); 
    float originalHeight = bitmap.getHeight(); 
    Bitmap output = Bitmap.createBitmap(wantedWidth, wantedHeight, Config.ARGB_8888); 
    Canvas canvas = new Canvas(output); 
    Matrix m = new Matrix(); 

    float scalex = wantedWidth/originalWidth; 
    float scaley = wantedHeight/originalHeight; 
    float xTranslation = 0.0f, yTranslation = (wantedHeight - originalHeight * scaley)/2.0f; 

    m.postTranslate(xTranslation, yTranslation); 
    m.preScale(scalex, scaley); 
    // m.setScale((float) wantedWidth/bitmap.getWidth(), (float) wantedHeight/bitmap.getHeight()); 
    Paint paint = new Paint(); 
    paint.setFilterBitmap(true); 
    canvas.drawBitmap(bitmap, m, paint); 

    return output; 
} 
42

這將尊重maxWidth和maxHeight,這意味着所生成位圖將永遠不會有較大的那麼這些維度:

private static Bitmap resize(Bitmap image, int maxWidth, int maxHeight) { 
    if (maxHeight > 0 && maxWidth > 0) { 
     int width = image.getWidth(); 
     int height = image.getHeight(); 
     float ratioBitmap = (float) width/(float) height; 
     float ratioMax = (float) maxWidth/(float) maxHeight; 

     int finalWidth = maxWidth; 
     int finalHeight = maxHeight; 
     if (ratioMax > ratioBitmap) { 
      finalWidth = (int) ((float)maxHeight * ratioBitmap); 
     } else { 
      finalHeight = (int) ((float)maxWidth/ratioBitmap); 
     } 
     image = Bitmap.createScaledBitmap(image, finalWidth, finalHeight, true); 
     return image; 
    } else { 
     return image; 
    } 
} 
+0

解決方案的答案會造成圖像,但此解決方案完美無缺。 – Arslan

+0

@Arslan我沒有用這種方法進行任何修剪。你能再詳細一點嗎? –

+3

@JoshPinter「這個問題的接受答案導致了裁剪,這個答案對我來說非常合適,因爲它不會導致裁剪。」 – JakeSteam

4

這裏是一個方法,從我的utils的課,那這項工作:

public static Bitmap scaleBitmapAndKeepRation(Bitmap TargetBmp,int reqHeightInPixels,int reqWidthInPixels) 
    { 
     Matrix m = new Matrix(); 
     m.setRectToRect(new RectF(0, 0, TargetBmp.getWidth(), TargetBmp.getHeight()), new RectF(0, 0, reqWidthInPixels, reqHeightInPixels), Matrix.ScaleToFit.CENTER); 
     Bitmap scaledBitmap = Bitmap.createBitmap(TargetBmp, 0, 0, TargetBmp.getWidth(), TargetBmp.getHeight(), m, true); 
     return scaledBitmap; 
    } 
+2

**注意**這是API 17(Jellybean)或更高版本 – RileyE

+0

Neat !! 。這很簡單。除了變量命名約定。更好地改變TargetBmp - > targetBmp。爲**肖像**和**風景**圖像工作 –

1

上述答案都不適用於我,我只是創建了一種方法,將所有尺寸設置爲所需尺寸,並將空白區域塗成黑色。這裏是我的方法:

/** 
* Scale the image preserving the ratio 
* @param imageToScale Image to be scaled 
* @param destinationWidth Destination width after scaling 
* @param destinationHeight Destination height after scaling 
* @return New scaled bitmap preserving the ratio 
*/ 
public static Bitmap scalePreserveRatio(Bitmap imageToScale, int destinationWidth, 
     int destinationHeight) { 
    if (destinationHeight > 0 && destinationWidth > 0 && imageToScale != null) { 
     int width = imageToScale.getWidth(); 
     int height = imageToScale.getHeight(); 

     //Calculate the max changing amount and decide which dimension to use 
     float widthRatio = (float) destinationWidth/(float) width; 
     float heightRatio = (float) destinationHeight/(float) height; 

     //Use the ratio that will fit the image into the desired sizes 
     int finalWidth = (int)Math.floor(width * widthRatio); 
     int finalHeight = (int)Math.floor(height * widthRatio); 
     if (finalWidth > destinationWidth || finalHeight > destinationHeight) { 
      finalWidth = (int)Math.floor(width * heightRatio); 
      finalHeight = (int)Math.floor(height * heightRatio); 
     } 

     //Scale given bitmap to fit into the desired area 
     imageToScale = Bitmap.createScaledBitmap(imageToScale, finalWidth, finalHeight, true); 

     //Created a bitmap with desired sizes 
     Bitmap scaledImage = Bitmap.createBitmap(destinationWidth, destinationHeight, Bitmap.Config.ARGB_8888); 
     Canvas canvas = new Canvas(scaledImage); 

     //Draw background color 
     Paint paint = new Paint(); 
     paint.setColor(Color.BLACK); 
     paint.setStyle(Paint.Style.FILL); 
     canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), paint); 

     //Calculate the ratios and decide which part will have empty areas (width or height) 
     float ratioBitmap = (float)finalWidth/(float)finalHeight; 
     float destinationRatio = (float) destinationWidth/(float) destinationHeight; 
     float left = ratioBitmap >= destinationRatio ? 0 : (float)(destinationWidth - finalWidth)/2; 
     float top = ratioBitmap < destinationRatio ? 0: (float)(destinationHeight - finalHeight)/2; 
     canvas.drawBitmap(imageToScale, left, top, null); 

     return scaledImage; 
    } else { 
     return imageToScale; 
    } 
} 

例如;假設您的圖像爲100 x 100,但所需尺寸爲300x50,則此方法會將您的圖像轉換爲50 x 50並將其繪製爲尺寸爲300 x 50的新圖像(以及空白文件將是黑色的)。

另一個例子:假設您的圖像爲600 x 1000,所需大小再次爲300 x 50,那麼您的圖像將被轉換爲30 x 50並繪製成尺寸爲300 x的新創建圖像50.

我想這是它必須是,盧比。

3

簡單的解決方法:注意,我們將寬度設置爲500個像素

public void scaleImageKeepAspectRatio() 
    { 
     int imageWidth = scaledGalleryBitmap.getWidth(); 
     int imageHeight = scaledGalleryBitmap.getHeight(); 
     int newHeight = (imageHeight * 500)/imageWidth; 
     scaledGalleryBitmap = Bitmap.createScaledBitmap(scaledGalleryBitmap, 500, newHeight, false); 

    } 
1

我的解決辦法是這樣的,它保持縱橫比,並且只需要一個尺寸,例如,如果你有1920 * 1080和1080並希望將其調整到1280×1920的圖像,首先將是1280 * 720,第二個會是720 * 1280

public static Bitmap resizeBitmap(final Bitmap temp, final int size) { 
     if (size > 0) { 
      int width = temp.getWidth(); 
      int height = temp.getHeight(); 
      float ratioBitmap = (float) width/(float) height; 
      int finalWidth = size; 
      int finalHeight = size; 
      if (ratioBitmap < 1) { 
       finalWidth = (int) ((float) size * ratioBitmap); 
      } else { 
       finalHeight = (int) ((float) size/ratioBitmap); 
      } 
      return Bitmap.createScaledBitmap(temp, finalWidth, finalHeight, true); 
     } else { 
      return temp; 
     } 
    } 
1

This is an awesome library from ArthurHub既編程方式和交互方式處理圖像作物,如果你不想重新發明輪子。

但是,如果你喜歡不臃腫的版本和我一樣..,這裏顯示的內部函數是一個相當複雜的與幾個標準選項

/** 
* Resize the given bitmap to the given width/height by the given option.<br> 
*/ 

enum RequestSizeOptions { 
    RESIZE_FIT, 
    RESIZE_INSIDE, 
    RESIZE_EXACT 
} 

static Bitmap resizeBitmap(Bitmap bitmap, int reqWidth, int reqHeight, RequestSizeOptions options) { 
    try { 
     if (reqWidth > 0 && reqHeight > 0 && (options == RequestSizeOptions.RESIZE_FIT || 
       options == RequestSizeOptions.RESIZE_INSIDE || 
       options == RequestSizeOptions.RESIZE_EXACT)) { 

      Bitmap resized = null; 
      if (options == RequestSizeOptions.RESIZE_EXACT) { 
       resized = Bitmap.createScaledBitmap(bitmap, reqWidth, reqHeight, false); 
      } else { 
       int width = bitmap.getWidth(); 
       int height = bitmap.getHeight(); 
       float scale = Math.max(width/(float) reqWidth, height/(float) reqHeight); 
       if (scale > 1 || options == RequestSizeOptions.RESIZE_FIT) { 
        resized = Bitmap.createScaledBitmap(bitmap, (int) (width/scale), (int) (height/scale), false); 
       } 
      } 
      if (resized != null) { 
       if (resized != bitmap) { 
        bitmap.recycle(); 
       } 
       return resized; 
      } 
     } 
    } catch (Exception e) { 
     Log.w("AIC", "Failed to resize cropped image, return bitmap before resize", e); 
    } 
    return bitmap; 
} 
1

新增RESIZE_CROP到Gowrav的回答進行圖像縮放。

enum RequestSizeOptions { 
    RESIZE_FIT, 
    RESIZE_INSIDE, 
    RESIZE_EXACT, 
    RESIZE_CENTRE_CROP 
} 
static Bitmap resizeBitmap(Bitmap bitmap, int reqWidth, int reqHeight, RequestSizeOptions options) { 
    try { 
     if (reqWidth > 0 && reqHeight > 0 && (options == RequestSizeOptions.RESIZE_FIT || 
       options == RequestSizeOptions.RESIZE_INSIDE || 
       options == RequestSizeOptions.RESIZE_EXACT || options == RequestSizeOptions.RESIZE_CENTRE_CROP)) { 

      Bitmap resized = null; 
      if (options == RequestSizeOptions.RESIZE_EXACT) { 
       resized = Bitmap.createScaledBitmap(bitmap, reqWidth, reqHeight, false); 
      } else { 
       int width = bitmap.getWidth(); 
       int height = bitmap.getHeight(); 
       float scale = Math.max(width/(float) reqWidth, height/(float) reqHeight); 
       if (scale > 1 || options == RequestSizeOptions.RESIZE_FIT) { 
        resized = Bitmap.createScaledBitmap(bitmap, (int) (width/scale), (int) (height/scale), false); 
       } 
       if (scale > 1 || options == RequestSizeOptions.RESIZE_CENTRE_CROP) { 
        int smaller_side = (height-width)>0?width:height; 
        int half_smaller_side = smaller_side/2; 
        Rect initialRect = new Rect(0,0,width,height); 
        Rect finalRect = new Rect(initialRect.centerX()-half_smaller_side,initialRect.centerY()-half_smaller_side, 
          initialRect.centerX()+half_smaller_side,initialRect.centerY()+half_smaller_side); 
        bitmap = Bitmap.createBitmap(bitmap, finalRect.left, finalRect.top, finalRect.width(), finalRect.height(), null, true); 
        //keep in mind we have square as request for cropping, otherwise - it is useless 
        resized = Bitmap.createScaledBitmap(bitmap, reqWidth, reqHeight, false); 
       } 

      } 
      if (resized != null) { 
       if (resized != bitmap) { 
        bitmap.recycle(); 
       } 
       return resized; 
      } 
     } 
    } catch (Exception e) { 
     Log.w("AIC", "Failed to resize cropped image, return bitmap before resize", e); 
    } 
    return bitmap; 
}