Android - 缩放和压缩位图

时间:2013-12-15 21:08:58

标签: java android image image-processing bitmap

我正在开发一款Android应用,它具有相机捕捉和照片上传功能。如果设备具有高分辨率相机,则捕获的图像尺寸将非常大(1~3MB或更多)。
由于应用程序需要将此图像上传到服务器,我需要在上传之前压缩图像。例如,如果相机拍摄的是1920x1080全分辨率照片,理想的输出是保持16:9的图像比例,将其压缩为640x360图像以降低图像质量并使其以字节为单位缩小。 / p>

这是我的代码(从谷歌引用):

/**
 * this class provide methods that can help compress the image size.
 *
 */
public class ImageCompressHelper {

/**
 * Calcuate how much to compress the image
 * @param options
 * @param reqWidth
 * @param reqHeight
 * @return
 */
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) {

    final int halfHeight = height / 2;
    final int halfWidth = width / 2;

    // Calculate the largest inSampleSize value that is a power of 2 and keeps both
    // height and width larger than the requested height and width.
    while ((halfHeight / inSampleSize) > reqHeight
            && (halfWidth / inSampleSize) > reqWidth) {
        inSampleSize *= 2;
    }
}

return inSampleSize;
}

/**
 * resize image to 480x800
 * @param filePath
 * @return
 */
public static Bitmap getSmallBitmap(String filePath) {

    File file = new File(filePath);
    long originalSize = file.length();

    MyLogger.Verbose("Original image size is: " + originalSize + " bytes.");

    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(filePath, options);

    // Calculate inSampleSize based on a preset ratio
    options.inSampleSize = calculateInSampleSize(options, 480, 800);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;

    Bitmap compressedImage = BitmapFactory.decodeFile(filePath, options);

    MyLogger.Verbose("Compressed image size is " + sizeOf(compressedImage) + " bytes");

    return compressedImage;
}

上述代码的问题是:

  1. 无法保持比例,代码强制图像调整为480x800。如果用户以另一个比例拍摄图像,压缩后图像看起来不会很好。
  2. 效果不佳。无论原始文件大小是多少,代码都会始终将图像大小更改为7990272byte。如果原始图像尺寸已经非常小,它会变得很大(我的测试结果是拍摄我的墙,这是非常单色的):

    Original image size is: 990092 bytes.
    Compressed image size is 7990272 bytes

  3. 我在问是否有更好的方法压缩照片以便顺利上传?

2 个答案:

答案 0 :(得分:12)

  1. 您需要决定宽度或高度的限制(显然不是两者)。然后用计算的图像替换那些固定的图像尺寸,例如:

    int targetWidth = 640; // your arbitrary fixed limit
    int targetHeight = (int) (originalHeight * targetWidth / (double) originalWidth); // casts to avoid truncating
    

    (根据需要添加横向/纵向方向的检查和计算方法。)

  2. 正如@harism所评论的那样:你提到的大尺寸是480x800位图的原始大小,而不是文件大小,在你的情况下应该是JPEG。你打算如何保存这个位图,BTW?您的代码似乎不包含保存部分。

    请参阅this question here获取相关帮助,其中包含以下内容:

    OutputStream imagefile = new FileOutputStream("/your/file/name.jpg");
    // Write 'bitmap' to file using JPEG and 80% quality hint for JPEG:
    bitmap.compress(CompressFormat.JPEG, 80, imagefile);
    

答案 1 :(得分:2)

首先我检查图像的大小然后根据大小压缩图像并获得压缩的位图然后将该位图发送到服务器 对于压缩位图调用功能,我们必须在下面的功能中传递图像路径

public Bitmap get_Picture_bitmap(String imagePath) {

    long size_file = getFileSize(new File(imagePath));

    size_file = (size_file) / 1000;// in Kb now
    int ample_size = 1;

    if (size_file <= 250) {

        System.out.println("SSSSS1111= " + size_file);
        ample_size = 2;

    } else if (size_file > 251 && size_file < 1500) {

        System.out.println("SSSSS2222= " + size_file);
        ample_size = 4;

    } else if (size_file >= 1500 && size_file < 3000) {

        System.out.println("SSSSS3333= " + size_file);
        ample_size = 8;

    } else if (size_file >= 3000 && size_file <= 4500) {

        System.out.println("SSSSS4444= " + size_file);
        ample_size = 12;

    } else if (size_file >= 4500) {

        System.out.println("SSSSS4444= " + size_file);
        ample_size = 16;
    }

    Bitmap bitmap = null;

    BitmapFactory.Options bitoption = new BitmapFactory.Options();
    bitoption.inSampleSize = ample_size;

    Bitmap bitmapPhoto = BitmapFactory.decodeFile(imagePath, bitoption);

    ExifInterface exif = null;
    try {
        exif = new ExifInterface(imagePath);
    } catch (IOException e) {
        // Auto-generated catch block
        e.printStackTrace();
    }
    int orientation = exif
            .getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
    Matrix matrix = new Matrix();

    if ((orientation == 3)) {
        matrix.postRotate(180);
        bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0,
                bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix,
                true);

    } else if (orientation == 6) {
        matrix.postRotate(90);
        bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0,
                bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix,
                true);

    } else if (orientation == 8) {
        matrix.postRotate(270);
        bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0,
                bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix,
                true);

    } else {
        matrix.postRotate(0);
        bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0,
                bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix,
                true);

    }

    return bitmap;

}

获取图片大小的getFileSize功能

    public long getFileSize(final File file) {
    if (file == null || !file.exists())
        return 0;
    if (!file.isDirectory())
        return file.length();
    final List<File> dirs = new LinkedList<File>();
    dirs.add(file);
    long result = 0;
    while (!dirs.isEmpty()) {
        final File dir = dirs.remove(0);
        if (!dir.exists())
            continue;
        final File[] listFiles = dir.listFiles();
        if (listFiles == null || listFiles.length == 0)
            continue;
        for (final File child : listFiles) {
            result += child.length();
            if (child.isDirectory())
                dirs.add(child);
        }
    }

    return result;
}