安卓 - 如何缩放、旋转并保存位图到SD卡而不失去质量

3

我正在开发一个应用程序,它使用相机拍照后旋转和缩放图片。因为相机返回的图像是错误旋转的,所以我需要旋转图像,并缩小图像以减小其大小。 我首先将相机返回的原始图像保存在临时目录中,然后读取它并进行修改,将新图像保存到新文件中。 我尝试使用矩阵来旋转和缩放图片,但它会失去质量。 然后我尝试先使用Bitmap.createScaledBitmap缩放图片,然后再使用矩阵旋转图片,但结果比仅使用矩阵更难看。 然后我尝试先旋转图像,然后再使用Bitmap.createScaledBitmap调整大小。图像不会失去质量,但由于在旋转后缩放,宽度和高度被反转。我也尝试根据所做的旋转反转高度和宽度,但它再次失去了质量。 这是我最近编写的代码:

in= new FileInputStream(tempDir+"/"+photo1_path);
            out = new FileOutputStream(file+"/picture.png");
            Bitmap src = BitmapFactory.decodeStream(in);
            int iwidth = src.getWidth();
            int iheight = src.getHeight();
            int newWidth = 0;
            int newHeight = 0;

                newWidth = 800;
                newHeight = 600;

              // calculate the scale - in this case = 0.4f
              float scaleWidth = ((float) newWidth) / iwidth;
              float scaleHeight = ((float) newHeight) / iheight;

              // createa matrix for the manipulation
              Matrix matrix = new Matrix();
              // resize the bit map
              //matrix.postScale(scaleWidth, scaleHeight);
              int orientation = getOrientation(MyActivity.this,Uri.parse(tempDir+"/"+photo1_path));
              switch(orientation) {
                case 3:
                    orientation = 180;
                    break;
                case 6:
                    orientation = 90;
                   break;
                case 8:
                    orientation = 270;
                    break;
              }
              int rotate = 0;
              switch(orientation) {
                case 90:
                    rotate=90;
                    break;
                case 180:
                    rotate=180;
                    break;
                case 270:
                    rotate=270;
                    break;

              }
              // rotate the Bitmap
              matrix.postRotate(rotate);

              src =Bitmap.createScaledBitmap(src , newWidth, newHeight, false);
              // recreate the new Bitmap
              Bitmap new_bit = Bitmap.createBitmap(src, 0, 0,
                                src.getWidth(), src.getHeight(), matrix, true);
                      new_bit.compress(Bitmap.CompressFormat.PNG, 100, out);

有什么建议吗?

编辑:如果我只旋转或只缩放图像,它不会失去质量。只有当我两者都做时,图像才会失去质量。此外,如果我在调整大小和缩放后将图像放入ImageView中,它不会失去质量,只有在保存到文件时才会失去质量。

3个回答

4
解决了!我使用BitmapFactory的inSampleSize选项调整图片大小,图片质量没有任何损失。 代码:
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = true;
Bitmap bm = BitmapFactory.decodeFile(tempDir+"/"+photo1_path , bmpFactoryOptions);


int heightRatio = (int)Math.ceil(bmpFactoryOptions.outHeight/(float)600);
int widthRatio = (int)Math.ceil(bmpFactoryOptions.outWidth/(float)800);

if (heightRatio > 1 || widthRatio > 1)
{
    if (heightRatio > widthRatio){
        bmpFactoryOptions.inSampleSize = heightRatio;
    } else {
        bmpFactoryOptions.inSampleSize = widthRatio; 
    } 
}

bmpFactoryOptions.inJustDecodeBounds = false;
bm = BitmapFactory.decodeFile(tempDir+"/"+photo1_path, bmpFactoryOptions);
//bm.compress(Bitmap.CompressFormat.PNG, 100, out);
/*Bitmap new_bit = Bitmap.createScaledBitmap(src , newWidth, newHeight, true);
            new_bit.compress(Bitmap.CompressFormat.PNG, 100, out);*/


// recreate the new Bitmap
src = Bitmap.createBitmap(bm, 0, 0,bm.getWidth(), bm.getHeight(), matrix, true);


//Bitmap dest = Bitmap.createScaledBitmap(new_bit , newWidth, newHeight, true);
src.compress(Bitmap.CompressFormat.PNG, 100, out);

Bitmap.CompressFormat.PNG 的问题在于每次旋转后文件大小会变得更大。 - Yoann Hercouet

0

使用这个方法来旋转位图...

private Bitmap checkifImageRotated() {
    ExifInterface exif;
    try {
        exif = new ExifInterface(file.getAbsolutePath());
        int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
        int rotate = 0;
        switch (orientation) {
            case ExifInterface.ORIENTATION_ROTATE_270 :
                rotate = -90;
                break;
            case ExifInterface.ORIENTATION_ROTATE_180 :
                rotate = 180;
                break;
            case ExifInterface.ORIENTATION_ROTATE_90 :
                rotate = 90;
                break;
        }
        if (rotate != 0) {
            Bitmap bitmap = BitmapFactory.decodeFile(getTempFile().getPath());
            Matrix matrix = new Matrix();
            matrix.setRotate(rotate);
            Bitmap bmpRotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
            recycle(bitmap);
            return bmpRotated;
        }
    }
    catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;
}

谢谢,我刚试了一下,但是没有任何改变,它总是失去质量。无论如何,您也使用矩阵来旋转图像,因此即使使用ExifInterface获取方向,也有可能什么都不会改变 :( - dany84

0
不要新建位图,只需覆盖原有的。
int angle=0; int valueangle=0; Bitmap bitmap;
        @Override
        public void onClick(View v) {

            System.out.println("valueeeeeee  " + angle);
            if (bitmap != null) {

                angle = valueangle + 90;



                Matrix matrix = new Matrix();
                matrix.postRotate(angle);

                bitmap = Bitmap.createBitmap(
                        bitmap , 0, 0,
                        bitmap .getWidth(),
                        bitmap .getHeight(), matrix, true);



                main_img.setImageBitmap(bitmap );

            } else {

                System.out.println(" bitmap is null");
            }

        }

谢谢,我刚刚尝试了覆盖,但结果是一样的,图像失去了质量。我没有像你那样将位图放在ImageView中,这可能会改变一些东西吗? - dany84
如果这段代码对您有所帮助,请接受并点赞。意思是要适当地解释更改的内容。 - Rishi Gautam
不要一遍又一遍地对位图进行缩放,然后对该位图执行任何操作时,如果你多次旋转它,它不会失去质量,只有在你第一次缩放位图时才会降低其质量。 - Rishi Gautam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接