web-dev-qa-db-ja.com

Android-ビットマップを拡大縮小して圧縮する

Androidアプリで、カメラのキャプチャと写真のアップロード機能を使用しています。デバイスに高解像度のカメラが搭載されている場合、キャプチャされる画像のサイズは非常に大きくなります(1〜3MB以上)。 。
アプリはこの画像をサーバーにアップロードする必要があるため、アップロードする前に画像を圧縮する必要があります。たとえば、カメラが1920x1080のフル解像度の写真をキャプチャした場合、理想的な出力は、画像の比率を16:9に保ち、画像を640x360の画像に圧縮して画質を低下させ、バイト単位のサイズを小さくすることです。

これが私のコードです(グーグルから参照):

/**
 * 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

写真をスムーズにアップロードできるように、写真を圧縮するためのより良い方法の提案があるかどうかを尋ねています。

7
Allan Jiang
  1. 幅または高さのいずれかの制限を決定する必要があります(明らかに両方ではありません)。次に、これらの固定画像サイズを計算されたものに置き換えます。

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

    (必要に応じて、横向き/縦向きのチェックと計算の選択肢を追加します。)

  2. @harismもコメントしているように、あなたが言及した大きなサイズは、その480x800ビットマップのrawサイズであり、ファイルサイズではありません。場合。ところで、そのビットマップをどのように保存しますか?コードに保存部分が含まれていないようです。

    それに関するヘルプについては この質問はこちら を参照してください。キーは次のようなものです。

    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);
    
12
Sz.

まず、画像のサイズを確認し、サイズに応じて画像を圧縮して圧縮ビットマップを取得し、そのビットマップをサーバーに送信します関数の下の圧縮ビットマップ呼び出しの場合、関数の下に画像パスを渡す必要があります

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