Android 从设备相机保存 PNG(质量差)

jam*_*z77 0 png android bitmapimage image-quality

我在尝试使用 Android 应用程序将照片保存到存储时遇到问题。该应用程序使用设备相机拍摄照片并将其以 PNG 格式保存到设备。

由于某种原因,无论我做什么或将图像存储在哪里,质量都很差。该应用程序是一个相当大的现有项目,因此我想知道将图像保存到设备时是否需要考虑其他因素,或者可能是另一种覆盖质量的方法。

这是以前的开发人员编写的函数:

public String saveImageToDevice(Bitmap image) {
    saveCanvasImage(image);

    String root = Environment.getExternalStorageDirectory().toString()+"/Android/data/com.app.android";
    File myDir = new File(root + "/saved_images");    
    myDir.mkdirs();

    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String fname = "Image-"+ timeStamp +".png";
    File file = new File (myDir, fname);
    if (file.exists ()){ 
        file.delete ();
    } 
    try {




       Toast.makeText(getActivity(), "Saving Image...", Toast.LENGTH_SHORT).show();
       Log.i("Image saved", root+"/saved_images/"+fname);
       FileOutputStream out = new FileOutputStream(file);
       image.compress(CompressFormat.PNG, 100, out);
       imageLocations.add(fname);
       out.flush();
       out.close();


       //return myDir.getAbsolutePath() + "/" +fname;
       return fname;

    } catch (Exception e) {
           e.printStackTrace();
           return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我自己从网上的例子中尝试过的一个功能:

public void saveCanvasImage(Bitmap b) {

    File f = new File(Environment.getExternalStorageDirectory().toString() + "/img.png");



    try {

    f.createNewFile();  // your mistake was at here 

    FileOutputStream fos = new FileOutputStream(f);

    b.compress(CompressFormat.PNG, 100, fos);

    fos.flush();

    fos.close();

    }catch (IOException e){

        e.printStackTrace();
    }

  }
Run Code Online (Sandbox Code Playgroud)

这两种方法都会产生同样非常差的图像。我在下面发布了前后片段。这就是相机预览的样子。

这就是相机预览的样子。

这是保存后的结果图像。 这是保存后的结果图像。

在与一些人交谈后,我添加了我的相机意图代码:

public void startCameraIntent(){
    /*************************** Camera Intent Start ************************/        
    // Define the file-name to save photo taken by Camera activity         
    String fileName = "Camera_Example.png";        
    // Create parameters for Intent with filename
    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.TITLE, fileName);
    values.put(MediaStore.Images.Media.DESCRIPTION,"Image capture by camera");
    // imageUri is the current activity attribute, define and save it for later usage  
    @SuppressWarnings("unused")
    Uri imageUri = getActivity().getContentResolver().insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    /**** EXTERNAL_CONTENT_URI : style URI for the "primary" external storage volume. ****/


    // Standard Intent action that can be sent to have the camera
    // application capture an image and return it.  
    Intent intent = new Intent( MediaStore.ACTION_IMAGE_CAPTURE );
    //intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);   // set the image file name      

    startActivityForResult( intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);


 /*************************** Camera Intent End ************************/
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,EXTRA_OUTPUT 行已被注释掉,因为它会导致崩溃并出现以下错误:

12-17 13:31:37.339: E/AndroidRuntime(16123): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=65537, result=-1, data=null} to activity {}: java.lang.NullPointerException
Run Code Online (Sandbox Code Playgroud)

我还包含了我的 onActivityresult 代码:

    public void onActivityResult( int requestCode, int resultCode, Intent data)
{
    super.onActivityResult(requestCode, resultCode, data);


    int page = mViewPager.getCurrentItem();
    NotesPagerFragment  note = pages.get(page);
    Log.i("Request Code", ""+requestCode);
        //For the ImageCapture Activity
        if ( requestCode == 1) {

              if ( resultCode != 0) {
                 /*********** Load Captured Image And Data Start ****************/
                 Bitmap bp = (Bitmap) data.getExtras().get("data");
                 //add the image to the note through a function call
                 note.addImage(bp);
                 note.saveImageToDevice(bp);
                  //String imageId = convertImageUriToFile( imageUri,CameraActivity);                       
                 //  Create and excecute AsyncTask to load capture image
                 // new LoadImagesFromSDCard().execute(""+imageId);                      
                /*********** Load Captured Image And Data End ****************/                    
              } else if ( resultCode == 0) {
                  Toast.makeText(this.getActivity(), " Picture was not taken ", Toast.LENGTH_SHORT).show();
              } else {

                  Toast.makeText(this.getActivity(), " Picture was not taken ", Toast.LENGTH_SHORT).show();
              }
          }

        //For the deleting an Image
        if (requestCode == 2) {
            String location = (String) data.getExtras().get("imageLocation");
            if(data.getExtras().get("back") != null){
                //just going back, don't mind me
            }else {
                //Toast.makeText(this.getActivity(), "BOO", Toast.LENGTH_SHORT).show();
                note.removeNoteImageFromView(location);
                database.removeSingleNoteImageFromSystemByLocation(location);

            }
        }
  }
Run Code Online (Sandbox Code Playgroud)

jam*_*z77 5

好的,在Melquiades的大力帮助下,我最终解决了这个问题。我遇到的问题是我的意图和 onActivityResult 正在检索图像的缩略图并将其放大(因此质量很差)。

\n

下面的代码行负责获取缩略图预览 (120px x 160px):

\n
Bitmap bp = (Bitmap) data.getExtras().get("data");\n
Run Code Online (Sandbox Code Playgroud)\n

为了访问完整图像,我需要将 EXTRA_OUTPUT 添加到意图中,如下所示:

\n
public void startCameraIntent(){\n    /*************************** Camera Intent Start ************************/        \n    File imageFile = new File(imageFilePath); \n    Uri imageFileUri = Uri.fromFile(imageFile); // convert path to Uri\n    \n    // Standard Intent action that can be sent to have the camera\n    // application capture an image and return it.  \n    Intent intent = new Intent( MediaStore.ACTION_IMAGE_CAPTURE );\n    intent.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri);   // set the image file name      \n    \n    startActivityForResult( intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);\n    \n    \n /*************************** Camera Intent End ************************/\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我还在活动顶部将 imageFilePath 声明为字符串:

\n
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());\nString imageFilePath = Environment.getExternalStorageDirectory().toString()+"/Android/data/com.my.app/Image-"+timeStamp+".png";\n
Run Code Online (Sandbox Code Playgroud)\n

然后我必须更改 onActivityResult 以便它可以访问完整图像以使用:

\n
public void onActivityResult( int requestCode, int resultCode, Intent data){\n    super.onActivityResult(requestCode, resultCode, data);\n    \n    int page = mViewPager.getCurrentItem();\n    NotesPagerFragment  note = pages.get(page);\n    Log.i("Request Code", ""+requestCode);\n        //For the ImageCapture Activity\n        if ( requestCode == 1) {\n               \n              if ( resultCode != 0) {\n                 /*********** Load Captured Image And Data Start ****************/\n                  \n                  // Decode it for real \n                 BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();\n                 bmpFactoryOptions.inJustDecodeBounds = false; \n\n                //imageFilePath image path which you pass with intent \n                 Bitmap bp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions); \n                 \n                 //rotate image by 90 degrees\n                 Matrix rotateMatrix = new Matrix();\n                 rotateMatrix.postRotate(90);\n                 Bitmap rotatedBitmap = Bitmap.createBitmap(bp, 0, 0, bp.getWidth(), bp.getHeight(), rotateMatrix, false);\n                \n                //add the image to the note through a function call\n                 note.addImage(rotatedBitmap);\n                 note.saveImageToDevice(rotatedBitmap);\n                  //String imageId = convertImageUriToFile( imageUri,CameraActivity);                       \n                 //  Create and excecute AsyncTask to load capture image\n                 // new LoadImagesFromSDCard().execute(""+imageId);                      \n                /*********** Load Captured Image And Data End ****************/   \n                 \n              } else if ( resultCode == 0) {\n                  Toast.makeText(this.getActivity(), " Picture was not taken ", Toast.LENGTH_SHORT).show();\n              } else {\n                   \n                  Toast.makeText(this.getActivity(), " Picture was not taken ", Toast.LENGTH_SHORT).show();\n              }\n          }\n        \n        //For the deleting an Image\n        if (requestCode == 2) {\n            String location = (String) data.getExtras().get("imageLocation");\n            if(data.getExtras().get("back") != null){\n                //just going back, don\'t mind me\n            }else {\n                //Toast.makeText(this.getActivity(), "BOO", Toast.LENGTH_SHORT).show();\n                note.removeNoteImageFromView(location);\n                database.removeSingleNoteImageFromSystemByLocation(location);\n                \n            }\n        }\n  }\n
Run Code Online (Sandbox Code Playgroud)\n

这里的关键部分是:

\n
 // Decode it for real \n BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();\n bmpFactoryOptions.inJustDecodeBounds = false; \n\n //imageFilePath image path which you pass with intent \n Bitmap bp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions); \n
Run Code Online (Sandbox Code Playgroud)\n

此代码将您在 imageFilePath 中保存的图像解码为可用的位图。从这里您可以正常使用它。

\n

有时(显然这很常见)图像旋转了 90\xc2\xb0,如果您需要的话,下一段代码会将其旋转回来:

\n
//rotate image by 90 degrees\nMatrix rotateMatrix = new Matrix();\nrotateMatrix.postRotate(90);\nBitmap rotatedBitmap = Bitmap.createBitmap(bp, 0, 0, bp.getWidth(), bp.getHeight(), rotateMatrix, false);\n
Run Code Online (Sandbox Code Playgroud)\n