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.
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'm using following code from here. I want to compress image.
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bmp = BitmapFactory.decodeFile(filePath, options);
int actualHeight = options.outHeight;
int actualWidth = options.outWidth;
After choose image from Camera, Gallery and Photos, i'm getting different type of paths in different devices based on OS type and device model. like:
1) /storage/emulated/0/Android/data/...
2) /raw//storage/emulated/0/mb/1511172993547.jpg
3) /2/1/content://media/external/images/media/11647/ORIGINAL/NONE/486073582
If path is like 1st url, this code is working fine. But if i get other types of images, then BitmapFactory.decodeFile() is giving null.
Is there any way to compress image in all types of devices and OS versions.
UPDATE :
To Open Picker :
Intent pickIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
pickIntent.setType("image/*");
startActivityForResult(pickIntent, 1001);
After choosing image :
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Uri imgUri = Uri.fromFile(new File(data.getData().getPath()));
Bitmap cmpBitmap = ImageUtils.compressUriQuality(OpenWallWeb.this, imgUri);
dlgImageToPost.setImageBitmap(cmpBitmap);
...
}
For compression :
public static Bitmap compressUriQuality(Context mContext, Uri selectedImage) {
InputStream imageStream = null;
Bitmap bmp = null;
try {
imageStream = mContext.getContentResolver().openInputStream(
selectedImage);
bmp = BitmapFactory.decodeStream(imageStream);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 50, stream);
if (imageStream != null)
imageStream.close();
stream.close();
stream = null;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return bmp;
}
Tv 2) /raw//storage/emulated/0/mb/1511172993547.jpg
That is not a path you would get if the user selected pictures from Gallery or Photos. And certainly it is no file system path you could use for .decodeFile(). How did you obtain it?
3) /2/1/content://media/external/images/media/11647/ORIGINAL/NONE/486073582
That is no valid content scheme path. How did you obtain it? And certainly cannot be used for .decodeFile().
i'm getting different type of paths
You will never get such paths if you 'act normal'. So what is it what you are doing? Elementary uri handling wrong?
using following code from here.
That is pretty dirty example code for a big part as you have perceived now.
any way to compress image in all types of devices and OS versions.
Of course. Just use the obtained selected uri directly. Open an InputStream for it and use .decodeStream() instead.
My god.. you are not using the uri directly.
Bitmap cmpBitmap = ImageUtils.compressUriQuality(OpenWallWeb.this, imgUri);
Change to
Bitmap cmpBitmap = ImageUtils.compressUriQuality(OpenWallWeb.this, data.getData());
I had same issue, please add storage permission to your app.
Check this link for more info
Storage permission error in Marshmallow
I have multiple Activities that are supposed to work on one image that is taken through an Intent as described here
https://developer.android.com/training/camera/photobasics.html
I then have a path to my image, which I use to access the photo and manipulate it (changing size, colors)
But when I try to create a Bitmap from the path, it always give Errors like
E/BitmapFactory: Unable to decode stream: java.lang.NullPointerException: Attempt to invoke virtual method 'char[] java.lang.String.toCharArray()' on a null object reference
I have the imagePath saved in a private variable, and pass it in a Bundle betweeen the activities, which works fine the first time. When I pass it the same way to the third activity, the abobe error shows.
Here's a bit of my code to scale the image before putting it in the ImageView:
public class scaleImage {
static Bitmap setPic(ImageView mImageView, String mCurrentPhotoPath) {
// Get the dimensions of the View
int targetW = mImageView.getWidth();
int targetH = mImageView.getHeight();
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
//bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
mImageView.setImageBitmap(bitmap);
return bitmap;
}
}
The function in the first Activity that creates a file that the image is saved to (like in the example):
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.getAbsolutePath();
imageFileName = image.getName();
return image;
}
The second Activity gets the imagePath through a Bundle when called and passes it to the third one the same way like this:
void callPictureScalerActivity() {
Intent intent = new Intent(this, ConvertToGrayscale.class);
Bundle b = new Bundle();
b.putString("imagePath", mCurrentPhotoPath);
intent.putExtras(b);
startActivity(intent);
}
The third Activity tries get a Bitmap from the imagepath which isn't working anymore. (Have to do this not in onCreate since the size of the imageView is not known yet):
public void onWindowFocusChanged(boolean focus) {
super.onWindowFocusChanged(focus);
scaleImage.setPic((ImageView) findViewById(R.id.scalablePicture), photoPath);
}
So I'm wondering, does the file for the image get deleted after calling more then one Activity or is the fault somewhere else? At this point I'm clueless at what other way I should access the Image.
Edit: The error above appears in the line where I'm trying to get the Bitmap from the path:
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
so it's an error that occurs in the decodeFile function, which I can't look into.
Also the third Activity is called when a Button is pressed in the second, calling the callPictureScalerActivity function.
The photo is saved with following function:
void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
Log.w("Error", "Error creating the image file");
}
// Continue only if the File was successfully created
if (photoFile != null) {
photoURI = FileProvider.getUriForFile(this,
"com.example.android.fileprovider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
I know the photo is saved since I looked up the path from mCurrentPhotoPath.
How do i export a subview of a fragment from another fragment as Png?
Context
I'am creating an app, which allows the user to create a personalized CV. The user can submit informations regarding his job-experience and skills. As a result the user is able to export his results as a png and save it to the device. My question aims at the export-functionallity of the application.
What i got so far
I tried to combine several answers from the site to get a result, but unfortunately the code that i have does not work so far.
public void export(Context context) throws FileNotFoundException {
View exportView = getLayoutInflater(getArguments()).inflate(R.layout.fragment_form, null, false);
RelativeLayout subView = (RelativeLayout) exportView.findViewById(R.id.fragment_form_container_root);
try {
subView.setDrawingCacheEnabled(true);
subView.measure(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
Bitmap b = Bitmap.createBitmap(subView.getDrawingCache(), 0, 0, subView.getMeasuredWidth(), subView.getMeasuredHeight());
File cachePath = new File(context.getCacheDir(), "images");
cachePath.mkdirs(); // don't forget to make the directory
FileOutputStream stream = new FileOutputStream(cachePath + "/image.png"); // overwrites this image every time
b.compress(Bitmap.CompressFormat.PNG, 100, stream);
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
File imagePath = new File(context.getCacheDir(), "images");
File newFile = new File(imagePath, "image.png");
Uri contentUri = FileProvider.getUriForFile(context, "com.example.lukas.masterthesis.fileprovider", newFile);
if (contentUri != null) {
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // temp permission for receiving app to read this file
shareIntent.setDataAndType(contentUri, getActivity().getContentResolver().getType(contentUri));
shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
startActivity(Intent.createChooser(shareIntent, "Choose an app"));
}
}
The export functionallity is called within Fragment A after a click event. I'am trying to get the wanted subview of Fragment B (wich seems to work), but creating the Bitmap always results in a null Object. Therefore the procedure fails.
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.graphics.Bitmap.compress(android.graphics.Bitmap$CompressFormat, int, java.io.OutputStream)' on a null
Honestly im not even sure this is the proper way to do such a thing, since I haven't found a Best-Practice solution for what im trying. If not, does anybody know a better way to do this?
If its an "ok" solution, does anybody know how to get my code to work or has some suggestions that can point me into the right direction?
Thx in advance.
try using
try using bitmap = Bitmap.createBitmap(subView.getDrawingCache());
instead of
Bitmap b = subView.getDrawingCache();
Just wanted to provide an answer.
I was basically on the right track. Ended up splitting my View into smaller parts since may drawing cache was to small to handle the whole thing at once. It might help somebody who has encountered a similar problem.
First part of code draws each part into the resulting bitmap. Second part allows the user to exports the it (for example to dropbox).
So here you go
public void export() throws FileNotFoundException {
View exportView = rootView.findViewById(R.id.fragment_form_container_root);
View view_title = rootView.findViewById(R.id.fragment_form_container_title);
View view_basicInformation = rootView.findViewById(R.id.fragment_form_container_basicinformation);
View view_experience_skill = rootView.findViewById(R.id.fragment_form_container_experience_skill);
View view_connect = rootView.findViewById(R.id.fragment_form_container_connect);
View view_footer = rootView.findViewById(R.id.fragment_form_container_footer);
try {
view_title.setDrawingCacheEnabled(true);
view_title.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
Bitmap b0 = Bitmap.createBitmap(view_title.getDrawingCache());
view_title.setDrawingCacheEnabled(false);
view_basicInformation.setDrawingCacheEnabled(true);
view_basicInformation.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
Bitmap b1 = Bitmap.createBitmap(view_basicInformation.getDrawingCache());
view_basicInformation.setDrawingCacheEnabled(false);
view_experience_skill.setDrawingCacheEnabled(true);
view_experience_skill.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
Bitmap b2 = Bitmap.createBitmap(view_experience_skill.getDrawingCache());
view_experience_skill.setDrawingCacheEnabled(false);
view_connect.setDrawingCacheEnabled(true);
view_connect.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
Bitmap b3 = Bitmap.createBitmap(view_connect.getDrawingCache());
view_connect.setDrawingCacheEnabled(false);
view_footer.setDrawingCacheEnabled(true);
view_footer.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
Bitmap b4 = Bitmap.createBitmap(view_footer.getDrawingCache());
view_footer.setDrawingCacheEnabled(false);
Bitmap result = Bitmap.createBitmap(exportView.getWidth(), exportView.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
//canvas.setDensity(300);
Paint paint = new Paint();
paint.setFlags(Paint.FILTER_BITMAP_FLAG);
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
canvas.drawBitmap(b0, 0, 0, paint);
canvas.drawBitmap(b1, 0, b0.getHeight(), paint);
canvas.drawBitmap(b2, 0, b0.getHeight() + b1.getHeight(), paint);
canvas.drawBitmap(b3, 0, b0.getHeight() + b1.getHeight() + b2.getHeight(), paint);
canvas.drawBitmap(b4, 0, b0.getHeight() + b1.getHeight() + b2.getHeight() + b3.getHeight(), paint);
File cachePath = new File(string_CachePath, "images"); // -> string_CachePath == context.getCacheDir();
cachePath.mkdirs(); // don't forget to make the directory
FileOutputStream stream = new FileOutputStream(cachePath + "/image.png"); // overwrites this image every time
result.compress(Bitmap.CompressFormat.PNG, 100, stream);
stream.close();
File newFile = new File(cachePath.getPath(), "image.png");
Uri contentUri = FileProvider.getUriForFile(getActivity(), "com.example.lukas.masterthesis.fileprovider", newFile);
if (contentUri != null) {
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // temp permission for receiving app to read this file
shareIntent.setDataAndType(contentUri, getActivity().getContentResolver().getType(contentUri));
shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
startActivity(Intent.createChooser(shareIntent, "Choose an app"));
}
} catch (Exception e) {
e.printStackTrace();
}
}
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