Edit: Solved.
I'm trying to upload an image to parse that has been selected from the phone's gallery. However I cannot seem to locate the imageview as it returns null. I think this page: Saving images to Parse has a similar question to what I'm asking but there is no answer to it.
Fragment class:
public void onClick(View view) {
img = (ImageView) rootView.findViewById(R.id.imageView1);
// Locate the image (error is here)
Bitmap bitmap = BitmapFactory.decodeResource(getActivity().getResources(), img);
// Convert it to byte
ByteArrayOutputStream stream = new ByteArrayOutputStream();
// Compress image to lower quality scale 1 - 100
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] image = stream.toByteArray();
//byte[] image = img.getContext().toString().getBytes();
//Bitmap bitmap = BitmapFactory.decodeFile(img);
ParseFile file = new ParseFile("image.jpg", image);
file.saveInBackground();
ParseObject familyTree = new ParseObject("FamilyTree");
familyTree.put("image", file);
familyTree.put("name", etName.getText().toString());
familyTree.put("relation", etRelation.getText().toString());
familyTree.saveInBackground();
Toast.makeText(FamilyTreeFragment2.this.getActivity(), "Saved.", Toast.LENGTH_SHORT).show();
// getFragmentManager().beginTransaction().replace(R.id.container, new FamilyTreeFragment2()).addToBackStack(null).commit();
}
Any help is appreciated. Thank you.
I've managed to find the solution.
Replaced
Bitmap bitmap = BitmapFactory.decodeResource(getActivity().getResources(), img);
with
Bitmap bitmap = ((BitmapDrawable) img.getDrawable()).getBitmap();
Related
Guys I am facing this issue since 2 days straight. I want to pick an image from gallery and convert it to Base64 method. I have tried Picasso but my imageview is large. Can you please help me. I tried everything but out of memory is too much for me when converting it to bitmap and then to base64.
BitmapDrawable drawable = (BitmapDrawable) ProfilePic.getDrawable();
yourSelectedIBitmapDrawable drawable = (BitmapDrawable) ProfilePic.getDrawable();
yourSelectedImage = drawable.getBitmap();mage = drawable.getBitmap();
Code which is converting this bitmap to Base64. Is there any possibility of skipping the bitmap and directly converting to Base64
private String encodeToBase64(Bitmap image) {
Bitmap immagex = image;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
immagex.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] b = baos.toByteArray();
String imageEncoded = Base64.encodeToString(b,Base64.DEFAULT);
//Log.e("LOOK", imageEncoded);
return imageEncoded;
}
Profile Pic is name of Imageview.
EDIT: So guyz one of the ways is to use the large heap, but Google says you should not use that unless absolutely necessary. The other one that worked for me is the accepted answer. Now I came up with my own solution. In theory, I am using Picasso to load the image into image view. So what if I can extract the image from the ImageView. Not from URI or path, but from Imageview. This way you have an image which is already reduced by Picasso. Picasso provides Callback to for Success or failure. So on Success, you can access the cache memory of ImageView and extract the Bit map out of it.
I will post the code as an answer shortly. I tried it and even an image of 35Mb originally can be converted to bitmap without Out of memory exception.
So here is my ans: https://stackoverflow.com/a/52125006/6022584
You can try to read the bitmap data with a buffer. Something like that :
private String encodeToBase64(Bitmap image) {
// get an InputStream
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(CompressFormat.PNG, 0, baos);
byte[] bitmapdata = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(bitmapdata);
// prepare a buffer to read the inputStream
byte[] buffer = new byte[10 * ONE_KIO]; // ONE_KIO = 1024
int bytesRead;
// prepare the stream to encode in Base64
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Base64OutputStream base64OutputStream = new Base64OutputStream(outputStream, Base64.DEFAULT);
// read the inputStream
while ((bytesRead = bais.read(buffer)) != -1) {
base64OutputStream.write(buffer, 0, bytesRead);
}
base64OutputStream.close();
// get the encoded result string
return outputStream.toString();
}
This is my Code that worked. New Issue is the name of Activity for me
if (requestCode == PICK_IMAGE) {
if(resultCode == RESULT_OK){
//isImageFromGallery = true;
//isImageSelected = true;
ImagePath = data.getData();
Picasso.get()
.load(ImagePath)
.resize(1024,1024)
.onlyScaleDown()
.centerCrop()
.into(picture, new Callback(){
#Override
public void onSuccess() {
BitmapDrawable drawable = (BitmapDrawable) picture.getDrawable();
yourSelectedImage = drawable.getBitmap();
//isImageSelected = true;
Log.d("FileSize",Formatter.formatFileSize(NewIssue.this,
yourSelectedImage.getByteCount()));
}
#Override
public void onError(Exception e) {
Toast.makeText(NewIssue.this, "Could Not Load Image", Toast.LENGTH_SHORT).show();
}
});
}
}
My program starts with a Base64 string which i turn into a byte array
byte[] bytes = Convert.FromBase64String(imageBase64);
then i turn the byte array into a Bitmap
Bitmap bitmap = BitmapFactory.DecodeByteArray(bytes, 0, bytes.Length);
then i try to use the Emgucv Image<> Bitmap constructor
image = new Image<Gray, byte>(bitmap);
but i get this error System.NullReferenceException: Object reference not set to an instance of an object.
I've debugged and can confirm that the bitmap is being created successfully and has a byte count, width, height but still gives me this error. Here's the full method I'm using to go from Base64 to Emgucv UMat.
private async void SetBase64Pattern()
{
detection.Clear();
foreach (Assets asset in lstAssets)
{
if (asset.Used == 1)
{
detection.Add(0);
UMat imagePattern = new UMat();
VectorOfKeyPoint keyPoint = new VectorOfKeyPoint();
Mat desc = new Mat();
Image<Gray, byte> image;
string imageBase64 = asset.AssetImage;
imageBase64 = imageBase64.Split(',')[1];
byte[] bytes = Convert.FromBase64String(imageBase64);
#if __IOS__
NSData data = NSData.FromArray(bytes);
UIImage uiImage = UIImage.LoadFromData(data);
image = new Image<Gray, byte>(uiImage);
#elif __ANDROID__
//IImageSourceHandler handler = new StreamImagesourceHandler();
//Bitmap bitmap = await handler.LoadImageAsync(ImageSource.FromStream(() => new MemoryStream(bytes)), Forms.Context);
//image = new Image<Gray, byte>(bitmap);
Bitmap bitmap = BitmapFactory.DecodeByteArray(bytes, 0, bytes.Length);
image = new Image<Gray, byte>(bitmap);
#endif
imagePattern = image.ToUMat();
featureDetector.DetectAndCompute(imagePattern, null, keyPoint, desc, false);
triggers.Add(imagePattern);
triggersKPS.Add(keyPoint);
triggersDescs.Add(desc);
}
}
}
Thanks for looking!
EDIT
Just wanted to mention that the iOS code in fact works and that's what makes this all the more confusing on why the Android code does not work.
Answer to my own question.
The images were gif images before being encoded to Base64. After changing the gif to a jpeg before being encoded the process now works.
I am having trouble trying to upload the image on server using Parse API. I can read from the server and update data on any column except uploading image.
I have picked the image from the device and displayed in imageView..
// Move to first row
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String imgDecodableString = cursor.getString(columnIndex);
cursor.close();
ImageView imageView = (ImageView) findViewById(R.id.imageView);
Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
// Set the Image in ImageView after decoding the String
imageView.setImageURI(selectedImage);
Picasso.with(this).load(selectedImage).fit().centerCrop().into(imageView);
//resizing the image part 2
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//to Compress the image
//Quality Accepts 0 - 100
//0 = MAX Compression (Least Quality which is suitable for Small images)
//100 = Least Compression (MAX Quality which is suitable for Big images)
bitmap.compress(Bitmap.CompressFormat.PNG, 0, baos);
//uploading the image to server
byte[] imageInByte = imgDecodableString.getBytes();
final ParseFile bitmapFile = new ParseFile(imageInByte);
bitmapFile.saveInBackground();
//current user is already logged in.
ParseObject userDisplayImage = new ParseObject("UserDisplayImage");
userDisplayImage.put("photo", bitmapFile);
userDisplayImage.saveInBackground();
In your code :
final ParseFile bitmapFile = new ParseFile(imageInByte);
bitmapFile.saveInBackground();
the bitmapFile is uploaded in a background thread, hence by the time you reach to the next statement :
ParseObject userDisplayImage = new ParseObject("UserDisplayImage");
userDisplayImage.put("photo", bitmapFile);
userDisplayImage.saveInBackground (...);
The bitmapFile is not completely uploaded and hence it userDisaplyImage is not able to make a pointer towards it.
You can try the following to fix it :
final ParseFile bitmapFile = new ParseFile(imageInByte);
bitmapFile.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if(e==null){
Log.i("hello"," photo saved ");
ParseObject userDisplayImage = new ParseObject("UserDisplayImage");
userDisplayImage.put("photo", bitmapFile);
userDisplayImage.saveInBackground ();
} else {
e.printStackTrace();
Log.i("Error", e + "photo not saved");
}
}
});
I am trying to use parse.com database to upload file and syntax needs me to use byte []. I will write syntax below:
byte[] data = "Working at Parse is great!".getBytes();
ParseFile file = new ParseFile("resume.png", data);
file.saveInBackground();
ParseObject jobApplication = new ParseObject("JobApplication");
jobApplication.put("applicantResumeFile", file);
jobApplication.saveInBackground();
I need to know how to use the first instruction to get ImageView Data in byte[] and upload it.
#wisejoy I have an implementation but I think its a little bit different... hope it can help you... cheers!!
myBitmap = (Bitmap) data.getExtras().get("data");//here I set an image taken by the camera
imageView.setImageBitmap(myBitmap);//I set it into an image view
imageView.buildDrawingCache();
ByteArrayOutputStream baos = new ByteArrayOutputStream();//and then I convert that image into a byteArray
myBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] b = baos.toByteArray();
encondedImage = android.util.Base64.encodeToString(b, Base64.DEFAULT);
Log.e(TAG, "" + txt);
I hava a Bitmap variable named bmp in Activity1 , and I want to send the bitmap to Activity2
Following is the code I use to pass it with the intent.
Intent in1 = new Intent(this, Activity2.class);
in1.putExtra("image",bmp);
startActivity(in1);
And in Activity2 I try to access the bitmap using the following code
Bundle ex = getIntent().getExtras();
Bitmap bmp2 = ex.getParceable("image");
ImageView result = (ImageView)findViewById(R.Id.imageView1);
result.setImageBitmap(bmp);
The application runs without an exception but it does not give the expected result
Convert it to a Byte array before you add it to the intent, send it out, and decode.
//Convert to byte array
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
Intent in1 = new Intent(this, Activity2.class);
in1.putExtra("image",byteArray);
Then in Activity 2:
byte[] byteArray = getIntent().getByteArrayExtra("image");
Bitmap bmp = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
edit
Thought I should update this with best practice:
In your first activity, you should save the Bitmap to disk then load it up in the next activity. Make sure to recycle your bitmap in the first activity to prime it for garbage collection:
Activity 1:
try {
//Write file
String filename = "bitmap.png";
FileOutputStream stream = this.openFileOutput(filename, Context.MODE_PRIVATE);
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
//Cleanup
stream.close();
bmp.recycle();
//Pop intent
Intent in1 = new Intent(this, Activity2.class);
in1.putExtra("image", filename);
startActivity(in1);
} catch (Exception e) {
e.printStackTrace();
}
In Activity 2, load up the bitmap:
Bitmap bmp = null;
String filename = getIntent().getStringExtra("image");
try {
FileInputStream is = this.openFileInput(filename);
bmp = BitmapFactory.decodeStream(is);
is.close();
} catch (Exception e) {
e.printStackTrace();
}
Sometimes, the bitmap might be too large for encode&decode or pass as a byte array in the intent. This can cause either OOM or a bad UI experience.
I suggest to consider putting the bitmap into a static variable of the new activity (the one that uses it) which will carefully be null when you no longer need it (meaning in onDestroy but only if "isChangingConfigurations" returns false).
Simply we can pass only Uri of the Bitmap instead of passing Bitmap object. If Bitmap object is Big, that will cause memory issue.
FirstActivity.
intent.putExtra("uri", Uri);
From SecondActivity we get back bitmap.
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(),Uri.parse(uri));
Kotlin Code for send Bitmap to another activity by intent:
1- in First Activity :
val i = Intent(this#Act1, Act2::class.java)
var bStream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.PNG, 50, bStream)
val byteArray = bStream.toByteArray()
i.putExtra("image", byteArray )
startActivity(i)
2- In Activity two (Read the bitmap image) :
var bitmap : Bitmap? =null
if (intent.hasExtra("image")){
//convert to bitmap
val byteArray = intent.getByteArrayExtra("image")
bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
}
3- if you need to set it as background for a view, like ConstraintLayout or... :
if (bitmap != null) {
//Convert bitmap to BitmapDrawable
var bitmapDrawable = BitmapDrawable( resources , bitmap)
root_constraintLayout.backgroundDrawable = bitmapDrawable
}
create a singleton class for storing bitmap data
public final class BitmapData {
private static final BitmapData bitmapData = new BitmapData();
private Bitmap bitmap;
private BitmapData() {
}
public static BitmapData getInstance() {
return bitmapData;
}
public Bitmap getBitmap() {
return bitmap;
}
public void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
}
in first activity you can set like this.
BitmapData.getInstance().setBitmap(bitmap);
and in second activity
Bitmap bitmap = BitmapData.getInstance().getBitmap();
Note: check null value
We can also solve this without passing data through intent. Just store the image in the memory and in the next Activity just load the image from that location, which can also avoid app crash from passing large bitmap data.
Note: You need not even pass the location path to the intent, remember the path and use it.
I would like to also post a best practices answer for those looking to do this (but may be asking the wrong question).
Instead of passing a bitmap around (which I presume you downloaded from the network, otherwise, you would already have a file reference to it), I recommend using an image loader such as Universal Image Loader to download an image into an ImageView. You can configure it to then cache the image to disk:
DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisk(true)
.considerExifParams(true)
.bitmapConfig(Bitmap.Config.RGB_565)
.build();
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
.defaultDisplayImageOptions(defaultOptions)
.build();
ImageLoader.getInstance().init(config);
Now, just pass the image URL in your intent and use the UIL to load the image. In your newly created activity for example, the image will load instantly because it is loading from the cache - even if your image URL has expired since the download.
Bundle b = new Bundle();
b.putSerializable("Image", Bitmap);
mIntent.putExtras(b);
startActivity(mIntent);