【问题标题】:Android - Scale and compress a bitmapAndroid - 缩放和压缩位图
【发布时间】:2014-01-03 04:32:41
【问题描述】:

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

这是我的代码(来自google):

/**
 * 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. 它不能正常工作。无论原始文件大小如何,代码都会始终将图像大小更改为 7990272 字节。如果原始图像尺寸已经很小,它会变大(我的测试结果是给我的墙拍照,它几乎是单色的):

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

请问有没有更好的压缩照片的方法,可以顺利上传?

【问题讨论】:

  • 而不是使用硬编码的 480x800 大小 - 您应该计算一个动态输出位图大小,以保持所需的纵横比,即横向和纵向变化。对于图像大小 - 请记住,您将原始 压缩 文件大小与缩放 未压缩 位图大小进行比较。

标签: java android image image-processing bitmap


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:
    1. 您需要确定宽度或高度的限制(显然不是两者)。然后将那些固定的图像尺寸替换为计算出来的尺寸,比如:

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

      (根据需要为横向/纵向添加检查和计算选项。)

    2. 正如@harism 还评论的那样:您提到的大尺寸是该 480x800 位图的 raw 大小,而不是文件大小,在您的情况下应该是 JPEG。顺便说一句,您打算如何保存该位图?您的代码似乎不包含保存部分。

      请参阅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);
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-15
      • 1970-01-01
      • 1970-01-01
      • 2015-04-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多