0

我在尝试使用 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();
    }

  }

这两者都会产生同样非常糟糕的图像。我在下面发布了之前和之后的部分。这就是相机预览的样子。

这就是相机预览的样子。

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

在与几个人交谈后,我将我的相机意图代码包括在内:

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

            }
        }
  }
4

1 回答 1

4

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

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

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

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

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);
于 2014-12-18T09:54:01.350 回答