I have to share GIF images from URL to some other applications using intent, as per my knowledge for sharing them from url I have to save them first in my phone's memory.
I have used GLIDE lib to show them, how could I store them to share? My code so far (not working): It saves only one image from the set of frames of GIF image.
if (mGIFArrayList != null) {
// imageUri = getLocalBitmapUri(imageViewSimple);
// shareWithAppChooser(imageUri,"");
Glide
.with(mContext)
.load(mGIFArrayList.get(getPosition()).getStrUrl())
.asGif()
.toBytes()
.into(new SimpleTarget<byte[]>() {
#Override public void onResourceReady(final byte[] resource, GlideAnimation<? super byte[]> glideAnimation) {
new AsyncTask<Void, Void, Void>() {
#Override protected Void doInBackground(Void... params) {
// File sdcard = Environment.getExternalStorageDirectory();
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "shared_gif_" + System.currentTimeMillis() + ".gif");
File dir = file.getParentFile();
try {
if (!dir.mkdirs() && (!dir.exists() || !dir.isDirectory())) {
throw new IOException("Cannot ensure parent directory for file " + file);
}
BufferedOutputStream s = new BufferedOutputStream(new FileOutputStream(file));
s.write(resource);
s.flush();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}.execute();
}
})
;
}
on the following two lines you determine that the drawable is a GlideBitmapDrawable
Drawable drawable = imageView.getDrawable();
if (drawable instanceof GlideBitmapDrawable) {
and then on the following like you cast it to GifDrawable:
GifDrawable gifDrawable = ((GifDrawable) imageView.getDrawable());
I'm sure it's throwing a ClassCastException as GifDrawable and GlideBitmapDrawable are not related.
Unfortunately I don't think you can extract the file from the GifDrawable, because it doesn't work like this.
Probably your best workaround it, is to download the gif file from the link to the device storage, and then sharing the file.
Related
Is it possible to show previously downloaded image in Glide as placeholder while downloading new image.
Like I have an image loaded in imageview using glide. Now the imageurl is changed, so while loading this new image is it possible to keep displaying the old image (might be from cache).
What I want is while the new image is being loaded from the URL, is it possible to keep the current image as placeholder.
I found the answer to this in the discussion here - https://github.com/bumptech/glide/issues/527#issuecomment-148840717.
Intuitively I also thought of using placeholder(), but the problem is that as soon as you load the second image, you loose the reference to the first one. You can still reference it but it is not safe as it may be reused by Glide or recycled.
The proposed solution from the discussion is to use thumbnail() and load the first image again. The load will return the first image immediately from the memory cache and it will look as if the image did not change until the second image is loaded:
String currentImageUrl = ...;
String newImageUrl = ...;
Glide.with(this)
.load(newImageUrl)
.thumbnail(Glide.with(this)
.load(currentImageUrl)
.fitCenter()
)
.fitCenter()
.into(imageView);
Glide have a capability of getting the bitmap of the image from that url, so just get it and then save it to a desired storage into your phone, and after that in your .placeholder() just use that bitmap when you are trying to get another image , take a look at this snippet
/** Download the image using Glide **/
Bitmap theBitmap = null;
theBitmap = Glide.
with(YourActivity.this).
asBitmap().
load("Url of your image").
into(-1, -1).
get(); //with this we get the bitmap of that url
saveToInternalStorage(theBitmap, getApplicationContext(), "your preferred image name");
/** Save it on your device **/
public String saveToInternalStorage(Bitmap bitmapImage, Context context, String name){
ContextWrapper cw = new ContextWrapper(context);
// path to /data/data/yourapp/app_data/imageDir
String name_="foldername"; //Folder name in device android/data/
File directory = cw.getDir(name, Context.MODE_PRIVATE);
// Create imageDir
File mypath=new File(directory,name_);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mypath);
// Use the compress method on the BitMap object to write image to the OutputStream
bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.e("absolutepath ", directory.getAbsolutePath());
return directory.getAbsolutePath();
}
/** Method to retrieve image from your device **/
public Bitmap loadImageFromStorage(String path, String name)
{
Bitmap b;
String name_= name; //your folderName
try {
File f=new File(path, name_);
b = BitmapFactory.decodeStream(new FileInputStream(f));
return b;
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
return null;
}
/** Retrieve your image from device and set to imageview **/
//Provide your image path and name of the image your previously used.
Bitmap b= loadImageFromStorage(String path, String name)
ImageView img=(ImageView)findViewById(R.id.your_image_id);
img.setImageBitmap(b);
I want to implement functionality for saving image in Downloads directory and after that offer to user to open this one in a directory (open directory in which user can find and open this image). But I've got one issue. Saving ends successfully, but when user clicks "OPEN" in snackbar and chooses app to perform this action another directory appears. It contains also "Downloads" directory as well, this Downloads directory does not contain saved images! It seems like in android we have two different "Downloads" directories.
Below is how i get path for save image:
private File getFileForImageSaving() {
String filename = getImageNameFromUrl(mImageUrl) + ".png";
File dest = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
filename);
int index = 1;
while (dest.exists()) {
filename = getImageNameFromUrl(mImageUrl) + "_" + index + ".png";
dest = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
filename);
index++;
}
return dest;
}
This is how i run activity for view "Download" directory and open files.
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
Uri uri = Uri.parse(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath());
intent.setDataAndType(uri, "image/png");
startActivity(Intent.createChooser(intent, "Open folder"));
This is how I save image. It is realy works, I've checked.
pri
vate void saveImageToFile() {
File dest = getFileForImageSaving();
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
FileOutputStream out = null;
try {
dest.createNewFile();
out = new FileOutputStream(dest);
Bitmap bitmap = Glide.with(ArticleImageViewActivity.this)
.load(mImageUrl)
.asBitmap()
.into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.get();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
Utils.showInSnackBar(
ArticleImageViewActivity.this, getString(R.string.image_has_been_successfully_saved),
Snackbar.LENGTH_LONG,
onOpenImageInDirectoryListener,
getString(R.string.open_image_in_directory));
} catch (Exception e) {
Utils.showInSnackBar(ArticleImageViewActivity.this,
getString(R.string.error_occurred_during_saving_image),
Snackbar.LENGTH_SHORT, null, null);
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}.execute();
}
I partially resolve my problem by using Intent.ACTION_VIEW instead of Intent.ACTION_GET_CONTENT and " / " mime type instead of "image/png". But only partially because in this case user will be offered to choose a wide range of applications, but not only applications like filemanagers.
use MediaScannerConnection.scanFile to scan the file after saving. if you don't many/most galleries wont show your file.
https://developer.android.com/reference/android/media/MediaScannerConnection.html
I've been using the way the system saves screenshots to save my bitmaps to the disk and gallery. This works in Android 4.2 and before but not in Android 4.3.
Relevant code :
Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
OutputStream out = resolver.openOutputStream(uri);
Full code here.
In 4.3 (new Nexus 7) however, I get a FileNotFoundException on the second line. I couldn't see any changes in 4.3 relevant to this on the website.
So what is the right way to save an image to the disk and gallery?
Verified :
storage is mounted with this method
imageUri is not null (usually something like "content://media/external/images/media/2034")
manifest has permission android.permission.WRITE_EXTERNAL_STORAGE
This is the way I save bitmaps to the Gallery:
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri; //instantiate Uri with location of image
mediaScanIntent.setData(contentUri);
context.sendBroadcast(mediaScanIntent);
In your manifest file try with change target sdk to 18.-
<uses-sdk android:minSdkVersion="7"
android:targetSdkVersion="18"/>
It might solve your prob(May not). In 4.3 JELLY_BEAN_MR2, android did couple of changes and android clearly written that Your app might misbehave in a restricted profile environment. so please look at http://developer.android.com/about/versions/android-4.3.html
I have these permission in my Manifest.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
But I am using a Target SDK version 15. Is there a requirement that you have to use a target SDK 18?
BTW:
Here is a sample code for downloading profile pictures from Facebook:
private class DownloadProfilePicTask extends AsyncTask<Void,String,String> {
Bitmap profilePic;
String fileName;
String id;
String type;
URL img_value;
public DownloadProfilePicTask(String i,String ty)
{
id = i;
if(id==null)
{
//Log.v("Id is null", "Error");
}
//Log.v("Download Profile Pic Task initialized for id:",id);
type = ty;
}
#Override
protected String doInBackground(Void...param) {
String root = Environment.getExternalStorageDirectory().toString();
if(root==null)
{
return null;
}
try{
profilePic = BitmapFactory.decodeStream(img_value.openConnection().getInputStream());
}
catch (IOException e) {
e.printStackTrace();
}
if(profilePic == null)
{
//Log.v("profilePic is null", "Error");
}
//Log.v("Root for saving images",root );
File myDir = new File(root + "/saved_images");
myDir.mkdirs();
fileName = root + "/saved_images/" + id + ".png";
//Log.v("filename is ",fileName);
File file = new File (fileName);
fileName = file.getPath();
if (file.exists ()) file.delete ();
try {
FileOutputStream out = new FileOutputStream(file);
profilePic.compress(Bitmap.CompressFormat.PNG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
return id;
}
#Override
protected void onPreExecute()
{
try
{
img_value = new URL("http://graph.facebook.com/"+id+"/picture?type=" + type);
}
catch (MalformedURLException e) {
e.printStackTrace();
}
}
#Override
protected void onPostExecute(String result) {
}
}
and then I just call:
new DownloadProfilePicTask(id,type).execute();
to download and automatically save images.
Note: You will have to play with filePath a bit for exact location.
There some changes in the fileSystem on Android 4.3 to start to avoid dev. to directly write in "/sdcard" or "/mnt/sdcard" but use the android ExternalStorage system. (http://source.android.com/devices/tech/storage/index.html)
N.B. : ExternalStorage can be an internal memory :p
For your case, have you tryed to use a method based on getExternalStorage ?
(like this : Find an external SD card location)
So I have the following code in an AsyncTask. The AsyncTask takes in a url to an image file, downloads it into a Bitmap, saves the Bitmap off to disk somewhere, and then displays the Bitmap in an existing ImageView.
Here's the implementation of the doInBackground() call for my AsyncTask:
protected Bitmap doInBackground(String... urls) {
try {
URL image_url = new URL(urls[0]);
String image_url_prefix_regex = "http://www\\.somewebsite\\.com";
if (externalStorageIsAvailable()) {
String file_path = getExternalFilesDir(null).getPath() + image_url.toString().replaceAll(image_url_prefix_regex, "");
File target_file = new File(file_path);
if (!target_file.getParentFile().exists()) {
target_file.getParentFile().mkdirs();
}
BitmapFactory.Options bitmap_options = new BitmapFactory.Options();
bitmap_options.inScaled = false;
bitmap_options.inDither = false;
bitmap_options.inPreferredConfig = Bitmap.Config.ARGB_8888;
bitmap_options.inPreferQualityOverSpeed = true;
bitmap_options.inSampleSize = 1;
Bitmap image = BitmapFactory.decodeStream(image_url.openStream(), null, bitmap_options);
image.compress(CompressFormat.JPEG, 100, new FileOutputStream(target_file));
return image;
}
}
catch (MalformedURLException e) {
Log.v(DEBUG_TAG, "Error: Caught MalformedURLException");
}
catch (IOException e) {
Log.v(DEBUG_TAG, "Error: Caught IOException");
}
return null;
}
Then later in the onPostExecute() call I have this:
protected void onPostExecute(Bitmap image) {
ImageView mImageView = (ImageView) findViewById(R.id.main_image);
mImageView.setImageBitmap(image);
}
Yet when the code downloads and displays the image, the image is reduced in size and quality. How do I make it so that the resulting image is full quality? Those BitmapFactory.Options settings are the things I've tried thus far, but they did not seem to work.
Note that I'm not asking about the image that gets saved to external storage. I think that one will likely be of lower quality due to getting compressed again, but that shouldn't affect the image I'm sending to my ImageView, which is what I'm asking about. Of course, if there's anything wrong with these assumptions please point them out.
Why you are using Bitmap factory options while decoding bitmap Stream ?
Just use the
Bitmap image = BitmapFactory.decodeStream(image_url.openStream());
instead of
Bitmap image = BitmapFactory.decodeStream(image_url.openStream(), null, bitmap_options);
I am trying to use an image from the sd card and set it as the background for a relativelayout. I have tried other solutions that i have found here and elsewhere but they havent seemed to work for me. here is my code. I have commented out other ways that i have tried and didnt work. the only thing that worked for me was using setBackgroudnResource and using a resource from the app, but this was just to test to make sure mRoot was set up correctly. when I have tried all the other ways, it just doesn't set anything. Anyone know what I am doing wrong, or if there is a better way to do this?
//one way i tired...
//String extDir = Environment.getExternalStorageDirectory().toString();
//Drawable d = Drawable.createFromPath(extDir + "/pic.png");
//mRoot.setBackgroundDrawable(d);
//another way tried..
//Drawable d = Drawable.createFromPath("/sdcard/pic.png");
//mRoot.setBackgroundDrawable(d);
//last way i tried...
mRoot.setBackgroundDrawable(Drawable.createFromPath(new File(Environment.getExternalStorageDirectory(), "pic.png").getAbsolutePath()));
//worked, only to verify mRoot was setup correctly and it could be changed
//mRoot.setBackgroundResource(R.drawable.bkg);
You do not load a drawable from SD card but a bitmap. Here is a method to load it with the reduced sampling (quality) so the program will not complain if the image is too large. Then I guess you need to process this bitmap i.e. crop it and resize for the background.
// Read bitmap from Uri
public Bitmap readBitmap(Uri selectedImage) {
Bitmap bm = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2; //reduce quality
AssetFileDescriptor fileDescriptor =null;
try {
fileDescriptor = this.getContentResolver().openAssetFileDescriptor(selectedImage,"r");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
finally{
try {
bm = BitmapFactory.decodeFileDescriptor(fileDescriptor.getFileDescriptor(), null, options);
fileDescriptor.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return bm;
}
The Uri here can be supplied from a gallery picker activity.
The image then can be saved into application resources and loaded into an imageView
private void saveBackground(Bitmap Background) {
String strBackgroundFilename = "background_custom.jpg";
try {
Background.compress(CompressFormat.JPEG, 80, openFileOutput(strBackgroundFilename, MODE_PRIVATE));
} catch (Exception e) {
Log.e(DEBUG_TAG, "Background compression and save failed.", e);
}
Uri imageUriToSaveCameraImageTo = Uri.fromFile(new File(BackgroundSettings.this.getFilesDir(), strBackgroundFilename));
// Load this image
Bitmap bitmapImage = BitmapFactory.decodeFile(imageUriToSaveCameraImageTo.getPath());
Drawable bgrImage = new BitmapDrawable(bitmapImage);
//show it in a view
ImageView backgroundView = (ImageView) findViewById(R.id.BackgroundImageView);
backgroundView.setImageURI(null);
backgroundView.setImageDrawable(bgrImage);
}
File file = new File( url.getAbsolutePath(), imageUrl);
if (file.exists()) {
mDrawable = Drawable.createFromPath(file.getAbsolutePath());
}
I suggest checking that the drawable is being loaded correctly. Some things to try:
Try using a different image on the sd card
Put pic.png in R.drawable and make sure mRoot.setBackgroundResource() does what you expect
After loading the drawable, check d.getBounds() to make sure it is what you expect