2017-04-18 321 views
0

我有一個小的方法,旨在調整圖像大小(存儲爲文件)以產生具有某種預定義文件大小的新圖像(在我的情況下爲512 KB )。該方法看起來是這樣的:Android - 縮小圖像尺寸不會減小尺寸的比例

private static final int maximumFileSizeInKBs = 512; 

public static Uri resizeImage(Context context, Uri imageUri) { 
    // get image width and height 
    BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    Bitmap imageBitmap = BitmapFactory.decodeFile(new File(imageUri.getPath()).getAbsolutePath(), options); 
    int imageWidth = options.outWidth; 
    int imageHeight = options.outHeight; 

    // get image file size (in KBs) 
    File file = new File(imageUri.getPath()); 
    int fileSizeInKBs = Integer.parseInt(String.valueOf(file.length()/1024)); 

    // get the scaling factor 
    // (square root because when we scale both the width and height by the 
    // square root of the scaling factor, then the size of the final image 
    // will be scaled by the scaling factor) 
    double scalingFactor = Math.sqrt(fileSizeInKBs/maximumFileSizeInKBs); 

    // no need to scale if file already within maximum file size limit 
    if(scalingFactor <= 1) { 
     return imageUri; 
    } 

    // get scaled dimensions 
    int scaledImageWidth = (int) Math.floor(imageWidth/scalingFactor); 
    int scaledImageHeight = (int) Math.floor(imageHeight/scalingFactor); 

    // load original bitmap (load a scaled copy to avoid OutOfMemory errors) 
    options = new BitmapFactory.Options(); 
    options.inSampleSize = Math.max(imageHeight/scaledImageWidth, imageHeight/scaledImageHeight); 
    imageBitmap = BitmapFactory.decodeFile(new File(imageUri.getPath()).getAbsolutePath(), options); 

    // the scaled image above will be scaled by a value equal to the 
    // nearest power of 2, hence it wont be scaled to the exact value 
    // that we want. So, we need to calculate new scaling factors 
    // based on the scaled loaded bitmap 
    Matrix m = new Matrix(); 
    RectF inRect = new RectF(0, 0, imageWidth, imageHeight); 
    RectF outRect = new RectF(0, 0, scaledImageWidth, scaledImageHeight); 
    m.setRectToRect(inRect, outRect, Matrix.ScaleToFit.CENTER); 
    float[] values = new float[9]; 
    m.getValues(values); 

    // create a scaled bitmap with required file size 
    Bitmap scaledBitmap = Bitmap.createScaledBitmap(imageBitmap, (int) (imageWidth*values[0]), (int) (imageHeight*values[4]), true); 

    // delete original image 
    new File(imageUri.getPath()).delete(); 

    // write bitmap to file 
    File newImageFile = BaseResourceClass.makeTempResourceFile(Slide.ResourceType.IMAGE, context); 
    try { 
     newImageFile.createNewFile(); 
     FileOutputStream fos = new FileOutputStream(newImageFile); 
     scaledBitmap.compress(Bitmap.CompressFormat.PNG, 1, fos); 
     fos.close(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
     Toast.makeText(context, "Something went wrong", Toast.LENGTH_SHORT).show(); 
    } 

    // recycle bitmaps to reallocate memory 
    Storage.recycleBitmap(imageBitmap); 
    Storage.recycleBitmap(scaledBitmap); 

    // scaling done, return new Image 
    return Uri.fromFile(newImageFile); 
} 

當這個方法運行,圖像尺寸得到縮小到確切大小(如在什麼我希望它是),但在KB的圖像大小不按比例縮小由相同的因素。例如,運行此方法後,我得到了以下數字

before resizing 
imageWidth : 3120, imageHeight : 4160, fileSize : 2960 KB 

after resizing 
imageWidth : 1395, imageHeight : 1860, fileSize : 2491 KB 

我不明白,從圖像消除這麼多的像素之後,究竟是什麼佔用了這麼大的空間,以保持圖像文件的大小這麼多。試圖看看其他的StackOverflow問題和Android的BitmapFactory和Bitmap類文檔,但這個問題沒有提到。任何幫助,將不勝感激!

回答

1

發生這種情況的原因很多,取決於您正在閱讀的圖像類型(JPG,GIF,PNG,BMP),壓縮的質量(如果是JPG) ,以及在縮小圖像尺寸後如何保存它。

在您的示例中,您不顯示使用的圖像或圖像使用的壓縮類型。但從代碼中我看到您將它保存爲PNG圖像。

如果您拍攝高品質的2MB jpg圖像,並且像您一樣縮小尺寸,但將其保存爲PNG(無損質量),則可能會得到比以前更大的文件。

JPG圖像使用壓縮算法將圖像存儲爲儘可能與原始圖像相似但佔用的空間少得多。根據質量的不同,您可以獲得幾乎與原始文件大小相同的圖像,或者只有幾千字節的可怕圖像。

當您將圖像保存爲PNG時,您會得到與原始圖像完全相同的圖像(這就是爲什麼它被稱爲無損),並且這樣,您無法通過壓縮保存很多文件大小。

如果您使用PNG作爲輸入,並將簡化版本保存爲PNG,那麼您可能會更接近「比例文件大小」的想法。儘管縮小尺寸可以通過抗鋸齒在結果圖像中創建新的顏色,並降低壓縮性能。

使用JPG圖像會使原始圖像和用於壓縮結果的圖像質量有點不可預知,這兩者都會影響結果的文件大小。

0

如果圖像未壓縮,您可以預期圖像文件大小與圖像寬度x高度成正比。這僅適用於BMP格式。

您正在處理以PNG格式存儲的圖像。 PNG是使用壓縮來存儲圖像。這就是爲什麼圖像尺寸更多取決於圖像具有多少細節以及圖像寬度較低的原因。

在你的案例中,圖像大小主要取決於第二個參數,質量。

scaledBitmap.compress(Bitmap.CompressFormat.PNG,,fos);

您可以將其更改爲0以使文件更小。

image