I have created a base64 string from a picture on the SD card using this(below) code, and it works but when I try to decode it (even further below) I get a java.lang.outOfMemoryException, presumably because I am not splitting the string into a reasonable size before I decode it as I am before I encode it.
byte fileContent[] = new byte[3000];
StringBuilder b = new StringBuilder();
try{
FileInputStream fin = new FileInputStream(sel);
while(fin.read(fileContent) >= 0) {
b.append(Base64.encodeToString(fileContent, Base64.DEFAULT));
}
}catch(IOException e){
}
The above code works well, but the problem comes when I try to decode the image with the following code;
byte[] imageAsBytes = Base64.decode(img.getBytes(), Base64.DEFAULT);
ImageView image = (ImageView)this.findViewById(R.id.ImageView);
image.setImageBitmap(
BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)
);
I have tried this way too
byte[] b = Base64.decode(img, Base64.DEFAULT);
Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
image.setImageBitmap(bitmap);
Now I assume that I need to split the string up into sections like my image encoding code, but I have no clue how to go about doing it.
You need decode the image in Background thread like AsyncTask
or
you need reduce your image quality using BitmapFactory .
Example:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
options.inPurgeable=true;
Bitmap bm = BitmapFactory.decodeFile("Your image exact loaction",options);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, baos); //bm is the bitmap object
byte[] b = baos.toByteArray();
String encodedImage = Base64.encodeToString(b, Base64.DEFAULT);
You have two problem
base64 encoding requires much more space. 3 bytes convert to 4 chars (Factor 8/3)
you read the whole file at once
in same way your first approach solved this issues. So just use that version
By that way, why are you using decodeByteArray and not decodeFile
You might try to decode to a temporary file and create image from that file.
As to base64, it is 6 bits per character, or 6x4=24 bits=3 bytes per 4 characters.
So if you take 4 characters of base64, you will not break the corresponding 3 bytes.
That is, you may split the base64-encoded data at character indices that are a multiple of 4.
Related
I am trying to read a bitmap generated on the platform site
here is the code I use to generate a byte array in android:
ByteBuffer byteBuffer = ByteBuffer.allocate(bitmap.getByteCount());
bitmap.copyPixelsToBuffer(byteBuffer);
return byteBuffer.array();
When I try to decode it with the image library it fails (dart code):
Image img = decodeBmp(bitmapData);
The method 'getBytes' was called on null.
bitmap data is not empty and looks proper for me
If I instead compress image on the android side to png or jpg than decodeImage (or -Png or -Jpg) works
but I dont want to use bitmap.compress
this code would work with compress
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bufferedBmp.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] imageData = baos.toByteArray();
return imageData;
I've tried this code:
ByteArrayOutputStream bao = new ByteArrayOutputStream();
mylistImg.get(i).compress(Bitmap.CompressFormat.PNG, 100, bao);
byte[] ba = bao.toByteArray();
ba1 = Base64.encodeToString(ba, Base64.DEFAULT);
But it lowers the quality a lot. since I want to send a Base64 string to php, I must convert my Bitmap file to string without any quality reduction.
I've read these links but didn't get anything special!
How to convert Bitmap to string without losing quality
Edited
I'm sending ba1 variable to oracle database as a blob data
but when I see the result in database, the image quality is very low.
and I did not change anything inside my php code about image quality
Try this i just changed the way we get the byte array rather than using .compress method
//b is the Bitmap
Bitmap b=mylistImg.get(i);
//calculate how many bytes our image consists of.
int bytes = b.getByteCount();
//or we can calculate bytes this way. Use a different value than 4 if you don't use 32bit images.
//int bytes = b.getWidth()*b.getHeight()*4;
ByteBuffer buffer = ByteBuffer.allocate(bytes); //Create a new buffer
b.copyPixelsToBuffer(buffer); //Move the byte data to the buffer
byte[] ba= buffer.array();
ba1 = Base64.encodeToString(ba, Base64.DEFAULT);
I have an image which I turn into a byte array. I then encrypt this byte array with AES and I want a visual result to display representing this encryption.
The problem is all the header and meta information is also encrypted so this encrypted byte array, which is passed to byteToImage(), is not recognized as a valid representation of an image i.e. decodeByteArray() returns null.
I have tried cutting off the first 512 bytes of the original image and appending that back on to the start of the encrypted byte array in the hope that this will restore the header information - but it hasn't worked. I have this with .png and .bmp images. What I ideally want is a way to represent a RAW image in android and encrypt this information byte for byte - leaving out the need to fiddle around with headers etc.
I would really appreciate any help.
private static byte[] imageToBytes(ImageView iv){
byte[] imageInByte = null;
Bitmap originalImage;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BitmapDrawable drawable = (BitmapDrawable) iv.getDrawable();
originalImage = drawable.getBitmap();
originalImage.compress(Bitmap.CompressFormat.PNG, 0, baos); // was 70
imageInByte = baos.toByteArray();
return imageInByte;
}
private static Bitmap bytesToImage(byte data[]) {
// byte[] x = Base64.decode(data, Base64.DEFAULT); using x in place of data also fails
Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
return bmp;
}
Your idea will not work. If you encrypt just a lot of bytes of a bitmap byte array you will demolish its structure and after that you don't have a bitmap anymore. So you cannot display it. If you want to be able to display the 'encrypted' image then do it pixel wise. Have a look at Bitmap.getPixel()/setPixel() or Bitmap.getPixels()/setPixels().
I have been trying to pass a single byte array (compressed bitmap) from one activity to another. When I attempt to decode the byte array back to a bitmap, and show the bitmap, it appears to be a completely transparent bitmap.
I use this code on the first activity to compress the bitmap and send the byte array:
try {
InputStream selectedImage = getContentResolver().openInputStream(Uri.parse(photoPath));
bitmap = BitmapFactory.decodeStream(selectedImage);
} catch (FileNotFoundException exception) {
Log.e(this.toString(), exception.toString());
}
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte [] byteArray = stream.toByteArray();
Log.e("PANTHERIT_BYTEARRAY", byteArray.toString());
Intent stickerActivity = new Intent (this, StickerActivity.class);
stickerActivity.putExtra("byteArray", byteArray);
startActivity(stickerActivity);
And I use this code in the accepting activity to decompress and store the bitmap:
byte [] byteArray = getIntent().getByteArrayExtra("byteArray");
Log.e("STICKER_BYTEARRAY", byteArray.toString());
BitmapFactory.Options options = new BitmapFactory.Options();
options.inMutable = true;
bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length, options);
ImageView bitmapview = (ImageView) findViewById(R.id.bitmap_view);
bitmapview.setImageBitmap(bitmap);
I copied the code to the first activity, compressed the bitmap and immediately decompressed it. I took the decompressed bitmap and set it to an ImageView in that activity and it worked fine. So the error seems to be in the passing of the byte array from the first activity to the second, but I cannot figure out why that would be.
I found an answer. I do not really know why the byte array was getting messed up, maybe it was too large? Even so, both the input and output byte arrays were the same length, so not a very good explanation.
Anyway, I found my answer here: Send Bitmap Using Intent Android. The first answer by Zaid Daghestani is the same as what I initially tried, but his edit is what worked. Instead of passing a byte array, you save the compressed bitmap to a temporary file, and pass the filename through the intent. Definitely works for passing a bitmap, now I just have to figure out how to display the bitmap on a SurfaceView instead of an ImageView...
Also, just in case you need a mutable bitmap (in order to pass it to an ImageView) you can use:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inMutable = true;
bitmap = BitmapFactory.decodeStream(input, null, options);
I've converted an bitmap image into string to save it:
............
Bitmap photo = extras.getParcelable("data");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
photo.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] b = baos.toByteArray();
String encodedImage = Base64.encodeToString(b, Base64.DEFAULT);
Then I retrieve the bitmap from string to set an activity's background just like that:
byte[] temp = Base64.decode(encodedImage, Base64.DEFAULT);
Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap bitmap = BitmapFactory.decodeByteArray(temp, 0,
temp.length, options);
Drawable d = new BitmapDrawable(getResources(), bitmap);
getWindow().setBackgroundDrawable(d);
Everything works fine but the image quality reduces tremendously. How can I keep the image quality same as the original image? Did I do something wrong here that have reduced the quality?
JPEG is lossy, no matter what quality settings you use. If you want to keep the image unchanged, you have to use lossless compression. for example Bitmap.CompressFormat.PNG
You are having here a tradeoff situation between picture quality and memory usage. Take a look at this line:
photo.compress(Bitmap.CompressFormat.JPEG, 100, baos);
photo.compress is obviously decreasing your image resolution in a factor given by the second parameter, unfortunately, this is the best quality you can get, since between 0 - 100, 100 stands for the best quality you can get. Now, you have another option, depending on the original picture's size you can just save the image without compressing it, but be aware that most cases this doesn't work and Jalvik can throw an OutofMemoryException,
hope this helps.