ImageView, thumbnail and performances - android

I have an activity in which I have an EditText, an ImageButton to grab an image, and an ImageView.
The ImageView is empty, but I can add a src via Intent.ACTION_GET_CONTENT
The EditText was very slow if I had an image too, so I'm using thumbnails now:
Bitmap thumbImage = ThumbnailUtils.extractThumbnail(
BitmapFactory.decodeFile(imageFile.getAbsolutePath()),
uploadedImageView.getWidth(), uploadedImageView.getWidth());
uploadedImageView.setImageBitmap(thumbImage);
And all works fine now.
The problem is when I share an image with this activity from another app.
The EditText is slow as before the thumbnails.
This is how I'm doing it now:
in my onCreate method:
if (Intent.ACTION_SEND.equals(action) && type != null) {
if ("text/plain".equals(type)) {
...
} else if (type.startsWith("image/")) {
ViewTreeObserver viewTree = uploadedImageView.getViewTreeObserver();
viewTree.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
Uri selectedImageUri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
imageFile = new File(FileUtils.getPath(MyActivity.this, selectedImageUri));
Bitmap thumbImage = ThumbnailUtils.extractThumbnail(
BitmapFactory.decodeFile(imageFile.getAbsolutePath()),uploadedImageView.getWidth(),uploadedImageView.getWidth());
uploadedImageView.setImageBitmap(thumbImage);
return true;
}
});
}
}
What am I missing?

Related

Unable to get bitmap from the following uri : Uri imageUri = data.getClipData().getItemAt(i).getUri()

Project: Open Gallery From a Button in One Activity, Select The Images from there and Display it on the initial Activity screen.
Solution: I know that the solution for the problem above is given but it only deals with the multiple selection of images part and getting the data of the images.
My Problem:
From here, i am unable to use the uri data to convert to bitmap and hence store in my image view. I even tried
ImageView imageView = findViewById(R.id.imageView);
Bitmap bitmap = BitmapFactory.decodeFile(imageUri.getPath()) ;
imageView.setImageBitmap(bitmap); but the image doesn't show
How to get dynamic number of image views?
I want the image views on my activity.xml to be dynamic,i.e it changes its number depending on the number of selections
for eg: if the user selects 5 images on opening the gallery app, then i want to be able to display the 4 images on the initial Activity screen. If 6 images selected then 6, if 2 then 2. It should change the image view count depending on the number of selections as I dont want to hardcode the number of image views in the xml file.
How i am trying to get the bitmap is by
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
I am getting Unhandled exceptions error , java.io.FileNotFoundException for the getBitmap part below
I have attached my code below
public void onClick(View view){
Intent intent = new Intent();
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,"Select Picture"), PICK_IMAGE_MULTIPLE);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == PICK_IMAGE_MULTIPLE) {
if(resultCode == Activity.RESULT_OK) {
if(data.getClipData() != null) {
int count = data.getClipData().getItemCount(); //evaluate the count before the for loop --- otherwise, the count is evaluated every loop.
for (int i = 0; i < count; i++){
Uri imageUri = data.getClipData().getItemAt(i).getUri();
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(),imageUri) ; //MAIN ERROR OVER HERE
//OR
ImageView imageView = findViewById(R.id.imageView);
Bitmap bitmap = BitmapFactory.decodeFile(imageUri.getPath()) ;
imageView.setImageBitmap(bitmap); //STILL NOT WORKING
}
}
} else if(data.getData() != null) {
String imagePath = data.getData().getPath();
ImageView imageView = findViewById(R.id.imageView); //WANT TO AVOID THIS AND MAKE IMAGE VIEW NUMBER AS DYNAMIC
Bitmap bmImg = BitmapFactory.decodeFile(imagePath);
imageView.setImageBitmap(bmImg);
}
}
}
InputStream iStream = getContentResolver().openInputStream(selectedImageUri);
byte[] inputData = Utils.getBytes(iStream);
dbHelper.insertImage(inputData);
http://www.coderzheaven.com/2012/12/23/store-image-android-sqlite-retrieve-it/

Loading BitmapDrawable in Fresco

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

Xamarin.Android - "resolveURI failed on bad bitmap URI" after parsing encoded string

I am trying to display an image from a local URI when this activity begins.
The user selects an image, triggering the OnActivityResult() method. When I first obtain the URI, it displays the image with no problem:
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
if (requestCode == IMG_REQUEST_CODE && resultCode == Result.Ok)
{
Android.Net.Uri imageUri = null;
if (data != null)
{
imageUri = data.Data;
userPreferences.BackgroundImageURI = imageUri.ToString();
imgView.SetImageURI(imageUri);
imgView.Visibility = ViewStates.Visible;
}
}
}
As you can see, I am storing the URI as an encoded string in userPreferences. This is saved to the device, and can be loaded with no issue. In this case the string is content://com.android.providers.media.documents/document/image%3A38, and it is identical when loaded from memory (using Shared Preferences).
Here is my code for loading the encoded URI string, parsing the string to create a URI, and then setting URI of imgView to display that image.
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Preferences);
userPreferences = Helpers.LoadUserPreferences(this, new Shared.Model.UserPreferences());
imgView = FindViewById<ImageView>(Resource.Id.imgView);
if (!string.IsNullOrWhiteSpace(userPreferences.BackgroundImageURI))
{
var imgURI = Android.Net.Uri.Parse(userPreferences.BackgroundImageURI);
imgView.SetImageURI(imgURI);
imgView.Visibility = ViewStates.Visible;
}
else
{
imgView.Visibility = ViewStates.Invisible;
}
}
When it gets to the SetView(imgUri) line, I receive this output: resolveUri failed on bad bitmap uri: content://com.android.providers.media.documents/document/image%3A38
I have even tried hard-coding the URI to no avail. The main frustration is that the code is identical, just running in two different scenarios. Is it possible that it has to do with the Activity lifecycle? Or have I missed something bigger?
Try this:
if (!string.IsNullOrWhiteSpace(userPreferences.BackgroundImageURI))
{
var imgURI = Android.Net.Uri.Parse(userPreferences.BackgroundImageURI);
var input = Activity.ContentResolver.OpenInputStream(imgURI);
imgView.SetImageBitmap(BitmapFactory.DecodeStream(input));
imgView.Visibility = ViewStates.Visible;
}
else
{
imgView.Visibility = ViewStates.Invisible;
}
As alternative I have a class that get the real path for the image from a URI. It could be great if you want to give that path to a CropActivity for example.
You can download the class from here.
And use it like this:
if (!string.IsNullOrWhiteSpace(userPreferences.BackgroundImageURI))
{
var imgURI = Android.Net.Uri.Parse(userPreferences.BackgroundImageURI);
imgView.SetImageURI (Uri.Parse(PathUtils.PathUtils.GetPath(Activity, imgURI)));
imgView.Visibility = ViewStates.Visible;
}
else
{
imgView.Visibility = ViewStates.Invisible;
}

Glide sharing transformed GIF

I'd like to share GIFs I loaded with Glide but i can't find a way to do it.
I tried to share the GifDrawable data as an array of byte but when i try to share, the GIF doesn't appear.
Here's the code I wrote :
Glide.with(getActivity())
.load(to_add.mMeme.getmUrl())
.asGif()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.transformFrame(new TextTransformation(getContext(), to_add.mMeme.getmText()))
.listener(new RequestListener<String, GifDrawable>() {
#Override
public boolean onException(Exception e, String s, Target<GifDrawable> target, boolean b) {
return false;
}
#Override
public boolean onResourceReady(GifDrawable gifDrawable, String s, Target<GifDrawable> target, boolean b, boolean b1) {
to_add.mDrawable = gifDrawable;
to_add.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Meme to_share = null;
for (Meme meme : mViewList) {
if (meme.mView.equals(v)) {
to_share = meme;
break;
}
}
if (to_share != null) {
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.setType("image/*");
shareIntent.putExtra(Intent.EXTRA_STREAM, to_share.mDrawable.toString());
startActivity(Intent.createChooser(shareIntent, "Share"));
}
}
});
return false;
}
})
.into((ImageView) to_add.mView.findViewById(R.id.memeImageView));
Here is my Meme class used in the previous code :
public static class Meme {
public Meme(StorageManager.Meme meme, View view) {
mMeme = meme;
mView = view;
}
StorageManager.Meme mMeme;
View mView;
GifDrawable mDrawable;
}
mViewList is a List of Meme:
List<Meme> mViewList;
And to_add variable is the Meme containing the GIF i'm trying to share :
final Meme to_add = new Meme(data, getActivity().getLayoutInflater().inflate(R.layout.meme_layout, null));
I miss understood how to use share intents.
Sharing with intents
To answer my question, sharing a file with a Share intent require the file to be accessible on drive.
That's why I had to write it in the cache memory using :
File file = new File(mContext.getExternalCacheDir(), myMeme.getmFileName());
file.setReadable(true);
Don't write your file in your App cache dir, otherwise file will not be accessible by other applications
mContext.getCacheDir()
Then I could easily share my File using Uris :
Uri uri = Uri.fromFile(file);
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.setType("image/gif");
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(shareIntent, "Share with"));
Sharing works perfectly now.
Concerning Glide GIF
I wasn't able to get Glide transformed GIF.
To add my text to the GIF, i splitted all frames composing the GIF and writted down the text.
Split GIF into frames using Glide
GifDecoder decoder = mGif.getmDrawable().getDecoder();
Bitmap frame;
Log.d("GIF GENERATION", "STARTED FRAME SPLIT");
int max = mGif.getmDrawable().getFrameCount();
int current = 0;
decoder.advance();
while (current < max && (frame = decoder.getNextFrame()) != null) {
Log.d("GIF GENERATION", "ADDED FRAME");
// Here you get your GIF frame per frame
decoder.advance();
current++;
}
Log.d("GIF GENERATION", "ENDED FRAME SPLIT");
Adding text to every frame
To write down my text on every frame, I used this class that works perfectly for single line text : http://www.skoumal.net/en/android-how-draw-text-bitmap/
Creating new GIF with frames
To do that, I used another class called GifCreator. It can be found here : https://github.com/nbadal/android-gif-encoder
Final Result
Here's how the actual code is :
GifDecoder decoder = mGif.getmDrawable().getDecoder();
GifCreator creator = new GifCreator();
Bitmap frame;
creator.start(mOs);
creator.setSize(mGif.getmDrawable().getDecoder().getWidth(), mGif.getmDrawable().getDecoder().getHeight());
creator.setRepeat(0);
creator.setQuality(15);
Log.d("GIF GENERATION", "STARTED FRAME SPLIT");
int max = mGif.getmDrawable().getFrameCount();
int current = 0;
decoder.advance();
while (current < max && (frame = decoder.getNextFrame()) != null) {
Log.d("GIF GENERATION", "ADDED FRAME");
creator.addFrame(TextTransformation.drawTextToBitmap(mContext, temp, mText));
creator.setDelay(decoder.getNextDelay());
decoder.advance();
current++;
}
Log.d("GIF GENERATION", "ENDED FRAME SPLIT");
creator.finish();

Share image with ShareActionProvider from Picasso

i spand few hours to find this solution...
so i decided to share this informatiom, maybe some one itwill helpful :)
The first way, shown below, takes the bitmap from the view and loads it into a file.
// Get access to ImageView
ImageView ivImage = (ImageView) findViewById(R.id.ivResult);
// Fire async request to load image
Picasso.with(context).load(imageUrl).into(ivImage);
and then later assuming after the image has completed loading, this is how you can trigger a share:
// Can be triggered by a view event such as a button press
public void onShareItem(View v) {
// Get access to bitmap image from view
ImageView ivImage = (ImageView) findViewById(R.id.ivResult);
// Get access to the URI for the bitmap
Uri bmpUri = getLocalBitmapUri(ivImage);
if (bmpUri != null) {
// Construct a ShareIntent with link to image
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, bmpUri);
shareIntent.setType("image/*");
// Launch sharing dialog for image
startActivity(Intent.createChooser(shareIntent, "Share Image"));
} else {
// ...sharing failed, handle error
}
}
// Returns the URI path to the Bitmap displayed in specified ImageView
public Uri getLocalBitmapUri(ImageView imageView) {
// Extract Bitmap from ImageView drawable
Drawable drawable = imageView.getDrawable();
Bitmap bmp = null;
if (drawable instanceof BitmapDrawable){
bmp = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
} else {
return null;
}
// Store image to default external storage directory
Uri bmpUri = null;
try {
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS), "share_image_" + System.currentTimeMillis() + ".png");
file.getParentFile().mkdirs();
FileOutputStream out = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.PNG, 90, out);
out.close();
bmpUri = Uri.fromFile(file);
} catch (IOException e) {
e.printStackTrace();
}
return bmpUri;
}
Make sure to add the appropriate permissions to your AndroidManifest.xml:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
The second way to share an Image does not require you to write the image into a file. This code can safely be executed on the UI thread. The approach was suggested on this webpage http://www.nurne.com/2012/07/android-how-to-attach-image-file-from.html .
ImageView siv = (ImageView) findViewById(R.id.ivResult);
Drawable mDrawable = siv.getDrawable();
Bitmap mBitmap = ((BitmapDrawable)mDrawable).getBitmap();
String path = Images.Media.insertImage(getContentResolver(),
mBitmap, "Image Description", null);
Uri uri = Uri.parse(path);
return uri;
You get the Drawable from the ImageView. You get the Bitmap from the Drawable. Put that bitmap into the Media image store. That gives you a path which can be used instead of a file path or URL. Note the original webpage had an additional problem with immutable bitmaps, solved by drawing the bitmap into a canvas (never shown on screen). See linked page above for details.

Categories

Resources