Low size image uploading - android

I try upload image to server. I get image by path and convert it to byte array:
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
Bitmap picture = BitmapFactory.decodeFile(imagePath, bmOptions);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
ByteArrayOutputStream bao = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bao);
byte[] bytes = bao.toByteArray();
builder.addPart("uploadedfile", new ByteArrayBody(bytes, "name" + ".jpg"));
For example image's size is 300kb but size of uploaded image is 800kb.
How can I send image (selected by path) without size increasing?
SOULUTION
#greenapps right. I converted image as file:
public static byte[] fullyReadFileToBytes(File f) throws IOException {
int size = (int) f.length();
byte bytes[] = new byte[size];
byte tmpBuff[] = new byte[size];
FileInputStream fis= new FileInputStream(f);;
try {
int read = fis.read(bytes, 0, size);
if (read < size) {
int remain = size - read;
while (remain > 0) {
read = fis.read(tmpBuff, 0, remain);
System.arraycopy(tmpBuff, 0, bytes, size - remain, read);
remain -= read;
}
}
} catch (IOException e){
throw e;
} finally {
fis.close();
}
return bytes;
}

Put the image file in a byte array without using an intermediate Bitmap.

Related

How to read large file to byte array?

I have tried for 200 MB of image file and converting it onto byte array but is crashed due to OOM, so how to read large file and converting into byte[]
Caused by: java.lang.OutOfMemoryError: Failed to allocate a 210288697 byte allocation with 4108138 free bytes and 186MB until OOM
byte[] fullyReadFileToBytes(File file) throws IOException {
int size = (int) file.length();
byte bytes[] = new byte[size];
byte tmpBuff[] = new byte[size];
FileInputStream fis = new FileInputStream(file);
try {
int read = fis.read(bytes, 0, size);
if (read < size) {
int remain = size - read;
while (remain > 0) {
read = fis.read(tmpBuff, 0, remain);
System.arraycopy(tmpBuff, 0, bytes, size - remain, read);
remain -= read;
}
}
} catch (IOException e) {
throw e;
} finally {
fis.close();
}
return bytes;
}
NOTE: I have tried for 100MB and it is working perfect but in case of size greater than 150MB it's creating crash.
Use Http post multipart transfer i.e.
ByteArrayInputStream fileInputStream = new ByteArrayInputStream(dataFile.getContent());
int bytesAvailable = fileInputStream.available();
int maxBufferSize = 1024 * 1024;//1 mb buffer - set size according to your need
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize];
int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dataOutputStream.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
dataOutputStream.writeBytes(lineEnd);
Use volley multi-transfer request. It will keep track of failures
https://gist.github.com/anggadarkprince/a7c536da091f4b26bb4abf2f92926594
The below code helps to compress the bitmap image and convert to string bytes.
public String BitMapToString(Bitmap bitmap) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, baos);
byte[] b = baos.toByteArray();
String temp = null;
try {
System.gc();
temp = Base64.encodeToString(b, Base64.DEFAULT);
} catch (Exception e) {
e.printStackTrace();
} catch (OutOfMemoryError e) {
baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, baos);
b = baos.toByteArray();
temp = Base64.encodeToString(b, Base64.DEFAULT);
}
return temp;
}

Why bitmap compress with 100 quality became smaller

I am using camera with ImageFormat NV21 to preview, when I get NV21 data, I try to use this method following to get bytes that can be displayed to ImageView.
FONT FACE:
public static byte[] n21ToBitmap(byte[] data, Camera camera) {
try {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = parameters.getPreviewSize();
YuvImage image =
new YuvImage(data, parameters.getPreviewFormat(), size.width, size.height, null);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, size.width, size.height), 100, stream);
Bitmap originBitmap = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
stream.close();
Matrix matrix = new Matrix();
matrix.postRotate(270);
Bitmap rotateBitmap =
Bitmap.createBitmap(originBitmap, 0, 0, originBitmap.getWidth(), originBitmap.getHeight(),
matrix, true);
Bitmap temp = rotateBitmap.copy(rotateBitmap.getConfig(), true);
Log.e("TAG", "n21ToBitmap(ImageUtils.java:"
+ Thread.currentThread().getStackTrace()[2].getLineNumber()
+ ")"
+ "temp:"
+ temp.getByteCount());
stream = new ByteArrayOutputStream();
temp.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] bytes = stream.toByteArray();
Log.e("TAG", "n21ToBitmap(ImageUtils.java:"
+ Thread.currentThread().getStackTrace()[2].getLineNumber()
+ ")"
+ "bytes:"
+ bytes.length);
return bytes;
} catch (Exception ex) {
Log.e(TAG, "Error:" + ex.getMessage());
}
return null;
}
And the LOG:
n21ToBitmap(ImageUtils.java:103)temp: 2073600
n21ToBitmap(ImageUtils.java:112)bytes:311627
So, why the bytes length become smallar?
See bytes length is the size of array so each array indexes have some value again in bytes.
byte[] bytes;
bytest.length = array size;
Now your array size = 20 = bytest.length;
and each index have some bytes value.
Assume 1024 byets each index containing.
So total size = 20*1024 this is the actual size
in your case array length is 311627 and each index have some bytes of value
so total size = 311627* value at each index

Convert a file (<100Mo) in Base64 on Android

I am trying to convert a file from the sdcard to Base64 but it seems the file is too big and i get an OutOfMemoryError.
Here is my code :
InputStream inputStream = null;//You can get an inputStream using any IO API
inputStream = new FileInputStream(file.getAbsolutePath());
byte[] bytes;
byte[] buffer = new byte[8192];
int bytesRead;
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
while ((bytesRead = inputStream.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
e.printStackTrace();
}
bytes = output.toByteArray();
attachedFile = Base64.encodeToString(bytes, Base64.DEFAULT);
Is there a way to go around the OutOfMemoryError while filing the String attachedFile ?
Base64 encoding takes 3 input bytes and converts them to 4 bytes. So if you have 100 Mb file that will end up to be 133 Mb in Base64. When you convert it to Java string (UTF-16) it size will be doubled. Not to mention that during conversion process at some point you will hold multiple copies in memory. No matter how you turn this it is hardly going to work.
This is slightly more optimized code that uses Base64OutputStream and will need less memory than your code, but I would not hold my breath. My advice would be to improve that code further by skipping conversion to string, and using temporary file stream as output instead of ByteArrayOutputStream.
InputStream inputStream = null;//You can get an inputStream using any IO API
inputStream = new FileInputStream(file.getAbsolutePath());
byte[] buffer = new byte[8192];
int bytesRead;
ByteArrayOutputStream output = new ByteArrayOutputStream();
Base64OutputStream output64 = new Base64OutputStream(output, Base64.DEFAULT);
try {
while ((bytesRead = inputStream.read(buffer)) != -1) {
output64.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
e.printStackTrace();
}
output64.close();
attachedFile = output.toString();
// Converting File to Base64.encode String type using Method
public String getStringFile(File f) {
InputStream inputStream = null;
String encodedFile = "", lastVal;
try {
inputStream = new FileInputStream(f.getAbsolutePath());
byte[] buffer = new byte[10240]; //specify the size to allow
int bytesRead;
ByteArrayOutputStream output = new ByteArrayOutputStream();
Base64OutputStream output64 = new Base64OutputStream(output, Base64.DEFAULT);
while ((bytesRead = inputStream.read(buffer)) != -1) {
output64.write(buffer, 0, bytesRead);
}
output64.close();
encodedFile = output.toString();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
lastVal = encodedFile;
return lastVal;
}

Android Byte Array to Bitmap Results Null After Receiving From Socket

I have created a server which receives byte array from a c++ client, the client send image as uchar array(using opencv) and on the android I am receiving the data correctly. The server on android store data to byte array and I need to convert this byte array to Bitmap. But I am getting null Bitmap after using BitmapFactory.decodeByteArray.
Here is my server code which receives data and store in to byte array
class imageReciver extends Thread {
public static byte imageByte[];
private ServerSocket serverSocket;
InputStream in;
int imageSize=921600;//expected image size 640X480X3
public imageReciver(int port) throws IOException{
serverSocket = new ServerSocket(port);
}
public void run()
{
Socket server = null;
server = serverSocket.accept();
in = server.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte buffer[] = new byte[1024];
int remainingBytes = imageSize; //
while (remainingBytes > 0) {
int bytesRead = in.read(buffer);
if (bytesRead < 0) {
throw new IOException("Unexpected end of data");
}
baos.write(buffer, 0, bytesRead);
remainingBytes -= bytesRead;
}
in.close();
imageByte = baos.toByteArray();
baos.close();
server.close();
//Here conver byte array to bitmap
Bitmap bmp = BitmapFactory.decodeByteArray(imageByte, 0,imageByte.length);
return;
}
}
I seems your code is not correct, try this:
try {
URL myURL = new URL(url);
final BufferedInputStream bis = new BufferedInputStream(myURL.openStream(), 1024);
final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
BufferedOutputStream out = new BufferedOutputStream(dataStream,1024);
copy(bis, out);
out.flush();
final byte[] data = dataStream.toByteArray();
BitmapFactory.Options bfo = new BitmapFactory.Options();
bfo.inSampleSize = 2;
Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length, bfo);
bis.close();
//use the bitmap...
}
catch (Exception e) {
//handle ex
}

What is the most efficient way to convert image to Base64 in Android?

I am looking for the most efficient way of converting image file to Base64 String in Android.
The image has to be sent in a single Base64 String at once to backend.
First I use imageToByteArray and then imageToBase64 to get the String.
public static byte[] imageToByteArray(String ImageName) throws IOException {
File file = new File(sdcard, ImageName);
InputStream is = new FileInputStream(file);
// Get the size of the file
long length = file.length();
// Create the byte array to hold the data
byte[] bytes = new byte[(int)length];
// Read in the bytes
int offset = 0;
int numRead = 0;
while (offset < bytes.length
&& (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
offset += numRead;
}
//Close input stream
is.close();
// Ensure all the bytes have been read in
if (offset < bytes.length) {
throw new IOException("Could not completely read file "+file.getName());
}
return bytes;
}
public String imageToBase64(String ImageName){
String encodedImage = null;
try {
encodedImage = Base64.encodeToString(imageToByteArray(ImageName), Base64.DEFAULT);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return encodedImage;
}
Below is how I handle it mostly, this is in the gotActivityResults callback after calling the image picker activity. It's similar to your's but I think it will be more efficient because the toByteArray from the stream is native c code behind it as opposed to the java loop in yours.
Uri selectedImage = imageReturnedIntent.getData();
InputStream imageStream = getContentResolver().openInputStream(selectedImage);
Bitmap yourSelectedImage = BitmapFactory.decodeStream(imageStream);
ByteArrayOutputStream bao = new ByteArrayOutputStream();
yourSelectedImage.compress(Bitmap.CompressFormat.JPEG, 90, bao);
byte [] ba = bao.toByteArray();
String ba1= Base64.encodeToString(ba, 0);
HashMap<String, String > params = new HashMap<String, String>();
params.put("avatar", ba1);
params.put("id", String.valueOf(uc.user_id));
params.put("user_id", String .valueOf(uc.user_id));
params.put("login_token", uc.auth_token);
uc.setAvatar(params);

Categories

Resources