Send image to server from gallery android bitmap - android

I tried to send an image to server from gallery, I compressed it with Base64.
I started an activity for gallery:
private void startGalleryActivity() {
Intent intent = new Intent();
intent.setType("image/*");
String selectPicture = getResources().getString(R.string.select_picture);
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, GALLERY);
}
I received the result in onActivityResult:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == GALLERY && resultCode == MainActivity.RESULT_OK) {
Uri pickedImage = data.getData();
// Let's read picked image path using content resolver
String[] filePath = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(pickedImage, filePath, null, null, null);
cursor.moveToFirst();
String imagePath = cursor.getString(cursor.getColumnIndex(filePath[0]));
// Now we need to set the GUI ImageView data with data read from the picked file.
imageView.setImageBitmap(BitmapFactory.decodeFile(imagePath));
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
bitmap = BitmapFactory.decodeFile(imagePath, options);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream .toByteArray();
String encoded = Base64.encodeToString(byteArray, Base64.DEFAULT);
Server s = new Server("new");
s.send(encoded);
// At the end remember to close the cursor or you will end with the RuntimeException!
cursor.close();
}
super.onActivityResult(requestCode, resultCode, data);
When I send the image to serve the size of it is 4 times higher. If I write the image after I read it, this is write with double size. Why do I have this overhead?

Why do I have this overhead?
In addition to the Base64 overhead itself, you are re-encoding the image as a PNG. If the image started as something else, like a JPEG, a PNG version of that image may be substantially larger.
Also, please delete the four lines preceded by // Let's read picked image path using content resolver. First, that code will fail on hundreds of millions of Android devices, because a Uri is not a file, and you cannot assume that you can get a local filesystem path for that data. Second, you do not need it, as BitmapFactory has a decodeStream() method that you can use with getContentResolver().openInputStream(pickedImage).
In addition, please do not call decode...() on BitmapFactory twice. Load the bitmap once. Use the bitmap both for the ImageView and for your uploading.

Calling compress on a PNG will not make your file smaller as it is already compressed. Converting a binary file to a text stream
will really make it big. To avoid less overhead by converting the PNG file
to text file, just send the file as is, as a byte array. And add the file length
in the header. You can use DataOutputStream to do this.
byte[] byteArray = byteArrayOutputStream .toByteArray();
ByteArrayOutputStream btOS = new ByteArrayOutputStream();
DataOutputStream dataOS = new DataOutputStreamEx(btOS);
dataOS.writeInt(byteArray.length); // length of file
dataOS.write(byteArray); // actual file
dataOS.write(0); // end of field
dataOS.close()
I don't know what you are using in the backend, but you can just read
the first 4 bytes of what you will receive and that will be the length
of you file. And use that length to read the entire file.

It will be approximately 37% larger:
Very roughly, the final size of Base64-encoded binary data is equal to
1.37 times the original data size
Source: http://en.wikipedia.org/wiki/Base64

You are using Bitmap and BitmapFactory to convert a small jpg file to a big png file. Why aren't you sending the jpg directly? So do NOT use Bitmap and BitmapFactory to begin with. You end up else with something that was not your file.

Related

BitmapFactory.decodeFile() returns null in some devices

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

Uploading image using Dropbox API, Android

After capturing an image, I'm unsure of how to upload the bitmap as a file. I get the bitmap this way:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == CAM_REQUEST_CODE){
if(resultCode == RESULT_OK){
final Bitmap image = (Bitmap)data.getExtras().get("data");
}
}
}
Using Dropbox API, a file is uploaded this way:
File file = new File("working-draft.txt");
FileInputStream inputStream = new FileInputStream(file);
Entry response = mDBApi.putFile("/magnum-opus.txt", inputStream,
file.length(), null, null);
Log.i("DbExampleLog", "The uploaded file's rev is: " + response.rev);
Any help on this is greatly appreciated.
Here's one way you could do it:
Create a ByteArrayOutputStream
Call Bitmap.compress() to write the JPEG/PNG bytes to outputstream
Create a ByteArrayInputStream from the byte array you just output
Use that input stream for your putFile() method
Use the array size for your file length
I would be cautious about memory, though. It it was me, I'd try to find a way to return the bitmap source in the activity result instead of the actual bitmap.

Uploading image taken from gallery app (Quality issue)

Using Android's gallery app to select a photo to upload with httppost later. The photo gets uploaded but it's very low quality and size. I have been reading about setting the Bitmap.CompressFormat.PNG will make it lossless but it's taking the photo from 2000x1500 to 250x187.
Is it possible that I'm getting the thumbnail and not the actual image? I'm using Photos from Google.
Code
#Override
public void onActivityResult( int requestCode, int resultCode, Intent data ) {
super.onActivityResult( requestCode, resultCode, data );
if ( resultCode == getActivity().RESULT_OK ) {
selectedImage = Uri.parse( data.getDataString() );
try {
final Bitmap v = DecodeUriImage.Decode( selectedImage, getActivity() );
ByteArrayOutputStream bao = new ByteArrayOutputStream();
v.compress( Bitmap.CompressFormat.PNG, 100, bao );
byte[] byte_arr = bao.toByteArray();
// Add image to array
images.set( selectedImageIndex, Base64.encodeToString( byte_arr, Base64.DEFAULT ) );
} catch ( FileNotFoundException e ) {
e.printStackTrace();
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
}
Result
The Bitmap.CompressFormat.PNG will compress the image but It depends on what kink of format you have used on the non-compressed image. You should use a vectorial image to get the best results because on the "compressing transfer" the immage loses the quality both in getting the image bigger on not.
There is no reason to put the selected image in a Bitmap for later use. Moreover you did not show what all is happening in DecodeUriImage.Decode( selectedImage, getActivity() );. Maybe it's quality is changed there. Instead realise you have a media path in selectedImage which you can convert to a real path to the filesystem. Save that path for later use.
If you use it later than just load the file in a byte array and encode base64. Do not use Bitmapfactory.

Android share intent on specific application and from Bitmap resource

I'm trying to share from my app to Hyves using share intent. If I have hyves app installed and share from gallery it switch to hyves app, and upload image correctly to hyves, so it should work.
Problem is, I can't find it documented how should proper intent for hyves work, but I assume that gallery uploads images only, so I have this:
Bitmap image = BitmapFactory.decodeFile(MyGlobals.INSTANCE.activeSetting.f_image_path);
It's line of code where I pull my "active" or "selected" image within my app. At this point image is saved to SD Card, so I might read uri instead of decoding file, but I want it this way to have same approach for both hyves and facebook.
Then I call:
Intent hyvesIntent = new Intent(Intent.ACTION_SEND);
hyvesIntent.setPackage("com.hyves.android.application");
hyvesIntent.setType("image/jpeg");
hyvesIntent.putExtra("image", image);
startActivityForResult(hyvesIntent, 666);
First of all, I'm not sure if setPackage is OK to be used here, but I'm checking if this package exist to enable / disable share, and this is package name that is visible.
I need Activity result to then notify that Image is shared or not.
What happens here it starts the Hyves app, but I get full white screen, and then the Hyves app times out.
So, Can I use Bitmap in intent, and is it OK to setPackage or should I setClass?
Tnx
Maybe you can not put the bitmap directly in the intent.
First convert the bitmap into a byte array than send another side and convert into bitmap
//convert bitmap to bytearray
public static byte[] getBitmapAsByteArray(Bitmap bitmap, boolean type) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
if (type) {
bitmap.compress(CompressFormat.PNG, 0, outputStream);
} else {
bitmap.compress(CompressFormat.JPEG, 0, outputStream);
}
return outputStream.toByteArray();
}
//convert bitmap to bytearray
public static Bitmap getBitmap(byte[] imgByte){
Bitmap bm = BitmapFactory.decodeByteArray(imgByte, 0, imgByte.length);
return bm;
}
//than intent
Intent hyvesIntent = new Intent(Intent.ACTION_SEND);
hyvesIntent.setPackage("com.hyves.android.application");
hyvesIntent.setType("image/jpeg");
hyvesIntent.putExtra("image", getBitmapAsByteArray(image,true));
startActivityForResult(hyvesIntent, 666);
I hope that is right way to put image

Android: decodeFile always returns null for file in internal storage

I have a file saved locally into the application's private storage. I have verified it exists, however whenever I call BitmapFactory.decodeFile it always returns null.
If I save the file as a resource and use ImageView.setImageResource, it always shows up fine.
What is the problem?
Here is the snippet:
filename = "test.png";
if (doesFileExist(filename))
Bitmap bMap = BitmapFactory.decodeFile(filename);
I've also tried:
Bitmap bMap = BitmapFactory.decodeFile(getFilesDir().getPath()
+ filename);
This question has been answered before such as here:
BitmapFactory.decodeFile returns null even image exists
This was exactly what I needed:
String fname=new File(getFilesDir(), "test.png").getAbsolutePath();
Instead of using BitmapFactory.decodeFile, try using InputStream:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) {
super.onActivityResult(requestCode, resultCode, imageReturnedIntent);
if(resultCode == RESULT_OK){
Uri selectedImage = imageReturnedIntent.getData();
InputStream imageStream = getContentResolver().openInputStream(selectedImage);
Bitmap yourSelectedImage = BitmapFactory.decodeStream(imageStream);
Folks, files stored in app resource should be referenced in special way. E.g. if file is located in assets and named as "myfile.png" it has to be referenced as:
String uriString="file:///android_asset/myfile.png";
Uri uri=Uri.parse(uriString);
BitmapFactory.decodeFile expects a file path without the scheme. I.e. without the file:// in the beginning.
If you're handling a Uri, don't just .toString() it, but instead call .getPath() on it, and pass that to the method.
After adding the required permissions (READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE)
You need to add this line to manifests:
android:requestLegacyExternalStorage="true"
Could you try fileList()? It
returns an array of strings naming the
private files associated with this
Context's application package.
For me I was getting image from locally saved URL something like "file:///storage/emulated/0/...." (I have used Phonegap plugin to capture image. Plugin was giving me image path, which I need to use in native code)
Here is the code snippet which worked for me.
String captured_image_info = "file:///storage/emulated/0/Android/data/com.testapp/cache/1493809796526.jpg"
Uri uri=Uri.parse(captured_image_info);
largeLog("uri", "" + uri);
InputStream imageStream = getContentResolver().openInputStream(uri);
Bitmap bm = BitmapFactory.decodeStream(imageStream);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, baos); //bm is the bitmap object
byte[] decodedBytes = baos.toByteArray();
Bitmap img_captured_image = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
You need to setup run-time permissions for Manifest.permission.READ_EXTERNAL_STORAGE
If you don't you'll get a null without getting any error message or even an indication in the Log.
Note that you need to request the permissions both in the Manifest and at run time.

Categories

Resources