1

我有一个需要调整图像大小然后将其保存为 jpg 的应用程序。我的测试图像是一张天空中渐变非常平滑的照片。我正在尝试使用以下代码调整大小后将其保存为 jpeg:

dstBmp = Bitmap.createBitmap(srcBmp, cropX, 0, tWidth, srcBmp.getHeight());
if (android.os.Build.VERSION.SDK_INT > 12) {
    Log.w("General", "Calling setHasAlpha");
    dstBmp.setHasAlpha(true);
}
dstBmp = Bitmap.createScaledBitmap(dstBmp, scaledSmaller, scaledLarger, true);
OutputStream out = null;
File f = new File(directory + "/f"+x+".jpg");
try {
    f.createNewFile();
    out = new FileOutputStream(f);
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

dstBmp.compress(CompressFormat.JPEG, jpegQuality, out);

问题是图像的渐变中会出现过多的条带,除非我将质量提高到 95 左右。但是,在质量级别 95 下,生成的文件超过 150kb。当我在 Photoshop 中执行这些相同的功能并执行“保存为网络”时,我可以避免使用 50kb 的图像大小一直到质量级别 40 的条带。在我的网络服务器上使用 ImageCR,我可以在 30kb 上完成同样的任务。

Java中是否有任何方法可以更有效地将图像压缩为jpeg,或者我可以使用单独的库或api来做到这一点?我正在将大量图像加载到内存中,以这种速度,该应用程序正在威胁旧设备上的 OOM 错误。如果这有助于最终结果,我很乐意为图像处理分配更多时间。

4

1 回答 1

3

从http://developer.android.com/training/displaying-bitmaps/load-bitmap.html试试这个代码

简而言之,您有 2 个静态方法

第一个用于计算图像的新大小

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) {

    // Calculate ratios of height and width to requested height and width
    final int heightRatio = Math.round((float) height / (float) reqHeight);
    final int widthRatio = Math.round((float) width / (float) reqWidth);

    // Choose the smallest ratio as inSampleSize value, this will guarantee
    // a final image with both dimensions larger than or equal to the
    // requested height and width.
    inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}

return inSampleSize;
}

第二个用于将缩放大小的图像加载到内存中:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
    int reqWidth, int reqHeight) {

// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);

// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}

你可以这样调用这个函数:

Bitmap b = decodeSampledBitmapFromResource(getResources(), R.id.myimage, 128, 128));

您可以修改第二种方法以使用输入参数字符串(如果图像是 sdcard 上的文件,则为路径)而不是资源,而不是使用 decodeResource:

BitmapFactory.decodeFile(path, options);

加载大图像时,我总是使用此代码。

于 2013-08-09T14:18:35.433 回答