android – salvați imaginea în galerie (Programare, Android, Imageview, Galerie, Salvare Imagine)

Christian Giupponi a intrebat.

am o aplicație cu o galerie de imagini și vreau ca utilizatorul să o poată salva în propria galerie. am creat un meniu de opțiuni cu o singură voce „save” pentru a permite acest lucru, dar problema este…cum pot salva imaginea în galerie?

Acesta este codul meu:

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

Nu sunt sigur de această parte a codului:

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

este corect să salvez în galerie?din păcate, codul nu funcționează 🙁

Comentarii

  • ați rezolvat această problemă? vă rog să-mi spuneți și mie –  > Por user3233280.
  • și eu am aceeași problemă stackoverflow.com/questions/21951558/… –  > Por user3233280.
  • Pentru aceia dintre voi care încă mai au probleme cu salvarea fișierului, ar putea fi din cauza faptului că url-ul dvs. conține caractere ilegale, cum ar fi „?”, „:” și „-” Eliminați-le și ar trebui să funcționeze. Aceasta este o eroare comună în dispozitivele străine și în emulatorii android. Vedeți mai multe despre ea aici: stackoverflow.com/questions/11394616/… -…  > Por ChallengeAccepted.
  • Răspunsul acceptat este un pic depășit în 2019. Am scris un răspuns actualizat aici: stackoverflow.com/questions/36624756/… -…  > Por Bao Lei.
9 răspunsuri
sfratini
MediaStore.Images.Media.insertImage(getContentResolver(), yourBitmap, yourTitle , yourDescription);

Codul anterior va adăuga imaginea la sfârșitul galeriei. Dacă doriți să modificați data astfel încât să apară la început sau orice alte metadate, consultați codul de mai jos (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;
        }
    }
}

Comentarii

    25

  • Acest lucru salvează imaginea, dar la sfârșitul galeriei, deși atunci când faceți o fotografie cu aparatul foto se salvează în partea de sus. Cum pot salva imaginea în partea de sus a galeriei? –  > Por eric.itzhak.
  • 20

  • Rețineți că trebuie să adăugați și <uses-permission android_name=”android.permission.WRITE_EXTERNAL_STORAGE” /> la manifext.xml. –  > Por Kyle Clegg.
  • Imaginile nu sunt salvate în partea de sus a galeriei deoarece, la nivel intern, insertImage nu adaugă nicio meta-date. Vă rugăm să consultați acest GIST: gist.github.com/0242ba81d7ca00b475b9.git este o copie exactă a metodei insertImage, dar adaugă meta-date data pentru a se asigura că imaginea este adăugată în partea din față a galeriei. –  > Por S-K.
  • Iată linkul GIST corect menționat mai sus (a fost necesar să se elimine .git de la sfârșit) – –  > Por minipif.
  • MediaStore.Images.Media.insertImage(...) este deja depreciat. –  > Por Michael Abyzov.
Sigrist

De fapt, vă puteți salva imaginea în orice loc. Dacă doriți să o salvați într-un spațiu public, astfel încât orice altă aplicație să o poată accesa, utilizați acest cod:

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

Imaginea nu se duce în album. Pentru a face acest lucru, trebuie să apelați o scanare:

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

Puteți găsi mai multe informații la https://developer.android.com/training/camera/photobasics.html#TaskGallery

Comentarii

  • Aceasta este în felul acesta o soluție simplă și plăcută, deoarece nu trebuie să schimbăm întreaga implementare și pentru că putem crea un dosar personalizat pentru aplicații. –  > Por Hugo Gresse.
  • Trimiterea unei transmisiuni poate fi o risipă de resurse atunci când puteți scana doar un fișier: stackoverflow.com/a/5814533/43051. –  > Por Jérémy Reynaud.
  • Unde treceți de fapt harta de biți? –  > Por Daniel Reyhanian.
  • Environment.getExternalStoragePublicDirectory și Intent.ACTION_MEDIA_SCANNER_SCAN_FILE sunt depreciate acum… –  > Por Michael Abyzov.
MatPag

Am încercat o mulțime de lucruri pentru ca acest lucru să funcționeze pe Marshmallow și Lollipop. în cele din urmă am ajuns să mut imaginea salvată în folderul DCIM (noua aplicație Google Photo scanează imaginile numai dacă se află în interiorul acestui folder, aparent)

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

Și apoi codul standard pentru scanarea fișierelor pe care îl puteți găsi în site-ul Google Developers de asemenea.

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

Vă rugăm să rețineți că acest dosar nu ar putea fi prezent în fiecare dispozitiv din lume și că începând cu Marshmallow (API 23), trebuie să solicitați utilizatorului permisiunea de a WRITE_EXTERNAL_STORAGE.

Comentarii

  • Vă mulțumim pentru informațiile referitoare la Google Photos. –  > Por Jérémy Reynaud.
  • Aceasta este una și singura soluție care explică bine. Nimeni altcineva nu a menționat că fișierul trebuie să fie în folderul DCIM. Vă mulțumesc!!! –  > Por Predrag Manojlovic.
  • Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) a făcut truc pentru mine. Mulțumesc! –  > Por saltandpepper.
  • getExternalStoragePublicDirectory() este acum depreciat în API 29. Trebuie să folosiți MediaStore –  > Por riggaroo.
  • @riggaroo Da, ai dreptate Rebecca, voi actualiza răspunsul cât mai curând posibil –  > Por MatPag.
Cédric Julien

În conformitate cu acest curs, modul corect de a face acest lucru este:

Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES
    )

Aceasta vă va oferi calea rădăcină pentru directorul galeriei.

Comentarii

  • am încercat acest nou cod, dar s-a blocat java.lang.NoSuchFieldError: android.os.Environment.DIRECTORY_PICTURES –  > Por Christian Giupponi.
  • ok mulțumesc, deci nu există nici o modalitate de a pune o imagine pe galerie cu android < 2.2? –  > Por Christian Giupponi.
  • Perfect – un link direct către site-ul Android Developer. Acest lucru a funcționat și a fost o soluție simplă. –  > Por Phil.
  • Răspuns bun, dar ar fi mai bine cu adăugarea metodei „galleryAddPic” din celelalte răspunsuri de aici, deoarece, de obicei, veți dori ca aplicația Gallery să observe noile imagini. –  > Por Andrew Koster.
  • Environment.getExternalStoragePublicDirectory este deja depreciată… –  > Por Michael Abyzov.
nitin Sol
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);
}

javatar

Puteți crea un director în interiorul dosarului camerei și salvați imaginea. După aceea, puteți efectua pur și simplu scanarea. Se va afișa instantaneu imaginea dvs. în galerie.

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

Comentarii

  • în acest criteriu, acesta este cel mai bun răspuns –  > Por Noor Hossain.
Slaters

Vin aici cu aceeași îndoială, dar pentru Xamarin pentru Android, am folosit răspunsul Sigrist pentru a face această metodă după ce am salvat fișierul meu:

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

și mi-a rezolvat problema, Thx Sigrist. Am pus-o aici pentru că nu am găsit un answare despre acest lucru pentru Xamarin și sper că poate ajuta alte persoane.

dc10

În cazul meu, soluțiile de mai sus nu au funcționat, a trebuit să fac următoarele:

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

Comentarii

  • este foarte bine de știut despre această opțiune, dar, din păcate, nu funcționează pe unele dispozitive cu Android 6, așa că ContentProvider preferabil solytion –  > Por Siarhei.
Bhavik Mehta
 String filePath="/storage/emulated/0/DCIM"+app_name;
    File dir=new File(filePath);
    if(!dir.exists()){
        dir.mkdir();
    }

Acest cod se află în metoda onCreate.Acest cod este pentru crearea unui director de nume_aplicație.Acum, acest director poate fi accesat folosind aplicația implicită de gestionare a fișierelor din Android.Folosiți acest șir filePath oriunde este necesar pentru a seta dosarul de destinație.Sunt sigur că această metodă funcționează și pe Android 7, deoarece am testat-o.Prin urmare, poate funcționa și pe alte versiuni de Android.