android - 将图像保存到图库中

发布于 2024-12-22 03:57:29 字数 1339 浏览 5 评论 0原文

我有一个带有图像库的应用程序,我希望用户可以将其保存到自己的图库中。 我创建了一个带有单个语音“保存”的选项菜单以允许这样做,但问题是......我如何将图像保存到图库中?

这是我的代码:

@Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle item selection
            switch (item.getItemId()) {
            case R.id.menuFinale:

                imgView.setDrawingCacheEnabled(true);
                Bitmap bitmap = imgView.getDrawingCache();
                File root = Environment.getExternalStorageDirectory();
                File file = new File(root.getAbsolutePath()+"/DCIM/Camera/img.jpg");
                try 
                {
                    file.createNewFile();
                    FileOutputStream ostream = new FileOutputStream(file);
                    bitmap.compress(CompressFormat.JPEG, 100, ostream);
                    ostream.close();
                } 
                catch (Exception e) 
                {
                    e.printStackTrace();
                }



                return true;
            default:
                return super.onOptionsItemSelected(item);
            }
        }

我不确定这部分代码:

File root = Environment.getExternalStorageDirectory();
                File file = new File(root.getAbsolutePath()+"/DCIM/Camera/img.jpg");

保存到图库中是否正确? 不幸的是代码不起作用:(

i have an app with a gallery of images and i want that the user can save it into his own gallery.
I've created an option menu with a single voice "save" to allow that but the problem is...how can i save the image into the gallery?

this is my code:

@Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle item selection
            switch (item.getItemId()) {
            case R.id.menuFinale:

                imgView.setDrawingCacheEnabled(true);
                Bitmap bitmap = imgView.getDrawingCache();
                File root = Environment.getExternalStorageDirectory();
                File file = new File(root.getAbsolutePath()+"/DCIM/Camera/img.jpg");
                try 
                {
                    file.createNewFile();
                    FileOutputStream ostream = new FileOutputStream(file);
                    bitmap.compress(CompressFormat.JPEG, 100, ostream);
                    ostream.close();
                } 
                catch (Exception e) 
                {
                    e.printStackTrace();
                }



                return true;
            default:
                return super.onOptionsItemSelected(item);
            }
        }

i'm not sure of this part of code:

File root = Environment.getExternalStorageDirectory();
                File file = new File(root.getAbsolutePath()+"/DCIM/Camera/img.jpg");

is it correct to save into the gallery?
unfortunately the code doesn't work :(

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

娇纵 2024-12-29 03:57:29
MediaStore.Images.Media.insertImage(getContentResolver(), yourBitmap, yourTitle , yourDescription);

前面的代码将在图库的末尾添加图像。如果您想修改日期,使其出现在开头或任何其他元数据中,请参阅下面的代码(Cortesy of SK,samkirton):

https://gist.github.com/samkirton/0242ba81d7ca00b475b9

/**
 * Android internals have been modified to store images in the media folder with 
 * the correct date meta data
 * @author samuelkirton
 */
public class CapturePhotoUtils {

    /**
     * A copy of the Android internals  insertImage method, this method populates the 
     * meta data with DATE_ADDED and DATE_TAKEN. This fixes a common problem where media 
     * that is inserted manually gets saved at the end of the gallery (because date is not populated).
     * @see android.provider.MediaStore.Images.Media#insertImage(ContentResolver, Bitmap, String, String)
     */
    public static final String insertImage(ContentResolver cr, 
            Bitmap source, 
            String title, 
            String description) {

        ContentValues values = new ContentValues();
        values.put(Images.Media.TITLE, title);
        values.put(Images.Media.DISPLAY_NAME, title);
        values.put(Images.Media.DESCRIPTION, description);
        values.put(Images.Media.MIME_TYPE, "image/jpeg");
        // Add the date meta data to ensure the image is added at the front of the gallery
        values.put(Images.Media.DATE_ADDED, System.currentTimeMillis());
        values.put(Images.Media.DATE_TAKEN, System.currentTimeMillis());

        Uri url = null;
        String stringUrl = null;    /* value to be returned */

        try {
            url = cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

            if (source != null) {
                OutputStream imageOut = cr.openOutputStream(url);
                try {
                    source.compress(Bitmap.CompressFormat.JPEG, 50, imageOut);
                } finally {
                    imageOut.close();
                }

                long id = ContentUris.parseId(url);
                // Wait until MINI_KIND thumbnail is generated.
                Bitmap miniThumb = Images.Thumbnails.getThumbnail(cr, id, Images.Thumbnails.MINI_KIND, null);
                // This is for backward compatibility.
                storeThumbnail(cr, miniThumb, id, 50F, 50F,Images.Thumbnails.MICRO_KIND);
            } else {
                cr.delete(url, null, null);
                url = null;
            }
        } catch (Exception e) {
            if (url != null) {
                cr.delete(url, null, null);
                url = null;
            }
        }

        if (url != null) {
            stringUrl = url.toString();
        }

        return stringUrl;
    }

    /**
     * A copy of the Android internals StoreThumbnail method, it used with the insertImage to
     * populate the android.provider.MediaStore.Images.Media#insertImage with all the correct
     * meta data. The StoreThumbnail method is private so it must be duplicated here.
     * @see android.provider.MediaStore.Images.Media (StoreThumbnail private method)
     */
    private static final Bitmap storeThumbnail(
            ContentResolver cr,
            Bitmap source,
            long id,
            float width, 
            float height,
            int kind) {

        // create the matrix to scale it
        Matrix matrix = new Matrix();

        float scaleX = width / source.getWidth();
        float scaleY = height / source.getHeight();

        matrix.setScale(scaleX, scaleY);

        Bitmap thumb = Bitmap.createBitmap(source, 0, 0,
            source.getWidth(),
            source.getHeight(), matrix,
            true
        );

        ContentValues values = new ContentValues(4);
        values.put(Images.Thumbnails.KIND,kind);
        values.put(Images.Thumbnails.IMAGE_ID,(int)id);
        values.put(Images.Thumbnails.HEIGHT,thumb.getHeight());
        values.put(Images.Thumbnails.WIDTH,thumb.getWidth());

        Uri url = cr.insert(Images.Thumbnails.EXTERNAL_CONTENT_URI, values);

        try {
            OutputStream thumbOut = cr.openOutputStream(url);
            thumb.compress(Bitmap.CompressFormat.JPEG, 100, thumbOut);
            thumbOut.close();
            return thumb;
        } catch (FileNotFoundException ex) {
            return null;
        } catch (IOException ex) {
            return null;
        }
    }
}
MediaStore.Images.Media.insertImage(getContentResolver(), yourBitmap, yourTitle , yourDescription);

The former code will add the image at the end of the gallery. If you want to modify the date so it appears at the beginning or any other metadata, see the code below (Cortesy of S-K, samkirton):

https://gist.github.com/samkirton/0242ba81d7ca00b475b9

/**
 * Android internals have been modified to store images in the media folder with 
 * the correct date meta data
 * @author samuelkirton
 */
public class CapturePhotoUtils {

    /**
     * A copy of the Android internals  insertImage method, this method populates the 
     * meta data with DATE_ADDED and DATE_TAKEN. This fixes a common problem where media 
     * that is inserted manually gets saved at the end of the gallery (because date is not populated).
     * @see android.provider.MediaStore.Images.Media#insertImage(ContentResolver, Bitmap, String, String)
     */
    public static final String insertImage(ContentResolver cr, 
            Bitmap source, 
            String title, 
            String description) {

        ContentValues values = new ContentValues();
        values.put(Images.Media.TITLE, title);
        values.put(Images.Media.DISPLAY_NAME, title);
        values.put(Images.Media.DESCRIPTION, description);
        values.put(Images.Media.MIME_TYPE, "image/jpeg");
        // Add the date meta data to ensure the image is added at the front of the gallery
        values.put(Images.Media.DATE_ADDED, System.currentTimeMillis());
        values.put(Images.Media.DATE_TAKEN, System.currentTimeMillis());

        Uri url = null;
        String stringUrl = null;    /* value to be returned */

        try {
            url = cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

            if (source != null) {
                OutputStream imageOut = cr.openOutputStream(url);
                try {
                    source.compress(Bitmap.CompressFormat.JPEG, 50, imageOut);
                } finally {
                    imageOut.close();
                }

                long id = ContentUris.parseId(url);
                // Wait until MINI_KIND thumbnail is generated.
                Bitmap miniThumb = Images.Thumbnails.getThumbnail(cr, id, Images.Thumbnails.MINI_KIND, null);
                // This is for backward compatibility.
                storeThumbnail(cr, miniThumb, id, 50F, 50F,Images.Thumbnails.MICRO_KIND);
            } else {
                cr.delete(url, null, null);
                url = null;
            }
        } catch (Exception e) {
            if (url != null) {
                cr.delete(url, null, null);
                url = null;
            }
        }

        if (url != null) {
            stringUrl = url.toString();
        }

        return stringUrl;
    }

    /**
     * A copy of the Android internals StoreThumbnail method, it used with the insertImage to
     * populate the android.provider.MediaStore.Images.Media#insertImage with all the correct
     * meta data. The StoreThumbnail method is private so it must be duplicated here.
     * @see android.provider.MediaStore.Images.Media (StoreThumbnail private method)
     */
    private static final Bitmap storeThumbnail(
            ContentResolver cr,
            Bitmap source,
            long id,
            float width, 
            float height,
            int kind) {

        // create the matrix to scale it
        Matrix matrix = new Matrix();

        float scaleX = width / source.getWidth();
        float scaleY = height / source.getHeight();

        matrix.setScale(scaleX, scaleY);

        Bitmap thumb = Bitmap.createBitmap(source, 0, 0,
            source.getWidth(),
            source.getHeight(), matrix,
            true
        );

        ContentValues values = new ContentValues(4);
        values.put(Images.Thumbnails.KIND,kind);
        values.put(Images.Thumbnails.IMAGE_ID,(int)id);
        values.put(Images.Thumbnails.HEIGHT,thumb.getHeight());
        values.put(Images.Thumbnails.WIDTH,thumb.getWidth());

        Uri url = cr.insert(Images.Thumbnails.EXTERNAL_CONTENT_URI, values);

        try {
            OutputStream thumbOut = cr.openOutputStream(url);
            thumb.compress(Bitmap.CompressFormat.JPEG, 100, thumbOut);
            thumbOut.close();
            return thumb;
        } catch (FileNotFoundException ex) {
            return null;
        } catch (IOException ex) {
            return null;
        }
    }
}
泪痕残 2024-12-29 03:57:29

实际上,您可以将图片保存在任何地方。如果您想保存在公共空间中,以便任何其他应用程序都可以访问,请使用以下代码:

storageDir = new File(
    Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES
    ), 
    getAlbumName()
);

图片不会进入相册。为此,您需要调用扫描:

private void galleryAddPic() {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File f = new File(mCurrentPhotoPath);
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    this.sendBroadcast(mediaScanIntent);
}

您可以在 https: //developer.android.com/training/camera/photobasics.html#TaskGallery

Actually, you can save you picture at any place. If you want to save in a public space, so any other application can access, use this code:

storageDir = new File(
    Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES
    ), 
    getAlbumName()
);

The picture doesn't go to the album. To do this, you need to call a scan:

private void galleryAddPic() {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File f = new File(mCurrentPhotoPath);
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    this.sendBroadcast(mediaScanIntent);
}

You can found more info at https://developer.android.com/training/camera/photobasics.html#TaskGallery

一笔一画续写前缘 2024-12-29 03:57:29

我尝试了很多方法来让它在 Marshmallow 和 Lollipop 上运行。
最后,我最终将保存的图片移动到 DCIM 文件夹(新的 Google 照片应用程序仅扫描位于该文件夹内的图像)

public static File createImageFile() throws IOException {
    // Create an image file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
         .format(System.currentTimeInMillis());
    File storageDir = new File(Environment
         .getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + "/Camera/");
    if (!storageDir.exists())
        storageDir.mkdirs();
    File image = File.createTempFile(
            timeStamp,                   /* prefix */
            ".jpeg",                     /* suffix */
            storageDir                   /* directory */
    );
    return image;
}

然后扫描文件的标准代码,您可以在 Google 开发者网站

public static void addPicToGallery(Context context, String photoPath) {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File f = new File(photoPath);
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    context.sendBroadcast(mediaScanIntent);
}

请记住,这个文件夹不可能存在于世界上的所有设备中,并且从 Marshmallow (API 23) 开始,您需要向用户请求 WRITE_EXTERNAL_STORAGE 权限。

I've tried a lot of things to let this work on Marshmallow and Lollipop.
Finally i ended up moving the saved picture to the DCIM folder (new Google Photo app scan images only if they are inside this folder apparently)

public static File createImageFile() throws IOException {
    // Create an image file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
         .format(System.currentTimeInMillis());
    File storageDir = new File(Environment
         .getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + "/Camera/");
    if (!storageDir.exists())
        storageDir.mkdirs();
    File image = File.createTempFile(
            timeStamp,                   /* prefix */
            ".jpeg",                     /* suffix */
            storageDir                   /* directory */
    );
    return image;
}

And then the standard code for scanning files which you can find in the Google Developers site too.

public static void addPicToGallery(Context context, String photoPath) {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File f = new File(photoPath);
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    context.sendBroadcast(mediaScanIntent);
}

Please remember that this folder could not be present in every device in the world and that starting from Marshmallow (API 23), you need to request the permission to WRITE_EXTERNAL_STORAGE to the user.

楠木可依 2024-12-29 03:57:29

根据本课程,正确的方法是:

Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES
    )

这会给你图库目录的根路径。

According to this course, the correct way to do this is:

Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES
    )

This will give you the root path for the gallery directory.

屌丝范 2024-12-29 03:57:29
private void galleryAddPic() {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File f = new File(mCurrentPhotoPath);
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    this.sendBroadcast(mediaScanIntent);
}
private void galleryAddPic() {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File f = new File(mCurrentPhotoPath);
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    this.sendBroadcast(mediaScanIntent);
}
傲鸠 2024-12-29 03:57:29

您可以在相机文件夹内创建一个目录并保存图像。之后,您可以简单地执行扫描。它将立即在图库中显示您的图像。

String root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString()+ "/Camera/Your_Directory_Name";
File myDir = new File(root);
myDir.mkdirs();
String fname = "Image-" + image_name + ".png";
File file = new File(myDir, fname);
System.out.println(file.getAbsolutePath());
if (file.exists()) file.delete();
    Log.i("LOAD", root + fname);
    try {
        FileOutputStream out = new FileOutputStream(file);
        finalBitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
        out.flush();
        out.close();
    } catch (Exception e) {
       e.printStackTrace();
    }

MediaScannerConnection.scanFile(context, new String[]{file.getPath()}, new String[]{"image/jpeg"}, null);

You can create a directory inside the camera folder and save the image. After that, you can simply perform your scan. It will instantly show your image in the gallery.

String root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString()+ "/Camera/Your_Directory_Name";
File myDir = new File(root);
myDir.mkdirs();
String fname = "Image-" + image_name + ".png";
File file = new File(myDir, fname);
System.out.println(file.getAbsolutePath());
if (file.exists()) file.delete();
    Log.i("LOAD", root + fname);
    try {
        FileOutputStream out = new FileOutputStream(file);
        finalBitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
        out.flush();
        out.close();
    } catch (Exception e) {
       e.printStackTrace();
    }

MediaScannerConnection.scanFile(context, new String[]{file.getPath()}, new String[]{"image/jpeg"}, null);
绮烟 2024-12-29 03:57:29

注意:对于Build.VERSION.SDK_INT 29、图像必须首先保存在本地磁盘上,这会随着用户保存更多图像而增加应用程序的大小。用户可以稍后在“文件”应用程序中删除图像,但本地图像必须与云中的 Google Photos 或 Amazon Photos 同步。

将图像保存到云端的方法是让用户在导出后、删除应用程序 APK 之前打开其 Google Photos 或 Amazon Photos 应用程序。如果<的用户29 在打开 Google Photos 或 Amazon Photos 之前删除您的 APK,照片将会丢失。

这是 Q(级别 29)之前的 Android 版本的错误。 29级及以上直接保存到照片库。

Android Manifest XML

<!-- Adding Read External Storage Permission -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

保存功能

// - Save Image -

@Throws(FileNotFoundException::class)
private fun saveImage(
    bitmap: Bitmap,
    context: Context,
    folderName: String
) {

    if (Build.VERSION.SDK_INT >= 29) {

        val values = ContentValues()
        values.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/$folderName")
        values.put(MediaStore.Images.Media.IS_PENDING, true)

        // RELATIVE_PATH and IS_PENDING are introduced in API 29.

        val uri: Uri? = context.contentResolver
            .insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)

        if (uri != null) {
            saveImageToStream(bitmap, context.contentResolver.openOutputStream(uri))
            values.put(MediaStore.Images.Media.IS_PENDING, false)
            context.contentResolver.update(uri, values, null, null)
        }

    } else {

        var dir = File(
            applicationContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES),
            ""
        )

        // getExternalStorageDirectory is deprecated in API 29

        if (!dir.exists()) {

            dir.mkdirs()

        }

        val date = Date()

        val fullFileName = "myFileName.jpeg"

        val fileName = fullFileName?.substring(0, fullFileName.lastIndexOf("."))
        val extension = fullFileName?.substring(fullFileName.lastIndexOf("."))

        var imageFile = File(
            dir.absolutePath
                .toString() + File.separator
                    + fileName + "_" + Timestamp(date.time).toString()
                    + ".jpg"
        )

        println("imageFile: $imageFile")

        saveImageToStream(bitmap, FileOutputStream(imageFile))

        if (imageFile.getAbsolutePath() != null) {

            val values = ContentValues()

            values.put(MediaStore.Images.Media.DATA, imageFile.absolutePath)

            // .DATA is deprecated in API 29

            context.contentResolver
                .insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)

        }

    }

}

private fun contentValues(): ContentValues? {

    val values = ContentValues()

    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
    values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis() / 1000)
    values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())

    return values

}

private fun saveImageToStream(bitmap: Bitmap, outputStream: OutputStream?) {

    println("saveImageToStream")

    if (outputStream != null) {

        try {

            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
            outputStream.close()

            // success dialog

            runOnUiThread {

                val successDialog = SuccessDialog.getInstance(null)
                successDialog.show(supportFragmentManager, SuccessDialog.TAG)

            }

        } catch (e: Exception) {

            e.printStackTrace()

            // warning dialog

            runOnUiThread {

                val warningDialog = WarningDialog.getInstance(null)
                warningDialog.show(supportFragmentManager, WarningDialog.TAG)

            }

        }

    }

}

Note: For Build.VERSION.SDK_INT < 29, the image has to be saved locally on disk first, which will increase the app size as the user saves more images. The user can delete the image later, in the Files app, but the local image has to sync with Google Photos or Amazon Photos in the cloud.

Saving the image to the cloud is accomplished by having the user open their Google Photos or Amazon Photos app after exporting and before deleting your app APK. If the user of < 29 deletes your APK before opening Google Photos or Amazon Photos, the photo will be lost.

This is a bug with Android Builds before Q (Level 29). Level 29 and later save directly to the Photo Library.

Android Manifest XML

<!-- Adding Read External Storage Permission -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Save Function

// - Save Image -

@Throws(FileNotFoundException::class)
private fun saveImage(
    bitmap: Bitmap,
    context: Context,
    folderName: String
) {

    if (Build.VERSION.SDK_INT >= 29) {

        val values = ContentValues()
        values.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/$folderName")
        values.put(MediaStore.Images.Media.IS_PENDING, true)

        // RELATIVE_PATH and IS_PENDING are introduced in API 29.

        val uri: Uri? = context.contentResolver
            .insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)

        if (uri != null) {
            saveImageToStream(bitmap, context.contentResolver.openOutputStream(uri))
            values.put(MediaStore.Images.Media.IS_PENDING, false)
            context.contentResolver.update(uri, values, null, null)
        }

    } else {

        var dir = File(
            applicationContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES),
            ""
        )

        // getExternalStorageDirectory is deprecated in API 29

        if (!dir.exists()) {

            dir.mkdirs()

        }

        val date = Date()

        val fullFileName = "myFileName.jpeg"

        val fileName = fullFileName?.substring(0, fullFileName.lastIndexOf("."))
        val extension = fullFileName?.substring(fullFileName.lastIndexOf("."))

        var imageFile = File(
            dir.absolutePath
                .toString() + File.separator
                    + fileName + "_" + Timestamp(date.time).toString()
                    + ".jpg"
        )

        println("imageFile: $imageFile")

        saveImageToStream(bitmap, FileOutputStream(imageFile))

        if (imageFile.getAbsolutePath() != null) {

            val values = ContentValues()

            values.put(MediaStore.Images.Media.DATA, imageFile.absolutePath)

            // .DATA is deprecated in API 29

            context.contentResolver
                .insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)

        }

    }

}

private fun contentValues(): ContentValues? {

    val values = ContentValues()

    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
    values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis() / 1000)
    values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())

    return values

}

private fun saveImageToStream(bitmap: Bitmap, outputStream: OutputStream?) {

    println("saveImageToStream")

    if (outputStream != null) {

        try {

            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
            outputStream.close()

            // success dialog

            runOnUiThread {

                val successDialog = SuccessDialog.getInstance(null)
                successDialog.show(supportFragmentManager, SuccessDialog.TAG)

            }

        } catch (e: Exception) {

            e.printStackTrace()

            // warning dialog

            runOnUiThread {

                val warningDialog = WarningDialog.getInstance(null)
                warningDialog.show(supportFragmentManager, WarningDialog.TAG)

            }

        }

    }

}
删除→记忆 2024-12-29 03:57:29

这对我有用:

 private fun saveBitmapAsImageToDevice(bitmap: Bitmap?) {
    // Add a specific media item.
    val resolver = this.contentResolver

    val imageStorageAddress = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
    } else {
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    }

    val imageDetails = ContentValues().apply {
        put(MediaStore.Images.Media.DISPLAY_NAME, "my_app_${System.currentTimeMillis()}.jpg")
        put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
        put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis())
    }

    try {
        // Save the image.
        val contentUri: Uri? = resolver.insert(imageStorageAddress, imageDetails)
        contentUri?.let { uri ->
            // Don't leave an orphan entry in the MediaStore
            if (bitmap == null) resolver.delete(contentUri, null, null)
            val outputStream: OutputStream? = resolver.openOutputStream(uri)
            outputStream?.let { outStream ->
                val isBitmapCompressed =
                    bitmap?.compress(Bitmap.CompressFormat.JPEG, 95, outStream)
                if (isBitmapCompressed == true) {
                    outStream.flush()
                    outStream.close()
                }
            } ?: throw IOException("Failed to get output stream.")
        } ?: throw IOException("Failed to create new MediaStore record.")
    } catch (e: IOException) {
        throw e
    }
}

Here's what worked for me:

 private fun saveBitmapAsImageToDevice(bitmap: Bitmap?) {
    // Add a specific media item.
    val resolver = this.contentResolver

    val imageStorageAddress = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
    } else {
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    }

    val imageDetails = ContentValues().apply {
        put(MediaStore.Images.Media.DISPLAY_NAME, "my_app_${System.currentTimeMillis()}.jpg")
        put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
        put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis())
    }

    try {
        // Save the image.
        val contentUri: Uri? = resolver.insert(imageStorageAddress, imageDetails)
        contentUri?.let { uri ->
            // Don't leave an orphan entry in the MediaStore
            if (bitmap == null) resolver.delete(contentUri, null, null)
            val outputStream: OutputStream? = resolver.openOutputStream(uri)
            outputStream?.let { outStream ->
                val isBitmapCompressed =
                    bitmap?.compress(Bitmap.CompressFormat.JPEG, 95, outStream)
                if (isBitmapCompressed == true) {
                    outStream.flush()
                    outStream.close()
                }
            } ?: throw IOException("Failed to get output stream.")
        } ?: throw IOException("Failed to create new MediaStore record.")
    } catch (e: IOException) {
        throw e
    }
}
风和你 2024-12-29 03:57:29

我带着同样的疑问来到这里,但是对于 Xamarin for Android,我在保存文件后使用了 Sigrist 答案来执行此方法:

private void UpdateGallery()
{
    Intent mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
    Java.IO.File file = new Java.IO.File(_path);
    Android.Net.Uri contentUri = Android.Net.Uri.FromFile(file);
    mediaScanIntent.SetData(contentUri);
    Application.Context.SendBroadcast(mediaScanIntent);
} 

它解决了我的问题,Thx Sigrist。我把它放在这里是因为我没有找到关于 Xamarin 的答案,我希望它可以帮助其他人。

I come here with the same doubt but for Xamarin for Android, I have used the Sigrist answer to do this method after save my file:

private void UpdateGallery()
{
    Intent mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
    Java.IO.File file = new Java.IO.File(_path);
    Android.Net.Uri contentUri = Android.Net.Uri.FromFile(file);
    mediaScanIntent.SetData(contentUri);
    Application.Context.SendBroadcast(mediaScanIntent);
} 

and it solved my problem, Thx Sigrist. I put it here becouse i did not found an answare about this for Xamarin and i hope it can help other people.

原来是傀儡 2024-12-29 03:57:29

就我而言,上述解决方案不起作用,我必须执行以下操作:

sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(f)));

In my case the solutions above did not work I had to do the following:

sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(f)));
停滞 2024-12-29 03:57:29
 String filePath="/storage/emulated/0/DCIM"+app_name;
    File dir=new File(filePath);
    if(!dir.exists()){
        dir.mkdir();
    }

这段代码位于onCreate方法中。这段代码用于创建app_name的目录。
现在,可以使用 Android 中的默认文件管理器应用程序访问此目录。
在需要设置目标文件夹的地方使用此字符串 filePath。
我确信这个方法也适用于 Android 7,因为我对其进行了测试。因此,它也适用于其他版本的 Android。

 String filePath="/storage/emulated/0/DCIM"+app_name;
    File dir=new File(filePath);
    if(!dir.exists()){
        dir.mkdir();
    }

This code is in onCreate method.This code is for creating a directory of app_name.
Now,this directory can be accessed using default file manager app in android.
Use this string filePath wherever required to set your destination folder.
I am sure this method works on Android 7 too because I tested on it.Hence,it can work on other versions of android too.

停滞 2024-12-29 03:57:29

用于将图像保存到内部存储的 Kotlin 代码

您可以使用 Kotlin 优化 Android 中用于将图像保存到内部存储的代码,并改进代码如下:

private fun saveToInternalStorage(imageUri: Uri) {

        val contentResolver = this.contentResolver

        val contentValues = ContentValues().apply {
            put(MediaStore.Images.Media.TITLE, imageUri.toString())
            put(MediaStore.Images.Media.DISPLAY_NAME, imageUri.toString())
            put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
        }


        // check android version and provide require uri to contentResolver

        val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            contentResolver.insert(MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY),contentValues)
        } else {
            contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues)
        }

        uri?.let {
            val fileDescriptor = contentResolver.openFileDescriptor(it, "w")?.fileDescriptor
            val inputStream: InputStream? = this.getUriInputStream(imageUri)

            inputStream?.use { input ->
                fileDescriptor?.let { descriptor ->
                    val outputStream = FileOutputStream(descriptor)
                    val buffer = ByteArray(4096)
                    var bytesRead: Int

                    while (input.read(buffer).also { bytesRead = it } != -1) {
                        outputStream.write(buffer, 0, bytesRead)
                    }

                    outputStream.flush()
                    outputStream.close()
                }
            }
        }

    }

// An inline function to convert an imageUri to an InputStream
private fun Context.getUriInputStream(imageUri: Uri): InputStream? {
        val contentResolver: ContentResolver = this.contentResolver
        return try {
            contentResolver.openInputStream(imageUri)
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }

Kotlin Code for Saving an Image to Internal Storage

You can optimize the code for saving an image to internal storage in Android using Kotlin with the following improved code:

private fun saveToInternalStorage(imageUri: Uri) {

        val contentResolver = this.contentResolver

        val contentValues = ContentValues().apply {
            put(MediaStore.Images.Media.TITLE, imageUri.toString())
            put(MediaStore.Images.Media.DISPLAY_NAME, imageUri.toString())
            put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
        }


        // check android version and provide require uri to contentResolver

        val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            contentResolver.insert(MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY),contentValues)
        } else {
            contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues)
        }

        uri?.let {
            val fileDescriptor = contentResolver.openFileDescriptor(it, "w")?.fileDescriptor
            val inputStream: InputStream? = this.getUriInputStream(imageUri)

            inputStream?.use { input ->
                fileDescriptor?.let { descriptor ->
                    val outputStream = FileOutputStream(descriptor)
                    val buffer = ByteArray(4096)
                    var bytesRead: Int

                    while (input.read(buffer).also { bytesRead = it } != -1) {
                        outputStream.write(buffer, 0, bytesRead)
                    }

                    outputStream.flush()
                    outputStream.close()
                }
            }
        }

    }

// An inline function to convert an imageUri to an InputStream
private fun Context.getUriInputStream(imageUri: Uri): InputStream? {
        val contentResolver: ContentResolver = this.contentResolver
        return try {
            contentResolver.openInputStream(imageUri)
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }
桃扇骨 2024-12-29 03:57:29

只是您需要在保存完成后扫描您的媒体。

 BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable();
            Bitmap bitmap = drawable.getBitmap();

            File filepath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
            File dir = new File(filepath.getAbsolutePath()+"/Pro Scanner/");
            if(!dir.exists()){
                dir.mkdir();
            }
            File file = new File(dir,System.currentTimeMillis()+"_Pro_Scanner.png");
            try {
                outputStream = new FileOutputStream(file);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                downloadQRCode.setVisibility(View.VISIBLE);
                loadingBar.setVisibility(View.INVISIBLE);
            }
            bitmap.compress(Bitmap.CompressFormat.PNG,100,outputStream);
            Toast.makeText(GenerateQRCodeActivity.this, "QR image saved successfully", Toast.LENGTH_SHORT).show();
            try {
                outputStream.flush();
                outputStream.close();
                loadingBar.setVisibility(View.INVISIBLE);
                downloadDone.setVisibility(View.VISIBLE);
                downloadDone.setAnimation(bottomAnimation);
            } catch (IOException e) {
                downloadQRCode.setVisibility(View.VISIBLE);
                loadingBar.setVisibility(View.INVISIBLE);
                e.printStackTrace();
            }

            MediaScannerConnection.scanFile(GenerateQRCodeActivity.this,new String[]{file.getPath()},new String[] {"image/jpeg"},null);

这些代码与每个人都相同。如果您在此之后尝试以下代码,它将起作用。您只需要以下一行代码:

MediaScannerConnection.scanFile(GenerateQRCodeActivity.this,new String[]{file.getPath()},new String[] {"image/jpeg"},null);

繁荣!!!您现在可以在图库中获取保存的图像。

Just you need to scan your Media After Saving finished.

 BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable();
            Bitmap bitmap = drawable.getBitmap();

            File filepath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
            File dir = new File(filepath.getAbsolutePath()+"/Pro Scanner/");
            if(!dir.exists()){
                dir.mkdir();
            }
            File file = new File(dir,System.currentTimeMillis()+"_Pro_Scanner.png");
            try {
                outputStream = new FileOutputStream(file);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                downloadQRCode.setVisibility(View.VISIBLE);
                loadingBar.setVisibility(View.INVISIBLE);
            }
            bitmap.compress(Bitmap.CompressFormat.PNG,100,outputStream);
            Toast.makeText(GenerateQRCodeActivity.this, "QR image saved successfully", Toast.LENGTH_SHORT).show();
            try {
                outputStream.flush();
                outputStream.close();
                loadingBar.setVisibility(View.INVISIBLE);
                downloadDone.setVisibility(View.VISIBLE);
                downloadDone.setAnimation(bottomAnimation);
            } catch (IOException e) {
                downloadQRCode.setVisibility(View.VISIBLE);
                loadingBar.setVisibility(View.INVISIBLE);
                e.printStackTrace();
            }

            MediaScannerConnection.scanFile(GenerateQRCodeActivity.this,new String[]{file.getPath()},new String[] {"image/jpeg"},null);

These code are same as everyone .If you try the bellow code after this it will work. You just need these one line of code:

MediaScannerConnection.scanFile(GenerateQRCodeActivity.this,new String[]{file.getPath()},new String[] {"image/jpeg"},null);

Boom!!! Yo can now get your saved image on your Gallery.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文