Добавить изображение в Media Gallery – Android

Я пытаюсь добавить новое изображение в галерею. Я выбираю уже существующее изображение, хотя намерение, а затем изменяю его размер и сжимаю.

Затем я сохраняю полученный битмап:

public static File compressAndSaveImage(Context ctx, Uri imageUri) throws FileNotFoundException { File file = null; if (imageUri != null) { ContextWrapper cw = new ContextWrapper(ctx); File directory = cw.getDir("imageDir", Context.MODE_PRIVATE); file = new File(directory, imageUri.getLastPathSegment()); System.out.println("storing to " + file); InputStream input = ctx.getContentResolver().openInputStream(imageUri); Bitmap b = ImageManager.resize(BitmapFactory.decodeStream(input), ctx.getResources().getDimension(R.dimen.player_thumb_w), ctx.getResources().getDimension(R.dimen.player_thumb_h)); FileOutputStream fos = new FileOutputStream(file); if (b.compress(Bitmap.CompressFormat.PNG, 100, fos)) { System.out.println("Compression success");// bmp is your Bitmap instance } addPictureToGallery(ctx, file); } return file; } 

Но когда я пытаюсь добавить изображение в галерею, я не получаю ошибок и изображение не добавляется. Я попробовал оба метода ниже:

 private static void addPictureToGallery(Context ctx, File filepath) { // Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); // System.out.println("Publish: " + filepath.exists()); // System.out.println("Publish: " + filepath.getAbsolutePath()); // Uri contentUri = Uri.fromFile(filepath); // mediaScanIntent.setData(contentUri); // ctx.sendBroadcast(mediaScanIntent); MediaScannerConnection.scanFile( ctx, new String[]{filepath.getAbsolutePath()}, null, new MediaScannerConnection.OnScanCompletedListener() { @Override public void onScanCompleted(String path, Uri uri) { Log.w("mydebug", "file " + path + " was scanned successfully: " + uri); } }); } } 

Обратный вызов печатает следующую строку:

 file /data/data/test.myapps.appname/app_imageDir/6045564126748266738 was scanned successfully: content://media/external/file/7838 

Что мне не хватает?

Я бы поставил это как комментарий, поскольку у меня нет времени, чтобы действительно подробно рассказать о вещах, но это явно слишком долго. Попробуйте что-то вроде этого (я использую это для хранения растровых изображений в галерее). В качестве примечания, похоже, что вы ничего не делаете, кроме сканирования изображения. Сейчас кажется, что вы храните файл на своем внутреннем хранилище, а не на вашем телефоне (галерея).

Предположим, что мы запускаем это из ActivityA.class, который расширяет активность

  /** * Will save our card (currently set as a bitmap) as a jpeg and save it into our devices * native photo gallery. Unfortunately, the default method for this will add the image to the bottom * of the gallery by default, that is no good. This more complex method that utilizes Android's * native methods will allow us to store the bitmap at the top of the gallery by setting it's * meta data to today's date. */ public class SaveBitmapToDevice extends AsyncTask<Bitmap, Void, String>{ private final ShareType type; public SaveBitmapToDevice(ShareType type){ this.type = type; } @Override protected String doInBackground(Bitmap... cards) { return insertImageIntoGallery(getContentResolver(), cards[0], getString(R.string.card_gallery_title), getString(R.string.card_gallery_label)); } /** * 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(android.content.ContentResolver, Bitmap, String, String). * If the MediaStore not available, we will redirect the file to our alternative source, the SD card. */ public String insertImageIntoGallery(ContentResolver cr, Bitmap source, String title, String description) { ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.TITLE, title); values.put(MediaStore.Images.Media.DISPLAY_NAME, title); values.put(MediaStore.Images.Media.DESCRIPTION, description); values.put(MediaStore.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(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis()); values.put(MediaStore.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 = MediaStore.Images.Thumbnails.getThumbnail(cr, id, MediaStore.Images.Thumbnails.MINI_KIND, null); // This is for backward compatibility. storeThumbnail(cr, miniThumb, id, 50F, 50F, MediaStore.Images.Thumbnails.MICRO_KIND); } else { cr.delete(url, null, null); return storeToAlternateSd(source, title); // url = null; } } catch (Exception e) { if (url != null) { cr.delete(url, null, null); return storeToAlternateSd(source, title); // url = null; } } savedOnSD = false; 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 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(MediaStore.Images.Thumbnails.KIND,kind); values.put(MediaStore.Images.Thumbnails.IMAGE_ID,(int)id); values.put(MediaStore.Images.Thumbnails.HEIGHT,thumb.getHeight()); values.put(MediaStore.Images.Thumbnails.WIDTH,thumb.getWidth()); Uri url = cr.insert(MediaStore.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) { Log.e("IMAGE_COMPRESSION_ERROR", "File not found"); ex.printStackTrace(); return null; } catch (IOException ex) { Log.e("IMAGE_COMPRESSION_ERROR", "IO Exception"); ex.printStackTrace(); return null; } } /** * If we have issues saving into our MediaStore, save it directly to our SD card. We can then interact with this file * directly, opposed to pulling from the MediaStore. Again, this is a backup method if things don't work out as we * would expect (seeing as most devices will have a MediaStore). * * @param src * @param title * @return - the file's path */ private String storeToAlternateSd(Bitmap src, String title){ if(src == null) return null; File sdCardDirectory = new File(Environment.getExternalStorageDirectory() + File.separator + "My Cards"); if(!sdCardDirectory.exists()) sdCardDirectory.mkdir(); SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yyyy - (hh.mm.a)", Locale.US); File image = new File(sdCardDirectory, title + " -- [" + sdf.format(new Date()) + "].jpg"); try { FileOutputStream imageOut = new FileOutputStream(image); src.compress(Bitmap.CompressFormat.JPEG, 100, imageOut); imageOut.close(); savedOnSD = true; return image.getAbsolutePath(); } catch (FileNotFoundException ex) { ex.printStackTrace(); return null; } catch (IOException ex) { ex.printStackTrace(); return null; } } @Override public void onPostExecute(String url){ if(url != null){ Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); if(savedOnSD){ File file = new File(url); if(file.exists()) intent.setDataAndType(Uri.fromFile(file), "image/jpeg"); else return; } else intent.setDataAndType(Uri.parse(imageUrl), "image/jpeg"); ActivityA.this.startActivity(intent); } else Toast.makeText(ActivityA.this, getString(R.string.error_compressing), Toast.LENGTH_SHORT).show(); } } 

Спасибо @ zgc7009, ты поставил меня на правильный путь. Я использовал часть вашего кода, и это конечный результат для всех, кто хочет решить.

Проблема в том, что я сохранял изображение в локальном хранилище моего приложения.

 File storedImagePath = generateImagePath("player", "png"); if (!compressAndSaveImage(storedImagePath, bitmap)) { return null; } Uri url = addImageToGallery(context.getContentResolver(), "png", storedImagePath); 

Где используются три метода:

Создать путь

 private static File getImagesDirectory() { File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + File.separator + IMAGE_DIR);//Environment.getExternalStorageDirectory() if (!file.mkdirs() && !file.isDirectory()) { Log.e("mkdir", "Directory not created"); } return file; } public static File generateImagePath(String title, String imgType) { SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy-hh-mm-ss"); return new File(getImagesDirectory(), title + "_" + sdf.format(new Date()) + "." + imgType); } 

Сжатие и сохранение

 public boolean compressAndSaveImage(File file, Bitmap bitmap) { boolean result = false; try { FileOutputStream fos = new FileOutputStream(file); if (result = bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)) { Log.w("image manager", "Compression success"); } fos.close(); } catch (IOException e) { e.printStackTrace(); } return result; } 

Добавить в галерею

 public Uri addImageToGallery(ContentResolver cr, String imgType, File filepath) { ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.TITLE, "player"); values.put(MediaStore.Images.Media.DISPLAY_NAME, "player"); values.put(MediaStore.Images.Media.DESCRIPTION, ""); values.put(MediaStore.Images.Media.MIME_TYPE, "image/" + imgType); values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis()); values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis()); values.put(MediaStore.Images.Media.DATA, filepath.toString()); return cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); } 

Вы также можете использовать статические методы MediaStore …

 public String addImageToGallery(ContentResolver cr, File filepath) { try { retrun MediaStore.Images.Media.insertImage(cr, filepath.toString(), filepath.getName(), "Image Description"); } catch (FileNotFoundException e) { e.printStackTrace(); } } 

String возвращаемая из insertImage такая же, как вызов toString() объекта Uri в принятом ответе.

Я знаю, что это более старая должность, но я надеюсь, что это поможет другим, которые все еще находят свой путь здесь.

Intereting Posts
Не удалось создать проект проекта cocos2d-x android: Неизвестный атрибут объекта EABI 44 Поддержка sip-менеджера api Настройка фильтра на основе пользовательских данных Android Emulator -Error появляется при запуске приложения для Android Как использовать блокировку бодрствования для медиапланета андроида? Адвокатское посредничество – идентификатор издателя против идентификатора медиации Где хранить звуковые файлы в проекте и какое решение выбрать для хранения реферансов к ним Как показать всплывающее сообщение без контекста Разница между android.app.Fragment и android.support.v4.app.Fragment Android Studio переводит проект на другой компьютер? Хотите создать папку в SD-карте на AVD Intellij IDEA 14 – Пакет R не существует Получение TypeNotPresentException, за которым следует ClassNotFoundException или NoClassDefFoundError для всех версий Android, кроме android L WebView в CoordinatorLayout с CollapsingToolbarLayout Проблемы с mTextEditorWatcher на Android