2

올바른 주체를 사용하여 DocumentFile 또는 Uri에서 파일을 가져와야합니다. 장치의 주 메모리가 선택된 경우 content://com.android.externalstorage.documents/tree/primary: 인 파일이 필요합니다. 이미지의 파일 또는 절대 경로를 얻으려면 file : /// storage/emulated/0 또는 storage/emulated/0이 필요하지만 EXIF ​​데이터를 쓰는 File을 작성하기위한 올바른 Uri를 얻는 방법을 찾을 수 없습니다. 이미지.DocumentFile 클래스로 저장된 이미지에 EXIF ​​데이터 쓰기

내 시나리오는 다음과 같습니다

  1. 사용자() content://com.android.externalstorage.documents onActivityResult를 함께 열린 우리당을 반환 이미지를 저장할 경로를 선택합니다. 나중에 사용하기 위해이 경로를 SharedPreferences에 treeUri.toString()으로 저장합니다.
  2. 사용자가 사진을 촬영하고 난 실패 할 경우 이미지가 제대로 이미지를 가리키는 파일을 받고, DocumentFile.fromTreeUri(MainActivity.this, Uri.parse(uriString));
  3. 이 저장됩니다 콘텐츠와 열린 우리당은 : // 열린 우리당은 file:///storage/emulated/해야 기존 image.Correct을 반환하지 않고 내가 할 수있는 File filePath = new File(URI.create(saveDir.getUri().toString()));

이 어떻게 열린 내가 SAF UI에서 가져온 열린 우리당을 사용하여 파일 또는 파일을 consturcting에 필요한 얻을 수 있습니다 사용하여 파일이 열린 우리당을 변환?

EDIT :ExifInterface Support Library은 InputStream 또는 FileDescriptor를 사용할 수있는 Android 7.1 이상에 도입되었습니다.

Uri uri; // the URI you've received from the other app 
InputStream in; 
try { 
    in = getContentResolver().openInputStream(uri); 
    ExifInterface exifInterface = new ExifInterface(in); 
    // Now you can extract any Exif tag you want 
    // Assuming the image is a JPEG or supported raw format 
} catch (IOException e) { 
    // Handle any errors 
} finally { 
    if (in != null) { 
    try { 
     in.close(); 
    } catch (IOException ignored) {} 
    } 
} 

참고 : ExifInterface 그런 HttpURLConnection의에서 반환 된 것과 같은 원격에는 InputStream, 작동하지 않습니다. content/: // 또는 file : // URI에서만 사용하는 것이 좋습니다.

위의 스 니펫은 분명히 데이터를 읽는 InputStream을 열 때 데이터를 읽는 중입니다. JPEG 파일에 EXIF ​​데이터를 쓸 수 있어야합니다. API는 경우 FileDescriptor를 사용하여 알려진 내용 열린 이전에 저장 한 이미지와 함께 Exif 데이터를 작성하기위한

답변

1

대답 24

private void writeEXIFWithFileDescriptor(Uri uri) { 

    if (Build.VERSION.SDK_INT < 24) { 
     showToast("writeEXIFWithInputStream() API LOWER 24", Toast.LENGTH_SHORT); 
     return; 
    } 

    ParcelFileDescriptor parcelFileDescriptor = null; 
    try { 

     parcelFileDescriptor = mContext.getContentResolver().openFileDescriptor(uri, "rw"); 
     FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor(); 
     showToast("writeEXIFWithFileDescriptor(): " + fileDescriptor.toString(), Toast.LENGTH_LONG); 
     ExifInterface exifInterface = new ExifInterface(fileDescriptor); 
     // TODO Create Exif Tags class to save Exif data 
     exifInterface.saveAttributes(); 

    } catch (FileNotFoundException e) { 
     showToast("File Not Found " + e.getMessage(), Toast.LENGTH_LONG); 

    } catch (IOException e) { 
     // Handle any errors 
     e.printStackTrace(); 
     showToast("IOEXception " + e.getMessage(), Toast.LENGTH_LONG); 
    } finally { 
     if (parcelFileDescriptor != null) { 
      try { 
       parcelFileDescriptor.close(); 
      } catch (IOException ignored) { 
       ignored.printStackTrace(); 
      } 
     } 
    } 
} 

API는 24보다 낮은 경우는 버퍼 파일을 사용하고 있음을 저장하는 것이 필요 Exif 데이터를 작성한 후 DocumentFile으로 파일을 실제 위치에 버퍼링합니다.

private boolean exportImageWithEXIF(Bitmap bitmap, DocumentFile documentFile) { 
     OutputStream outputStream = null; 
     File bufFile = new File(Environment.getExternalStorageDirectory(), "buffer.jpg"); 
     long freeSpace = Environment.getExternalStorageDirectory().getFreeSpace()/1048576; 
     double bitmapSize = bitmap.getAllocationByteCount()/1048576d; 

     showToast("exportImageWithEXIF() freeSpace " + freeSpace, Toast.LENGTH_LONG); 
     showToast("exportImageWithEXIF() bitmap size " + bitmapSize, Toast.LENGTH_LONG); 
     try { 
      outputStream = new FileOutputStream(bufFile); 
      // Compress image from bitmap with JPEG extension 
      if (mCameraSettings.getImageFormat().equals(Constants.IMAGE_FORMAT_JPEG)) { 
       isImageSaved = bitmap.compress(CompressFormat.JPEG, mCameraSettings.getImageQuality(), outputStream); 
       showToast("isImageSaved: " + isImageSaved, Toast.LENGTH_SHORT); 
      } 

      if (isImageSaved) { 
       writeEXIFWithFile(bufFile); 
      } 

     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } finally { 
      if (outputStream != null) { 
       try { 
        outputStream.close(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
     OutputStream os = null; 
     InputStream is = null; 
     try { 
      int len; 
      byte[] buf = new byte[4096]; 

      os = mContext.getContentResolver().openOutputStream(documentFile.getUri()); 
      is = new FileInputStream(bufFile); 

      while ((len = is.read(buf)) > 0) { 
       os.write(buf, 0, len); 
      } 

      os.close(); 
      is.close(); 

      if (bufFile != null) { 
       bufFile.delete(); 
       bufFile = null; 
      } 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

     return isImageSaved; 
    } 

두 가지 방법 모두 Exif 데이터를 장치의 메모리 또는 SD 카드에 저장된 이미지에 쓸 수 있습니다. Storage Access Framework의 유효한 Uri를 사용하여 SD 카드에 이미지를 저장할 수도 있습니다.

콘텐츠 Uri에서 메모리와 SD 카드의 절대 경로를 얻는 방법을 찾았지만이 질문과 관련이 없으며 절대 경로 대신 Uri를 사용하는 것이 좋습니다. 또한 눈에 띄지 않는 오류가 발생하지 않도록 할 수 없었습니다. 절대 경로로 이미지를 SD 카드에 저장하고 읽을 수만 있습니다.

관련 문제