Home > Software engineering >  Save image using MediaStore, saved with wrong name and extension
Save image using MediaStore, saved with wrong name and extension

Time:11-27

I'm trying to use MediaStore API to save an image but it always save the file with this name 1637955326427.jpg and the size of the file is 0 B. this is the code that i use:

 OutputStream fos;
            ContentResolver resolver = getBaseContext().getContentResolver();
            ContentValues contentValues = new ContentValues();
            contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, "fileName.jpg");
            contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
            Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
            try {
                fos = resolver.openOutputStream(Objects.requireNonNull(imageUri));
                Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(),list.get(0).getDocfile().getUri());
                if(bitmap!=null){
                    bitmap.compress(Bitmap.CompressFormat.JPEG,100,fos);

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

list.get(0).getDocFile() return a DocumentFile also i tested this on API 28 Thanks in advance

NOTICE this image already exist on the External Storage, just need to copy it.

EDIT: I delete this code fos = resolver.openOutputStream(imageUri); was duplucate. I do realy apologize. the file work fine but steal wrong name.

CodePudding user response:

First lets take a look at getting write permissions for an existing image. Please note that the photopath does not necessarily exist yet but should point to the location you want your file to be saved.

if (!requestPhotoWritePermission(this, getImageUriFromFS(this, new File(photoPath)))) {
        return;
    } else {
        takePicture();
    }

This will form an overwrite request with the default camera

public static Uri getImageUriFromFS(Context c, File file) {
    long id = getFilePathToImageID(file, c);
    Uri fromUri = ContentUris.withAppendedId( MediaStore.Images.Media.EXTERNAL_CONTENT_URI,id);
    return fromUri;
}



public static long getFilePathToImageID(File imagePath, Context context)
{
    Uri mainUri;
    Cursor cursor1 = context.getContentResolver().query(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            new String[]{MediaStore.Images.Media._ID},
            MediaStore.Images.Media.DATA   "=? ",
            new String[]{imagePath.getAbsolutePath()}, null);
    long id = 0;
    if (cursor1 != null && cursor1.moveToFirst()) {

        id = cursor1.getLong(cursor1.getColumnIndex(MediaStore.MediaColumns._ID));
        cursor1.close();
    }
    return id;
}

public static boolean requestPhotoWritePermission(Activity activity, Uri fromUri) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {

        boolean hasPermission = true;
        if (activity.checkUriPermission(fromUri, Binder.getCallingPid(), Binder.getCallingUid(),
                Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION) != PackageManager.PERMISSION_GRANTED) {
            hasPermission = false;
        }

        List<Uri> uriList = new ArrayList<>();
        uriList.add(fromUri);

        if (!hasPermission) {
            PendingIntent pi = MediaStore.createWriteRequest(activity.getContentResolver(), uriList);
            try {
                activity.startIntentSenderForResult(pi.getIntentSender(), REQUEST_OVERWRITE_PERMISSION_CODE, null, 0, 0, 0);
            } catch (IntentSender.SendIntentException e) {
                e.printStackTrace();
            }
            return false;
        }
        return true;
    }
    return true;
}

This will persist the permission to overwrite or create a new picture via the camera intent

Then in your activity:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 53) {
        if (resultCode == RESULT_OK) {
            //you'll want to take your picture here and possibly store the uri to your photo for later retrieval
            takePicture();
        }
 }

This will take a picture if the permission request is accepted

To Take a picture using the default intent with a provider:

  1. Declare your provider in the manifest

     <provider
         android:name="androidx.core.content.FileProvider"
         android:authorities="${applicationId}.provider"
         android:enabled="true"
         android:exported="false"
         android:grantUriPermissions="true">
         <meta-data
             android:name="android.support.FILE_PROVIDER_PATHS"
             android:resource="@xml/file_paths">
         </meta-data>
     </provider>
    

1.5: xml File paths file:

<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path
    name="internal_images"
    path="files/Pictures" />
<external-files-path
    name="internal_images_alternate"
    path="Pictures" />
<external-path
    name="external"
    path="Documents" />
<external-files-path
    name="external_files"
    path="Documents" />
<cache-path
    name="cache"
    path="Documents" />
<external-cache-path
    name="external_cache"
    path="Documents" />
<files-path
    name="files"
    path="Documents" />
</paths>

The above will give you permission to save to the documents folder. Replace as required.

  1. Utilize the provider to take the picture

    public static File dispatchTakePictureIntent(Activity activity, String photoPath) {
    
         Intent takePictureIntent = getCameraIntentWithUpdatedPackages(activity);
         Uri photoURI = Uri.fromFile(new File(photoPath));
    
         Uri photoUri = FileProvider.getUriForFile(activity.getApplicationContext(), activity.getApplicationContext().getPackageName()   ".provider", new File(photoPath));
    
         activity.grantUriPermission(photoURI.getAuthority(), photoUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
         takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
         //disable strict mode policies
         StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
         StrictMode.setVmPolicy(builder.build());
         activity.startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
         return new File(photoPath);
    
    
     return null;
    

    }

EDIT: I forgot something

 public static Intent getCameraIntentWithUpdatedPackages(Context context) {
    List<ResolveInfo> resolveInfo = new ArrayList<>();

    final Intent capturePhoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    PackageManager pm = context.getPackageManager();
    resolveInfo = pm.queryIntentActivities(capturePhoto, 0);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
//             For Android 11 we need to add specific camera apps
        // due them are not added during ACTION_IMAGE_CAPTURE scanning...
//            resolveInfo.addAll(getCameraSpecificAppsInfo(context));
    }
    capturePhoto.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

    return capturePhoto;
}

EDIT: Update by the name (in onActivityResult after requesting an overwrite permission)

Uri fromUri = MediaUtils.getImageUriFromFS(this, new File(from));
                ContentResolver contentResolver = getContentResolver();
                ContentValues contentValues = new ContentValues();

                contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 1);
                contentResolver.update(fromUri, contentValues, null, null);
                contentValues.clear();
                contentValues.put(MediaStore.Files.FileColumns.DISPLAY_NAME, new File(to).getName());
                contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 0);
                contentResolver.update(fromUri, contentValues, null, null);

CodePudding user response:

I delete this code fos = resolver.openOutputStream(imageUri); was duplucate. the image work fine but steal wrong name.

  • Related