UFO ET IT

카메라 의도 사진 촬영 후 갤러리 이미지 삭제

ufoet 2020. 11. 21. 08:38
반응형

카메라 의도 사진 촬영 후 갤러리 이미지 삭제


여러 가지 방법으로 요청을 받았지만 여전히 기본 폴더에서 갤러리 이미지를 삭제할 수없는 것 같습니다. 파일을 SD 카드에 올바르게 저장하고 있으며 해당 파일을 잘 삭제할 수 있지만 카메라 폴더 아래에 표시되는 기본 갤러리 이미지 파일은 삭제되지 않습니다.

파일이 이미 SD 카드에 저장되어 있으므로 활동이 반환되면 이미지를 삭제하고 싶습니다 /Coupon2.

어떤 제안?

public void startCamera() {
    Log.d("ANDRO_CAMERA", "Starting camera on the phone...");

    mManufacturerText = (EditText) findViewById(R.id.manufacturer);
    String ManufacturerText = mManufacturerText.getText().toString();
    String currentDateTimeString = new Date().toString();

    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    File filedir = new File(Environment.getExternalStorageDirectory()+"/Coupon2");
    filedir.mkdirs();

    File file = new File(Environment.getExternalStorageDirectory()+"/Coupon2", ManufacturerText+"-test.png");
    outputFileUri = Uri.fromFile(file);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);

    startActivityForResult(intent, CAMERA_PIC_REQUEST);
}

protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == CAMERA_PIC_REQUEST && resultCode == -1) {  
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.putExtra("crop", "true");
        intent.putExtra("scale", "true");

        intent.putExtra("return-data", false);
        intent.setDataAndType(outputFileUri, "image/*");
        intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
        startActivityForResult(intent, CAMERA_CROP_REQUEST);
    }else { 
        SetImage();
        saveState();
    }
}

내 신청서에 사진을 찍으려면 전화를 걸어야합니다. 사진은 갤러리에있을 수 없지만 대신 SD 카드의 특정 디렉토리에 있어야합니다.

원래 EXTRA_OUTPUT을 사용했지만 곧 다음을 발견했습니다.-일부 장치는이를 완전히 사용하고 갤러리를 건너 뜁니다. -일부 장치는이를 완전히 무시하고 갤러리 만 사용합니다. -일부 장치는 실제로 전체 크기의 이미지를 갤러리에 저장하고 원하는 위치에만 축소판을 저장합니다. (HTC는 당신이 누군지 알고 있습니다 ...)

따라서 작업이 끝나면 갤러리 파일을 맹목적으로 삭제할 수 없습니다. 마지막으로 추가 된 사진이 제거하려는 사진 일 수도 있고 아닐 수도 있습니다. 또한 나중에 해당 파일을 복사해야 할 수도 있습니다. 내 활동이 2000 줄이고 회사에서 모든 코드가 게시되는 것을 원하지 않기 때문에이 작업과 관련된 방법 만 게시하고 있습니다. 도움이 되었기를 바랍니다.

또한 이것이 저의 첫 번째 Android 애플리케이션입니다. 내가 알지 못하는이 작업을 수행하는 더 좋은 방법이 있다면 놀라지 않을 것입니다. 그러나 이것이 저에게 효과가있는 것입니다!

그래서 여기 내 해결책이 있습니다.

첫째, 내 응용 프로그램 컨텍스트에서 다음과 같이 변수를 정의합니다.

public ArrayList<String> GalleryList = new ArrayList<String>();

다음으로 내 활동에서 갤러리의 모든 사진 목록을 가져 오는 방법을 정의합니다.

private void FillPhotoList()
{
   // initialize the list!
   app.GalleryList.clear();
   String[] projection = { MediaStore.Images.ImageColumns.DISPLAY_NAME };
   // intialize the Uri and the Cursor, and the current expected size.
   Cursor c = null; 
   Uri u = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
   //
   // Query the Uri to get the data path.  Only if the Uri is valid.
   if (u != null)
   {
      c = managedQuery(u, projection, null, null, null);
   }

   // If we found the cursor and found a record in it (we also have the id).
   if ((c != null) && (c.moveToFirst())) 
   {
      do 
      {
        // Loop each and add to the list.
        app.GalleryList.add(c.getString(0));
      }     
      while (c.moveToNext());
   }
}

새 이미지의 고유 한 파일 이름을 반환하는 방법은 다음과 같습니다.

private String getTempFileString()
{
   // Only one time will we grab this location.
   final File path = new File(Environment.getExternalStorageDirectory(), 
         getString(getApplicationInfo().labelRes));
   //
   // If this does not exist, we can create it here.
   if (!path.exists())
   {
      path.mkdir();
   }
   //
   return new File(path, String.valueOf(System.currentTimeMillis()) + ".jpg").getPath();
}

현재 파일에 대한 정보를 저장하는 세 가지 변수가 내 활동에 있습니다. 문자열 (경로), 파일 변수 및 해당 파일에 대한 URI :

public static String sFilePath = ""; 
public static File CurrentFile = null;
public static Uri CurrentUri = null;

직접 설정하지 않고 파일 경로에서 setter 만 호출합니다.

public void setsFilePath(String value)
{
   // We just updated this value. Set the property first.
   sFilePath = value;
   //
   // initialize these two
   CurrentFile = null;
   CurrentUri = null;
   //
   // If we have something real, setup the file and the Uri.
   if (!sFilePath.equalsIgnoreCase(""))
   {
      CurrentFile = new File(sFilePath);
      CurrentUri = Uri.fromFile(CurrentFile);
   }
}

이제 저는 사진을 찍으려고합니다.

public void startCamera()
{
   Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
   // Specify the output. This will be unique.
   setsFilePath(getTempFileString());
   //
   intent.putExtra(MediaStore.EXTRA_OUTPUT, CurrentUri);
   //
   // Keep a list for afterwards
   FillPhotoList();
   //
   // finally start the intent and wait for a result.
   startActivityForResult(intent, IMAGE_CAPTURE);
}

이 작업이 완료되고 활동이 돌아 오면 여기에 내 코드가 있습니다.

protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
   if (requestCode == IMAGE_CAPTURE)
   {
      // based on the result we either set the preview or show a quick toast splash.
      if (resultCode == RESULT_OK)
      {
         // This is ##### ridiculous.  Some versions of Android save
         // to the MediaStore as well.  Not sure why!  We don't know what
         // name Android will give either, so we get to search for this
         // manually and remove it.  
         String[] projection = { MediaStore.Images.ImageColumns.SIZE,
                                 MediaStore.Images.ImageColumns.DISPLAY_NAME,
                                 MediaStore.Images.ImageColumns.DATA,
                                 BaseColumns._ID,};
         //    
         // intialize the Uri and the Cursor, and the current expected size.
         Cursor c = null; 
         Uri u = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
         //
         if (CurrentFile != null)
         {               
            // Query the Uri to get the data path.  Only if the Uri is valid,
            // and we had a valid size to be searching for.
            if ((u != null) && (CurrentFile.length() > 0))
            {
               c = managedQuery(u, projection, null, null, null);
            }
            //   
            // If we found the cursor and found a record in it (we also have the size).
            if ((c != null) && (c.moveToFirst())) 
            {
               do 
               {
                  // Check each area in the gallary we built before.
                  boolean bFound = false;
                  for (String sGallery : app.GalleryList)
                  {
                     if (sGallery.equalsIgnoreCase(c.getString(1)))
                     {
                        bFound = true;
                        break;
                     }
                  }
                  //       
                  // To here we looped the full gallery.
                  if (!bFound)
                  {
                     // This is the NEW image.  If the size is bigger, copy it.
                     // Then delete it!
                     File f = new File(c.getString(2));

                     // Ensure it's there, check size, and delete!
                     if ((f.exists()) && (CurrentFile.length() < c.getLong(0)) && (CurrentFile.delete()))
                     {
                        // Finally we can stop the copy.
                        try
                        {
                           CurrentFile.createNewFile();
                           FileChannel source = null;
                           FileChannel destination = null;
                           try 
                           {
                              source = new FileInputStream(f).getChannel();
                              destination = new FileOutputStream(CurrentFile).getChannel();
                              destination.transferFrom(source, 0, source.size());
                           }
                           finally 
                           {
                              if (source != null) 
                              {
                                 source.close();
                              }
                              if (destination != null) 
                              {
                                 destination.close();
                              }
                           }
                        }
                        catch (IOException e)
                        {
                           // Could not copy the file over.
                           app.CallToast(PhotosActivity.this, getString(R.string.ErrorOccured), 0);
                        }
                     }
                     //       
                     ContentResolver cr = getContentResolver();
                     cr.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
                        BaseColumns._ID + "=" + c.getString(3), null);
                     break;                        
                  }
               } 
               while (c.moveToNext());
            }
         }
      }
   }      
}

누군가이 문제에 대한 더 간단한 해결 방법을 찾고 있다면 여기에 문제를 해결 한 방법이 있습니다.

캡처 버튼이 있고 눌렀을 때 의도가 전송되고 추가 한 것은 이미지 미디어 저장소에서 마지막 ID를 가져 와서 저장한다는 것입니다.

/**
 * Gets the last image id from the media store
 * @return
 */
private int getLastImageId(){
    final String[] imageColumns = { MediaStore.Images.Media._ID };
    final String imageOrderBy = MediaStore.Images.Media._ID+" DESC";
    final String imageWhere = null;
    final String[] imageArguments = null;
    Cursor imageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, imageWhere, imageArguments, imageOrderBy);
    if(imageCursor.moveToFirst()){
        int id = imageCursor.getInt(imageCursor.getColumnIndex(MediaStore.Images.Media._ID));
        imageCursor.close();
        return id;
    }else{
        return 0;
    }
}

그런 다음 활동이 반환되면이 코드를 실행하여 캡처 전 마지막 이미지 ID를 확인한 다음 캡처 후 이미지에 대한 쿼리의 ID가 기록 된 것보다 더 크며 그 이상이면 카메라에 대해 지정한 위치에있는 기록을 삭제합니다. 저장합니다.

/*
 * Checking for duplicate images
 * This is necessary because some camera implementation not only save where you want them to save but also in their default location.
 */
final String[] imageColumns = { MediaStore.Images.Media.DATA, MediaStore.Images.Media.DATE_TAKEN, MediaStore.Images.Media.SIZE, MediaStore.Images.Media._ID };
final String imageOrderBy = MediaStore.Images.Media._ID+" DESC";
final String imageWhere = MediaStore.Images.Media._ID+">?";
final String[] imageArguments = { Integer.toString(MyActivity.this.captureLastId) };
Cursor imageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, imageWhere, imageArguments, imageOrderBy);
if(imageCursor.getCount()>1){
    while(imageCursor.moveToNext()){
        int id = imageCursor.getInt(imageCursor.getColumnIndex(MediaStore.Images.Media._ID));
        String path = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
        Long takenTimeStamp = imageCursor.getLong(imageCursor.getColumnIndex(MediaStore.Images.Media.DATE_TAKEN));
        Long size = imageCursor.getLong(imageCursor.getColumnIndex(MediaStore.Images.Media.SIZE));
        if(path.contentEquals(MyActivity.this.capturePath)){
            // Remove it
            ContentResolver cr = getContentResolver();
            cr.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MediaStore.Images.Media._ID + "=?", new String[]{ Long.toString(id) } );
            break;
        }
    }               
}
imageCursor.close();

저에게 이것은 훨씬 더 간단한 솔루션이었고이 문제가있는 HTC에서 테스트했습니다.

또 다른 참고 사항 , 나는 원래 * _ID *가 아닌 * DATE_TAKEN *을 매개 변수로 사용했지만 에뮬레이터에서 의도를 통해 캡처되는 일부 이미지의 밀리 초 * DATE_TAKEN * 시간에 1000을 곱한 버그가있는 것 같습니다. 훨씬 더 강력한 것처럼 보이는 * _ID *로 전환되었습니다.


갤러리에서 파일이 삭제됩니다.

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

    if (requestCode == CAMERA_PIC_REQUEST && resultCode == RESULT_OK) { 

        /* Copy the file to other directory or whatever you want */

        // mContext is the context of the activity
        mContext.getContentResolver().delete(data.getData(), null, null);
    }
 }

표준 동작이 아닌 EXTRA_OUTPUT에 대해. 이 의사 알고리즘은 모든 경우에 작동해야한다고 생각합니다.

1) EXTRA_OUTPUT을 사용하지 마십시오. 이미지 / 사진은 항상 갤러리 위치로 이동합니다.

2) 갤러리 위치에서 원하는 위치로 파일을 복사합니다.

3) 갤러리에서 파일을 제거합니다 (상단 코드 사용).

하지만 물론 너무 완벽 해 보입니다 ... 일부 기기 (예 : Android 2.3의 원래 Galaxy Tab)에서는 ACTION_IMAGE_CAPTURE와 함께 EXTRA_OUTPUT을 사용해야합니다. 그렇지 않으면 의도가 작동하지 않습니다.


제가 생각하는 모든 문제는 발생하지 않는 다른 응용 프로그램에서 특정 결과를 기대하고 있다는 사실에서 비롯된 것입니다. (명확하게 말하면)-

  • 애플리케이션이 이미지를 캡처하지 않으므로 사진을 찍을 수있는 활동을 시작합니다.
  • picutre를 저장할 다른 응용 프로그램을 알려주십시오.
  • 지정한 위치에 저장된 이미지를 사용하십시오.
  • 그러나 문제는 다른 응용 프로그램도 이미지를 다른 위치에 저장했기 때문에 원하지 않습니다.

이제 이미지를 캡처하는 다른 애플리케이션 관점에서 살펴 보겠습니다. 두 가지 시나리오를 고려해 보겠습니다 (가능한)-

  • 첫째, 이미지를 저장할 파일 이름 또는 위치 옵션으로 응용 프로그램이 시작됩니다.
  • 둘째, 파일 이름이나 이미지를 저장할 위치와 같은 추가 정보없이 응용 프로그램이 시작됩니다 (캡처 응용 프로그램이 메뉴에서 직접 실행되는 경우 발생할 수 있음).

이제 이상적으로는 파일 이름이나 위치와 같은 추가 정보가 있으면 해당 위치를 사용 했어야했습니다. 그렇지 않은 경우 자신의 위치를 ​​사용할 수 있습니다. 그러나 슬프게도 우리는 이상적인 세상에서 왔으며 카메라 애플리케이션을 시작할 때 어떤 일이 발생해야하는지에 대한 내용은 아무것도 없기 때문에 카메라 앱 개발자는 자신의 해석을 갖게됩니다.

장치마다 다른 카메라 애플리케이션이 기본값으로 설정되어 있기 때문에 (예, 일반적으로 기본 카메라가 교체 됨) 얻은 결과는 다를 수 있습니다.

따라서 일부 카메라의 경우 다른 한 위치에만 저장 될 수 있으며 카메라 폴더에도 저장 될 수 있습니다 (카메라 응용 프로그램이 캡처 된 이미지를 항상 카메라 폴더에 저장하고 다른 위치에 저장하는 것은 보너스 응용 프로그램)

카메라 응용 프로그램에 fileName을 전달하면 한 장의 사진을 찍은 후 응용 프로그램이 반환됩니까? 나는 그렇게 생각하지 않는다. 그렇다면 그러한 시나리오에서 무엇을해야합니까? 모두 매우 모호하거나 회색 영역입니다.

이제 카메라 폴더에 저장하지 않으려면 최근에 캡처 한 이미지의 파일 이름을 가져올 수 있는지 확인한 다음 응용 프로그램에서 삭제할 수 있습니다. 또는 카메라 응용 프로그램에 저장해야 할 위치를 알려주지 말고 파일 이름을 가져와 원하는 위치로 이동하십시오.

파일 이름을 얻지 못하면 다른 응용 프로그램 개발자의 자비입니다. (헤이! 그것도 그의 잘못이 아니라 그가 원하는 방식으로 디자인했습니다!)


나는 당신이 원하는 것을 할 수 없다고 생각합니다. 슬프지만 다른 답을 찾을 수 없습니다.

Google 카메라 구현으로 작업하면 제대로 작동합니다. EXTRA_OUTPUT이 지정된 갤러리에 사진을 저장하지 않습니다.

그러나 다른 장치에 직면하면 완전히 다른 일을 할 수 있습니다. 그 이유는 HTC, LG 및 기타 일부 제품에 맞춤형 카메라 구현이 있고 이에 대해 아무것도 할 수 없기 때문입니다. 그대로 두거나 필요한 방식으로 정확히 작동하는 카메라를 직접 작성할 수 있습니다.

실제로이 질문과 관련이 없지만 언젠가는 CROP 인 텐트가 일부 기기에서 작동하지 않는다는 것을 알게 될 것입니다 ( http://groups.google.com/group/android-developers/browse_frm/thread/2dd647523926192c/4b6d087073a39607 ? tvc = 1 & pli = 1 ). 다시 한번 필요하면 직접 작성해야합니다.


이것은 해결하기 쉬운 작업은 아니지만 까다로운 방법에 접근 할 수 있습니다. 아래 코드를 시도하십시오.

  1. 카메라 인 텐트를 호출하기 전에 현재 시간을 밀리 초 단위로 저장합니다.
  2. OnActivityResult는 찍은 날짜가 1 단계의 밀리 초보다 큰 이미지 URI를 쿼리합니다. 그리고 파일을 삭제하십시오. 그게 다야.
String[] projection = {MediaStore.Images.ImageColumns.SIZE,
                MediaStore.Images.ImageColumns.DISPLAY_NAME,
                MediaStore.Images.ImageColumns.DATA,
                BaseColumns._ID,MediaStore.Images.ImageColumns.DATE_ADDED};
        final String imageOrderBy = MediaStore.Images.Media._ID + " DESC";
        final String selection = MediaStore.Images.Media.DATE_TAKEN+" > "+mImageTakenTime;
        //// intialize the Uri and the Cursor, and the current expected size.
        Cursor c = null;
        Uri u = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        c = getActivity().managedQuery(u, projection, selection, null, imageOrderBy);
        if(null != c && c.moveToFirst()){
            ContentResolver cr = getActivity().getContentResolver();
            cr.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    BaseColumns._ID + "=" + c.getString(3), null);
        }

Look here - that's a piece of code which saves picture to EXTRA_OUTPUT folder without saving it to gallery. In this way in my application I used to grab picture directly from camera and then delete taken picture.


This is the code I use which takes a pic and saves it at the location specified

Uri outputFileUri;

public void takePhoto() {
    File directory = new File(Environment.getExternalStorageDirectory()
            + "/HI-Tech" + "/");

    if (!directory.exists()) {
        directory.mkdir();
    }

    int count = 0;
    if (directory != null) {
        File[] files = directory.listFiles();
        if (files != null) {
            count = files.length;
        }
    }
    count++;
    String imagePath = "IMAGE_" + count + ".jpg";
    File file = new File(directory, imagePath);
    outputFileUri = Uri.fromFile(file);

        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
    startActivityForResult(intent, JobActivity.TAKE_PIC);
}

I then handle the response.

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    try {
        if (resultCode == RESULT_OK) {
            if (requestCode == JobActivity.TAKE_PIC) {
                Bitmap bitmap = decodeFile(new File(outputFileUri.getPath()), 160, 120);
    } catch (Exception e) {
        Log.e("Error", "Unable to set thumbnail", e);
    }
}

I had to declare the outputFileUri as a global variable as I found no way of acquiring the saved path onActivityResult. By passing the outputFileUri you will notice that the image isn't saved in the Camera folde but at the location specified. I've tried this code on my Nexus1 and a cheap samsung thing.

Hope this helps


I also was struggling with this issue. By the way, this issue is marked as Obsolete in the Android bug tracker. For some reason Android team doesn't consider this as a bug anymore. Maybe because this is manufacturer-related.

It seems that all solutions (from this thread and other blog posts etc.) form the following algorithm:

  1. Save a unique identifier of the last taken photo;
  2. Launch camera activity using Intent with EXTRA_OUTPUT ;
  3. Take a photo and check whether an id of the last taken photo in Gallery has changed to decide whether it should be deleted.

Something similar is proposed in the accepted answer.

But I found that such approach cannot be used in a production code. For example, let's image a simple situation:

You store some id of the last taken photo in Gallery and launch camera activity. When the user takes a photo on some devices the camera activity shows a dialog with Cancel and OK buttons (or something like that). And the logic behind them is as follows:

  • if the user presses Cancel he returns to the camera activity and can continue to take photos.
  • if he/she (the user) presses OK button the camera activity returns the result to your app.

The important notes here: it turns out that on some devices (I tested on LG and HTC) the image can be already saved while this dialog being presented.

Now imagine what if the user for some reason decides to tap Home button and starts another app (e.g. another camera app where the user can take different photos!). And then returns to your app where that dialog is still presented and presses OK. Obviously in that case your app your will delete the wrong file... and disappoint the user :(

So after a lot of researching I decided that the best approach to overcome this problem is to write your own camera engine or just use some third-party libs like this: material camera.


Your best bet is probably to handle the Camera class directly, and then store the jpeg or raw returned in the callback where you want.

Alternatively, you could try and delete the taken image by _id from the content provider for media after it's been added. Just find it by query and delete it via the ContentResolver.delete, not sure about the implementation though.


After struggeling with this for some time, I bit the bullet and wrote my own camera caputere activity. I am convinced this is much more portable and safer than the MediaStore.ACTION_IMAGE_CAPTURE solutions. The image will be stored where you store it and nowhere else and you are not in danger to delete some unrelated file by accident. Also, it is possible to adapt the actual camera function exactly to the requirements.

For portability reasons, I used the Camera class, not camera2.

It is worth to note that the camera parameters should all be set, especially picture size, focus mode and flash mode, they all may be in an unexpected state when starting the camera.

Posting this as an answer, not as a comment, because in my opinion it is the correct answer resulting in minimal effort.


protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
    if (requestCode == CAMERA_REQUEST && resultCode == RESULT_OK) {

    Bitmap photo = (Bitmap) data.getExtras().get("data");
    Uri tempUri = Utils.getUri(getActivity(), photo);
    File finalFile = new File(getRealPathFromURI(tempUri));
    finalFile.delete();
    }  
}


public String getRealPathFromURI (Uri contentUri) {
    String path = null;
    String[] proj = { MediaStore.MediaColumns.DATA };
    Cursor cursor = getActivity().getContentResolver().query(contentUri, proj, null, null, null);
    if (cursor.moveToFirst()) {
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
        path = cursor.getString(column_index);
    }
    cursor.close();
    return path;
}

참고URL : https://stackoverflow.com/questions/6390163/deleting-a-gallery-image-after-camera-intent-photo-taken

반응형