android-将图像保存到图库


91

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

这是我的代码:

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

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


您解决了这个问题吗?你能和我分享


对于那些仍然在保存文件时遇到问题的人,可能是因为您的url包含非法字符,例如“?”,“:”和“-”。请删除这些字符,它应该可以工作。这是外部设备和android模拟器中的常见错误。查看更多有关在这里:stackoverflow.com/questions/11394616/...
ChallengeAccepted

接受的答案是有点过时2019年我在这里写了一个更新的答案:stackoverflow.com/questions/36624756/...
鲍蕾

Answers:


168
MediaStore.Images.Media.insertImage(getContentResolver(), yourBitmap, yourTitle , yourDescription);

前一个代码会将图像添加到图库的末尾。如果您想修改日期,使其显示在开头或任何其他元数据中,请参见下面的代码(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;
        }
    }
}

22
这样可以保存图像,但是保存到图库的尽头,尽管用相机拍摄照片时,图像会保存在顶部。如何将图像保存到图库顶部?
eric.itzhak 2012年

19
请注意,您还必须将<uses-permission android:name =“ android.permission.WRITE_EXTERNAL_STORAGE” />添加到manifext.xml中。
凯尔·克莱格

3
图像不会保存在图库的顶部,因为内部insertImage不会添加任何日期元数据。请参见以下GIST:gist.github.com/0242ba81d7ca00b475b9.git,它是insertImage方法的精确副本,但它添加了日期元数据日期以确保将图像添加到画廊的前面。
S-

1
@ S-K'我无法访问该URL。请更新它,我将更新我的答案,因此它具有两个选项。干杯
sfratini 2014年

6
这是上面提到的正确的GIST链接(需要删除.git结尾处的内容)
minipif 2014年

48

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

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找到更多信息


1
这是一个很好的简单解决方案,因为我们不需要更改整个实现,并且可以为应用程序创建自定义文件夹。
雨果格莱斯

2
当您仅扫描文件:stackoverflow.com/a/5814533/43051时,发送广播可能会浪费资源。
杰里米雷诺

2
您实际上在哪里传递位图?
Daniel Reyhanian

22

我已经尝试了很多方法来使它在棉花糖和棒棒糖上起作用。最后,我最终将保存的图片移动到DCIM文件夹中(只有当新的Google Photo应用显然位于该文件夹中时,它才扫描图像)

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 Developers网站上找到该代码。

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

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


1
感谢您提供有关Google相册的信息。
杰里米雷诺

1
这是一个很好解释的解决方案。没有其他人提到该文件必须位于DCIM文件夹中。谢谢!!!
Predrag Manojlovic

Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)为我做了把戏。谢谢!
saltandpepper

2
getExternalStoragePublicDirectory()现在已在API 29上弃用。需要使用MediaStore
riggaroo

@riggaroo是的,您是对的Rebecca,我将尽快更新答案
MatPag

13

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

Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES
    )

这将为您提供Gallery目录的根路径。


我尝试了此新代码,但崩溃了java.lang.NoSuchFieldError:android.os.Environment.DIRECTORY_PICTURES
Christian Giupponi 2011年

好的,谢谢,所以没有办法在android <2.2的情况下将图像放在图库中吗?
Christian Giupponi 2012年

完美-直接链接到Android Developer网站。这有效并且是一个简单的解决方案。
Phil

1
好的答案,但是最好从这里的其他答案中添加“ galleryAddPic”方法,因为您通常希望Gallery应用程序注意到新图片。
安德鲁·科斯特

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

6

您可以在camera文件夹内创建目录并保存图像。之后,您只需执行扫描即可。它将立即在图库中显示您的图像。

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

按照这个标准,这是最好的答案
Noor Hossain

1

我带着同样的疑问来到这里,但是对于Android的Xamarin,在保存文件后,我使用了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的Answare,我希望它可以帮助其他人。


1

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

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

它的,真的很好了解此选项,但不幸的是没有工作在与Android 6的一些设备,因此ContentProvider最好solytion
Siarhei

0
 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上使用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.