I know it is possible to use another app's bitmaps using the following blockquote, or similar:
String packageName = "com.some.package";
Resources res = getPackageManager().getResourcesForApplication(packageName);
int resId = res.getIdentifier("some_bitmap_icon", "drawable", packageName);
((BitmapDrawable) res.getDrawable(resId)).getBitmap();
Is there anyway of passing res and resIdto Android-Universal-Image-Loader to directly load the bitmap from the 3rd party app?
Or would I have to copy the bitmap to the SD card, then display it by passing "file:///mnt/sdcard/some_temp_bitmap"
Thanks to #CommonsWare for pointing me in the right direction.
I started by extending BaseImageDownloader, and overriding getStreamFromOtherSource:
public class CustomImageDownloader extends BaseImageDownloader {
public CustomImageDownloader(Context context) {
super(context);
}
#Override
protected InputStream getStreamFromOtherSource(String imageUri, Object extra) {
if (imageUri.startsWith("thirdparty://")) {
try {
String drawableString = imageUri.replace("thirdparty://", "");
String[] location = drawableString.split("/");
Resources res = context.getPackageManager().getResourcesForApplication(location[0]);
return res.openRawResource(Integer.parseInt(location[1]));
} catch (PackageManager.NameNotFoundException e) {
return null;
}
} else throw new UnsupportedOperationException(imageUri);
}
}
Then implemented this class in my ImageLoaderConfiguration using:
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
.imageDownloader(new CustomImageDownloader(context))
.build();
ImageLoader.getInstance().init(config);
Then it's just a case of starting the image loader using:
ImageLoader.getInstance().displayImage("thirdparty://"+ packageName + "/" + resId, imageView, options);
Now Android universal image loader can be used for loading bitmaps from 3rd party apps.
Related
So i basically have method which converts one image with some shape and than makes Drawable from my bitmap. Now there was method load bitmap drawable (setImageDrawable) but its deprecated.
So code is like this:
public static Drawable getDrawableFromName(String name, Activity activity) {
int resourceId = activity.getResources().getIdentifier(name, "drawable", activity.getPackageName());
if(resourceId == 0) {
return null;
} else {
Bitmap croppedIcon = cropImage(activity, resourceId);
if(croppedIcon == null)
return null;
return new BitmapDrawable(activity.getResources(), croppedIcon);
}
}
cropImage return bitmap image with some custom shape.
How should i now load this drawable, which is actually nowhere located only in memory (as its generated) to Fresco SimpleDraweeView. Is it somehow possible to have this as Uri resource?
Uri uri = new Uri.Builder()
.scheme(UriUtil.LOCAL_RESOURCE_SCHEME) // "res"
.path(String.valueOf(resId))
.build();
simpleDraweeView.setImageURI(uri);
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.
Universal Image Loader provide many ways to load the image.
"file:///mnt/sdcard/image.png" // from SD card
"file:///mnt/sdcard/video.mp4" // from SD card (video thumbnail)
"content://media/external/images/media/13" // from content provider
"content://media/external/video/media/13" // from content provider (video thumbnail)
"assets://image.png" // from assets
"drawable://" + R.drawable.img // from drawables (non-9patch images)
But all these way load image form file, I need a way to load from memory since my images was encrypted and stored in the assets folder, When I display this image, I need the following steps.
decrypt the image into bytes array.
Create bitmap from the bytes.
Load/display the image.
So it's something like this. Is that possible?
Bitmap bitmap = decrypt(encryptedImageFile);
imageLoader.displayImage(bitmap, imageView);
Currently, I am considering to save the bitmap to file and load the file, but this will take more time.
I believe the below is what you are seeking if your images are stored in image folder in assets directory, then you can get the list of images
private List<String> getImage(Context conetx) throws IOException {
AssetManager assetManager =conetx.getAssets();
String[] files = assetManager.list("image");
List<String> it=Arrays.asList(files);
return it;
}
As a note, instead of using assets dir, put the file into /res/raw and you can then access it using the following URI
android.resource://com.your.packagename/" + R.raw.<nameoffile>
I think you need to understand this. You must know, If you have read the source code of universal-image-loader, the order of loading a image into a ImageView after the image's url is provided, is: memory, SDCard(if set), internet. That means after you called, ImageLoader.display(url, imageview);, it will look for the Bitmap from memory first, if it doesn't exist, if will look for the file of the image from SDCard then, if the file exist, if will convert the file into a Bitmap, then load the Bitmap into the ImageView and store it in memory. But if the file doesn't exist, it will download the image file of the url, then store the file into the SDCard and convert the file into a Bitmap and load the Bitmap into memory. Most importantly, I recommend you to read source codes of it, if you are confused with what I post above.
So, it is unnecessary for you to load the Bitmap from memory, ImageLoader will do it for you.
Lets choose own scheme so our URIs will look like "stream://...".
Then implement ImageDownloader. We should catch URIs with our scheme and return image stream.
public class StreamImageDownloader extends BaseImageDownloader {
private static final String SCHEME_STREAM = "stream";
private static final String STREAM_URI_PREFIX = SCHEME_STREAM + "://";
public StreamImageDownloader(Context context) {
super(context);
}
#Override
protected InputStream getStreamFromOtherSource(String imageUri, Object extra) throws IOException {
if (imageUri.startsWith(STREAM_URI_PREFIX)) {
return (InputStream) extra;
} else {
return super.getStreamFromOtherSource(imageUri, extra);
}
}
}
DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
.build();
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
.defaultDisplayImageOptions(defaultOptions)
.imageDownloader(new StreamImageDownloader(getApplicationContext()))
.build();
ImageLoader.getInstance().init(config);
ByteArrayInputStream stream = new ByteArrayInputStream(imgBytes);
String imageId = "stream://" + stream.hashCode();
DisplayImageOptions options = new DisplayImageOptions.Builder()
.extraForDownloader(stream)
.build();
ImageLoader.getInstance().displayImage(imageId, imageView, options);
I need to get the file URL to an image that I store locally in my app. I don't care where I store the file locally, just somewhere in which I can get a URL to it. I have tried assets and resources with no luck.
What I am trying to do is override UrlTileProvider:
public class FileSystemTileProvider extends UrlTileProvider {
public FileSystemTileProvider(int width, int height, String assestsDirectory) {
super(width, height);
}
#Override
public URL getTileUrl(int x, int y, int z) {
String tile = "file://<somewhere>/background.png";
URL fileUrl = null;
try {
fileUrl = new URL(tile);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return fileUrl;
}
}
I need to return a URL for this to work. I have hardcoded a file url and it does work. However I need a way to get a URL for my background.png image. Is this possible?
The easiest way would probably be to include the file as an asset in the APK, then extract it to the app's private directory with an AssetManager. For example as explained in this answer, except using getFilesDir() instead of getExternalFilesDir() (or even easier, by creating the FileOutputStream object with openFileOutput()).
Another option (especially if you want/need to provide different background images for different display densities) is to include it as a drawable, then extract it with a similar method.
After you have done either of these (only once, say at the main activity's start-up) and saved the file with a known name, just create the URL to this file.
File backgroundFile = new File(getFilesDir(), fileName);
URL fileUrl = backgroundFile.toURI().toURL();
I don't think you can access it that way.
But you can instead implement directly TileProvider and write your own implementation of
public Tile getTile (int x, int y, int zoom) {
//get the drawable
...
Bitmap bitmap = drawable.getBitmap();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
return Tile(WIDTH, HEIGHT, stream.toByteArray());
}
Get the drawable from the drawables folder with:
Resources res = getResources();
Drawable shape = res. getDrawable(R.drawable.background);
or from assets folder with:
InputStream ins = getAssets().open("background.jpg");
Drawable d = Drawable.createFromStream(ins, null);
Query to MediaStore.Video.Media.EXTERNAL_CONTENT_URI returns only video in /sdcard/DCIM/100MEDIA
But I want to get thumbnails for video in my /sdcard/Android/data/mypackage/files folder. Is it possible ?
Here is part of my code:
ContentResolver cr = getContentResolver();
String[] proj = {
BaseColumns._ID
};
Cursor c = cr.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, proj, null, null, null);
if (c.moveToFirst()) {
do
{
int id = c.getInt(0);
Bitmap b = MediaStore.Video.Thumbnails.getThumbnail(cr, id, MediaStore.Video.Thumbnails.MINI_KIND, null);
Log.d("*****My Thumbnail*****", "onCreate bitmap " + b);
ImageView iv = (ImageView) findViewById(R.id.img_thumbnail);
iv.setImageBitmap(b);
}
while( c.moveToNext() );
}
c.close();
If you are on android-8 (Froyo) or above, you can use ThumbnailUtils.createVideoThumbnail:
Bitmap thumb = ThumbnailUtils.createVideoThumbnail(path,
MediaStore.Images.Thumbnails.MINI_KIND);
Use Glide it will fetch the thumbnail in async.
Glide.with(context)
.load(videoFilePath) // or URI/path
.into(imgView); //imageview to set thumbnail to
3 ways to get a thumbnail from a video:
The best way is to use Glide. It will do all the work in the background, load the thumbnail right into the ImageView and even can show animation when loading. It can work with Uri, byte[] and many other sources.
As #Ajji mentioned:
Glide.with(context)
.load(videoFilePath) // or URI/path
.into(imgView); //imageview to set thumbnail to
If you just need a bitmap in the most efficient way - use ThumbnailUtils.
In my case, it produced a bitmap with a size of 294 912 bytes (video taken with a camera of Nexus5X - 1280x720) and the quality was the same as in the next approach. After you compress into JPEG with 90 it will generate a jpeg file of ~30Kb.
Bitmap thumb = ThumbnailUtils.createVideoThumbnail(path,
MediaStore.Images.Thumbnails.MINI_KIND);
The last approach is to use MediaMetadataRetriever. But in my case, it produced a bitmap with size more than 6 times bigger than you got with ThumbnailUtils (with the same quality). So consider it as a last resort.
MediaMetadataRetriever mMMR = new MediaMetadataRetriever();
mMMR.setDataSource(mContext, mAttachment.getUri());
bmp = mMMR.getFrameAtTime();
P.S.: Don't forget that images in Bitmap, byte[] and real file .jpeg formats can be easily converted in any direction within these types. In case of Uri's you often don't have real path to the source file but you can always get the byte stream from it like this:
InputStream in = mContext.getContentResolver().openInputStream(uri);
and with this input stream you can do whatever you want.
You can just use FFmpegMediaMetadataRetriever and forget the reflection:
/**
*
* #param path
* the path to the Video
* #return a thumbnail of the video or null if retrieving the thumbnail failed.
*/
public static Bitmap getVideoThumbnail(String path) {
Bitmap bitmap = null;
FFmpegMediaMetadataRetriever fmmr = new FFmpegMediaMetadataRetriever();
try {
fmmr.setDataSource(path);
final byte[] data = fmmr.getEmbeddedPicture();
if (data != null) {
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
}
if (bitmap == null) {
bitmap = fmmr.getFrameAtTime();
}
} catch (Exception e) {
bitmap = null;
} finally {
fmmr.release();
}
return bitmap;
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDither = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmapThumb = MediaStore.Video.Thumbnails.getThumbnail(mActivity.getContentResolver(),
Long.parseLong(video_id),
Images.Thumbnails.MINI_KIND,
options);
Use Options to load bitmap of decrease the bitmap size..
see #Ajji 's answer :
Glide.with(context)
.load(videoFilePath) // or URI/path
.into(imgView); //imageview to set thumbnail to
It sometimes returns black image, this issue is already mentioned in Glide library's issues
Use this code:
BitmapPool bitmapPool = Glide.get(activity).getBitmapPool();
int microSecond = 6000000;// 6th second as an example
VideoBitmapDecoder videoBitmapDecoder = new VideoBitmapDecoder(microSecond);
FileDescriptorBitmapDecoder fileDescriptorBitmapDecoder = new FileDescriptorBitmapDecoder(videoBitmapDecoder, bitmapPool, DecodeFormat.PREFER_ARGB_8888);
Glide.with(activity)
.load(videoPath)
.asBitmap()
.override(50,50)// Example
.videoDecoder(fileDescriptorBitmapDecoder)
.into(holder.ivFirstUpload);
Get video thumbnail from VIDEO_ID:
public static Drawable getVideoThumbnail(Context context, int videoID) {
try {
String[] projection = {
MediaStore.Video.Thumbnails.DATA,
};
ContentResolver cr = context.getContentResolver();
Cursor cursor = cr.query(
MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI,
projection,
MediaStore.Video.Thumbnails.VIDEO_ID + "=?",
new String[] { String.valueOf(videoID) },
null);
cursor.moveToFirst();
return Drawable.createFromPath(cursor.getString(0));
} catch (Exception e) {
}
return null;
}
Here is a similar answer to Matthew Willis but with added reflection. Why? because science.
/**
*
* #param path
* the path to the Video
* #return a thumbnail of the video or null if retrieving the thumbnail failed.
*/
public static Bitmap getVidioThumbnail(String path) {
Bitmap bitmap = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
bitmap = ThumbnailUtils.createVideoThumbnail(path, Thumbnails.MICRO_KIND);
if (bitmap != null) {
return bitmap;
}
}
// MediaMetadataRetriever is available on API Level 8 but is hidden until API Level 10
Class<?> clazz = null;
Object instance = null;
try {
clazz = Class.forName("android.media.MediaMetadataRetriever");
instance = clazz.newInstance();
final Method method = clazz.getMethod("setDataSource", String.class);
method.invoke(instance, path);
// The method name changes between API Level 9 and 10.
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD) {
bitmap = (Bitmap) clazz.getMethod("captureFrame").invoke(instance);
} else {
final byte[] data = (byte[]) clazz.getMethod("getEmbeddedPicture").invoke(instance);
if (data != null) {
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
}
if (bitmap == null) {
bitmap = (Bitmap) clazz.getMethod("getFrameAtTime").invoke(instance);
}
}
} catch (Exception e) {
bitmap = null;
} finally {
try {
if (instance != null) {
clazz.getMethod("release").invoke(instance);
}
} catch (final Exception ignored) {
}
}
return bitmap;
}
If you are directly creating thumbnails as follows
Bitmap thumb = ThumbnailUtils.createVideoThumbnail(path,
MediaStore.Images.Thumbnails.MINI_KIND);
Then there is a problem with this method if your are creating thumbnails for large video set(for large number of videos). the application will freeze until all the thumbnails are loaded because all the process are executing in the main thread.
Use SuziLoader
This loader will load the thumbnails for the videos which is locally stored on your filesystem in background.
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/video.mp4";
ImageView mThumbnail = (ImageView) findViewById(R.id.thumbnail);
SuziLoader loader = new SuziLoader(); //Create it for once
loader.with(MainActivity.this) //Context
.load(path) //Video path
.into(mThumbnail) // imageview to load the thumbnail
.type("mini") // mini or micro
.show(); // to show the thumbnail
To get this dependency use the following steps
Step 1. Add the JitPack repository to your build file
Add it in your root build.gradle at the end of repositories:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
Step 2. Add the dependency
dependencies {
compile 'com.github.sushinpv:SuziVideoThumbnailLoader:0.1.0'
}
ADD READ EXTERNAL STORAGE Permission in manifest
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Try something similar to this code snippet:
img.setImageBitmap(ThumbnailUtils.createVideoThumbnail(
Environment.getExternalStorageDirectory().getPath() + "/WhatsApp/Media/WhatsApp Video/"+getItem(position),
MediaStore.Video.Thumbnails.FULL_SCREEN_KIND));
Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] projection = { MediaStore.Video.VideoColumns.DATA };
Cursor c = getContentResolver().query(uri, projection, null, null, null);
int vidsCount = 0;
if (c != null) {
vidsCount = c.getCount();
while (c.moveToNext()) {
String path = c.getString(0);
Bitmap thumb = ThumbnailUtils.createVideoThumbnail(path,
MediaStore.Images.Thumbnails.MINI_KIND);
}
c.close();
}
You can use this method with any Uri:
public static Bitmap getVideoFrame(Uri uri, Context context) {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(context, uri);
return retriever.getFrameAtTime();
}