2017-04-18 196 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