Enhancing the performance from changing the bitmap to hexString - android

I am trying to convert the captured photos (in .jpeg format ) to hexadecimal strings but when it comes to action, it tales more than 2 minutes to return the successful conversion. Would you please tell me how to enhance the performance besides increasing the buffer size? (using in Android)
The below is my code
private String changeByteToHex(byte[] a) {
StringBuilder sb = new StringBuilder();
for (byte d : a) {
sb.append(String.format("%02X", d));
}
return sb.toString();
}
public String photoEncode(File file) {
try{
ByteArrayInputStream inStream = retrieveByteArrayInputStream(file);
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] temp = new byte[8192];
int read;
while((read = inStream.read(temp)) >= 0){
outStream.write(temp, 0, read);
}
byte[] data = outStream.toByteArray();
return changeByteToHex(data);
} catch(Exception ex) {
ex.printStackTrace();
return null;
}
}

Related

How to compress a String in Android

I am trying to compress a large string object. This is what i tried, but i am unable to understand how to get compressed data, and how to define different type of compression tools.
This is what i got from Android docs.
byte[] input = jsonArray.getBytes("UTF-8");
byte[] output = new byte[100];
Deflater compresser = new Deflater();
compresser.setInput(input);
compresser.finish();
int compressedDataLength = compresser.deflate(output);
compresser.end();
compresser.deflate(output) gives me a int number, 100
but i am unable to understand which method will give me the compressed output that i can send to service.
The algorithm that I compress my data with is Huffman. You can find it by a simple search. But in your case maybe it helps you:
public static byte[] compress(String data) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length());
GZIPOutputStream gzip = new GZIPOutputStream(bos);
gzip.write(data.getBytes());
gzip.close();
byte[] compressed = bos.toByteArray();
bos.close();
return compressed;
}
And to decompress it you can use:
public static String decompress(byte[] compressed) throws IOException {
ByteArrayInputStream bis = new ByteArrayInputStream(compressed);
GZIPInputStream gis = new GZIPInputStream(bis);
BufferedReader br = new BufferedReader(new InputStreamReader(gis, "UTF-8"));
StringBuilder sb = new StringBuilder();
String line;
while((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
gis.close();
bis.close();
return sb.toString();
}
The documentation for Deflator shows that the output gets put into the buffer output
try {
// Encode a String into bytes
String inputString = "blahblahblah";
byte[] input = inputString.getBytes("UTF-8");
// Compress the bytes
byte[] output = new byte[100];
Deflater compresser = new Deflater();
compresser.setInput(input);
compresser.finish();
int compressedDataLength = compresser.deflate(output);
compresser.end();
// Decompress the bytes
Inflater decompresser = new Inflater();
decompresser.setInput(output, 0, compressedDataLength);
byte[] result = new byte[100];
int resultLength = decompresser.inflate(result);
decompresser.end();
// Decode the bytes into a String
String outputString = new String(result, 0, resultLength, "UTF-8");
} catch(java.io.UnsupportedEncodingException ex) {
// handle
} catch (java.util.zip.DataFormatException ex) {
// handle
}
all code you need to ENCODE, COMPRESS , DECOMPRESS , DECODE

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

Error in sending image as part of a JSONObject from android to GAE

I need to send an image from my Android app to Google App Engine datastore. This image needs to be embedded as a Blob datatype inside a JSONObject.
I am able to capture the image from the device camera and compress it to the jpg format. I then use the ByteArrayOutputStream from the Bitmap.compress() method to create a byte array.
The question is, how do I place (put()/accumulate()) this byte array into the JSONObject. I have tried the following, i.e., converting the byte array to a JSONArray
private JSONObject createJSONObject() {
byte[] bryPhoto = null;
ByteArrayInputStream bais = null;
ByteArrayOutputStream baos = null;
JSONArray jryPhoto = null;
JSONObject jbjToBeSent = null;
baos = new ByteArrayOutputStream();
jbjToBeSent = new JSONObject();
try {
jbjToBeSent.accumulate("hwBatch", strBatch);
jbjToBeSent.accumulate("hwDescription", etDescription.getText().toString());
if(null == bmpPhoto) {
bryPhoto = null;
}
else {
bmpPhoto.compress(Bitmap.CompressFormat.JPEG, 10, baos);
bryPhoto = baos.toByteArray();
bais = new ByteArrayInputStream(bryPhoto);
}
jryPhoto = readBytes(bais);
jbjToBeSent.accumulate("hwPhoto", jryPhoto);
}
catch(JSONException je) {
// Omitted exception handling code to improve readability
}
return jbjToBeSent;
}
public JSONArray readBytes(InputStream inputStream) {
JSONArray array = null;
try {
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
array = new JSONArray();
int len = 0;
int i = 0;
while ((len = inputStream.read(buffer)) != -1) {
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
byteBuffer.write(buffer, 0, len);
byte[] b= byteBuffer.toByteArray();
array.put(i,Base64.encodeToString(b, Base64.DEFAULT));
i++;
}
}
catch(IOException ioe) {
// Omitted exception handling code to improve readability
}
catch(JSONException jsone) {
// Omitted exception handling code to improve readability
}
return array;
}
This fails on the server side with the error:
Expected BEGIN_OBJECT but was BEGIN_ARRAY.
I know what I am doing is wrong but then, what is the correct way of embedding a byte array in a JSONObject?
EDIT: I know about Blobstore and that would be my last resort. My attempt to make this work is not an attempt to circumvent the Blobstore.
try this,
public JSONArray readBytes(InputStream inputStream) {
JSONArray array = null;
try {
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
array = new JSONArray();
int len = 0;
int i = 0;
array = new JSONArray();
while ((len = inputStream.read(buffer)) != -1) {
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
byteBuffer.write(buffer, 0, len);
byte[] b= byteBuffer.toByteArray();
array.put(i,Base64.encodeToString(b, Base64.DEFAULT));
i++;
}
}
catch(IOException ioe) {
}
catch(JSONException jsone) {
}
return array;
}

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

Reading a resource sound file into a Byte array

I have cheerapp.wav or cheerapp.mp3 or some other format.
InputStream in = context.getResources().openRawResource(R.raw.cheerapp);
BufferedInputStream bis = new BufferedInputStream(in, 8000);
// Create a DataInputStream to read the audio data from the saved file
DataInputStream dis = new DataInputStream(bis);
byte[] music = null;
music = new byte[??];
int i = 0; // Read the file into the "music" array
while (dis.available() > 0) {
// dis.read(music[i]); // This assignment does not reverse the order
music[i]=dis.readByte();
i++;
}
dis.close();
For the music byte array which takes the data from the DataInputStream. I don't know what the length of that to allocate.
This is raw file from resource not a file therefore I wouldn't know the size of that thing.
You do have byte array length as you can see:
InputStream inStream = context.getResources().openRawResource(R.raw.cheerapp);
byte[] music = new byte[inStream.available()];
And then you can read whole Stream into byte array easily.
Of course I would recommend that you do check when it comes to the size and use ByteArrayOutputStream with smaller byte[] buffer if needed:
public static byte[] convertStreamToByteArray(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buff = new byte[10240];
int i = Integer.MAX_VALUE;
while ((i = is.read(buff, 0, buff.length)) > 0) {
baos.write(buff, 0, i);
}
return baos.toByteArray(); // be sure to close InputStream in calling function
}
If you'll be doing lots of IO operations I recommend that you make use of org.apache.commons.io.IOUtils. That way you won't need to worry too much about quality of your IO implementation and once you import JAR into your project you would just do:
byte[] payload = IOUtils.toByteArray(context.getResources().openRawResource(R.raw.cheerapp));
Hope it will help.
Create an sdcard path:
String outputFile =
Environment.getExternalStorageDirectory().getAbsolutePath() + "/recording.3gp";
Convert as a file and have to call the byte array method:
byte[] soundBytes;
try {
InputStream inputStream =
getContentResolver().openInputStream(Uri.fromFile(new File(outputFile)));
soundBytes = new byte[inputStream.available()];
soundBytes = toByteArray(inputStream);
Toast.makeText(this, "Recordin Finished"+ " " + soundBytes, Toast.LENGTH_LONG).show();
} catch(Exception e) {
e.printStackTrace();
}
method:
public byte[] toByteArray(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
int read = 0;
byte[] buffer = new byte[1024];
while (read != -1) {
read = in.read(buffer);
if (read != -1)
out.write(buffer,0,read);
}
out.close();
return out.toByteArray();
}
In Kotlin use
InputStream.readBytes()

Categories

Resources