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

时间:2014-12-17 12:47:26

标签: android png 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;
    }
}

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

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

  }

这两者都产生相同的非常差的图像。我在下面发布了一个前后段。 这就是相机预览的样子。

This is what the camera preview looks like.

这是保存后生成的图像。 This is the resulting image once it has saved.

在与少数人交谈后,我收到了我的相机意图代码:

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

正如您所看到的,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

我也包含了我的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);

            }
        }
  }

1 个答案:

答案 0 :(得分:3)

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

以下行负责获取缩略图预览(120px x 160px):

Bitmap bp = (Bitmap) data.getExtras().get("data");

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

public void startCameraIntent(){
    /*************************** Camera Intent Start ************************/        
    File imageFile = new File(imageFilePath); 
    Uri imageFileUri = Uri.fromFile(imageFile); // convert path to Uri

    // 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, imageFileUri);   // set the image file name      

    startActivityForResult( intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);


 /*************************** Camera Intent End ************************/
}

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

String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFilePath = Environment.getExternalStorageDirectory().toString()+"/Android/data/com.my.app/Image-"+timeStamp+".png";

然后,我必须更改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 ****************/

                  // Decode it for real 
                 BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
                 bmpFactoryOptions.inJustDecodeBounds = false; 

                //imageFilePath image path which you pass with intent 
                 Bitmap bp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions); 

                 //rotate image by 90 degrees
                 Matrix rotateMatrix = new Matrix();
                 rotateMatrix.postRotate(90);
                 Bitmap rotatedBitmap = Bitmap.createBitmap(bp, 0, 0, bp.getWidth(), bp.getHeight(), rotateMatrix, false);

                //add the image to the note through a function call
                 note.addImage(rotatedBitmap);
                 note.saveImageToDevice(rotatedBitmap);
                  //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);

            }
        }
  }

这里的关键部分是:

 // Decode it for real 
 BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
 bmpFactoryOptions.inJustDecodeBounds = false; 

 //imageFilePath image path which you pass with intent 
 Bitmap bp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions); 

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

有时候(显然这很常见)图像会旋转90°,如果需要,下一位代码会旋转回来:

//rotate image by 90 degrees
Matrix rotateMatrix = new Matrix();
rotateMatrix.postRotate(90);
Bitmap rotatedBitmap = Bitmap.createBitmap(bp, 0, 0, bp.getWidth(), bp.getHeight(), rotateMatrix, false);