I am testing out if it is possible to send a JSON file with a image or two. Currently, I have the images converted into bytes and I use
Base64.encodeToString(temp_arr, Base64.NO_WRAP);
(this is Androids base64 class, and I have to use .NO_WRAP feature to make it work after reading other stack overflow pages)
to convert it to a string. At this point, I pass that string object into my JSON file (Using GSON library) and add the string go it. This data will be sent to a PHP page.
I have test converting the bytes into base64 and saving to a text file, copying that text file into my php page, running it through my php page using
base64_decode($);
and that is able to properly recreate the image just fine (sha hashes match). So now I needed to test it sending it over a network and using json. Is the only difference is that base64 string is put int other json file rather then a text file, the json is sent to php, i grab the data and decode it in PHP.
now the problem is the image is corrupt, looking at both files in a hex editor, the first 20 lines or so in the hex editor match fine, but after that it does not match. Oddly enough the very end of the files have same data except the uploaded copy has extra characters making it larger in size.
So my problem is trying to find out, can it be GSON (JSON) causing the problem or something else, and if so, what can I do about it.
Sadly, the way my work is, my boss needs the data (json with text, data and etc) to be sent at same time, to same php page with the images, this is why I am sending the images via json.
Try this work for me,convert image into base64
public static String getStringImage(Bitmap bmp)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.JPEG, 60, baos);
byte[] imageBytes = baos.toByteArray();
String encodedImage = Base64.encodeToString(imageBytes, Base64.DEFAULT);
Log.e("SignUp", "Image Decode : " + encodedImage);
String asa = encodedImage;
return encodedImage;
}
//pass bitmap image and return string of base64
I believe I found my solution, problem was the Base64.encodeToString() would encode the images bytes to characters that included "+", where on the PHP side, the data would be send except all the "+" became spaces. I just had to replace all spaces with the + and it worked.
Related
I make a http request in my android app to the google cloud api with the Volley library. My problem resides in the payload that I am sending. Google returns an 400 error. If I manually create the payload (json file) it works just fine.
I am creating a JSONObject and put into imageBytes the string "[BASE64]". If I put in the base64 encoded string directly i get escape problems as soon as I do JSONObject.toString().
Here is my code:
JSONObject payload = new JSONObject();
JSONObject image = new JSONObject();
JSONObject imageBytes = new JSONObject();
imageBytes.put("imageBytes", "[BASE64]");
image.put("image", imageBytes);
payload.put("payload", image);
requestBody = payload.toString().replace("[BASE64]", convert_bitmap(args[0]));
private String convert_bitmap(Bitmap bitmap){
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream.toByteArray();
return Base64.encodeToString(byteArray, Base64.DEFAULT);
}
I also tried to load the example payload file and replace the [BASE64] with my base64 string getting the same result. The only thing that works is adding the base64 encoded image directly in
imageBytes.put("imageBytes", "/9j/4AAQSkZJRgA...");
but only if the image is very small. I get compiler error (String is too long) when I put a large string there.
I have also tried to send the request to my server and save it in order to see differences between the working one and mine. The only thing that I have noticed is that in the non working examples, the line length is shorter:
{"payload":{"image":{"imageBytes":"/9j/4AAQSkZJRgABAQAAAQABAAD/4gIoSUNDX1BST0ZJTEUAAQEAAAIYAAAAAAIQAABtbnRyUkdC
IFhZWiAAAAAAAAAAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAA
AADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlk
ZXNjAAAA8AAAAHRyWFlaAAABZAAAABRnWFlaAAABeAAAABRiWFlaAAABjAAAABRyVFJDAAABoAAA..."}}}
and the working one:
{"payload":{"image":{"imageBytes":"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..."}}}
Resuming: When I add the base64 encoded image directly into the json file I get it to work. Also when I convert a very small image file into base64 and put the string directly into my code it works. But when dealing with normal images (photo taken with phone etc) and put the base64 encoded string in the imageBytes field it wont work due to escape problems (toString() seems to add slashes when converting the JSONObject) and replacing something like [BASE64] with my string also doesnt work due to line breaks or string length limits. I expect my problem to be here but cant solve it.
Oh boy… I have solved it! The solution was the Base64.NO_WRAP flag.
As I already thought while posting my question, the problem was the line break added while converting to base64.
I have in my application a image upload method that need to send a image and a string to my server.
The problem is that the server receives the content (image and string) but when it saves the image on the disk it is corrupted and can't be opened.
This is the relevant part of the script.
HttpPost httpPost = new HttpPost(url);
Bitmap bmp = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
String byteStr = new String(byteArray);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("--"+boundary+"\r\n");
stringBuilder.append("Content-Disposition: form-data; name=\"content\"\r\n\r\n");
stringBuilder.append(message+"\r\n");
stringBuilder.append("--"+boundary+"\r\n");
stringBuilder.append("Content-Disposition: form-data; name=\"image\"; filename=\"image.jpg\"\r\n");
stringBuilder.append("Content-Type: image/jpeg\r\n\r\n");
stringBuilder.append(byteStr);
stringBuilder.append("\r\n");
stringBuilder.append("--"+boundary+"--\r\n");
StringEntity entity = new StringEntity(stringBuilder.toString());
httpPost.setEntity(entity);
I can't change the server because other clients use it and it works for them. I just need to understand why the image is being corrupted.
When you do new String(byteArray), it's converting binary into the default character set (which is typically UTF-8). Most character sets aren't a suitable encoding for binary data. In other words if you were to encode certain binary strings to UTF-8 and then decode back to binary, you would not get the same binary string.
Since you're using multipart encoding, you need to write directly to the stream of the entity. Apache HTTP Client has helpers for doing this. See this guide, or this Android guide to uploading with multipart.
If you NEED to using strings only, you can safely convert your byte array to a string with
String byteStr = android.util.Base64.encode(byteArray, android.util.Base64.DEFAULT);
But it's important to note that your server will need to Base64 decode the string back to a byte array and save it to an image. Further, the transfer size will be greater because Base64 encoding isn't as space efficient as raw binary.
Your solutions above is not working because you are using new String(byteArray). The constructor encodes the byte array using the default encoding - see What is the default encoding - and it is very likely, that you have byte sequences in your data that cannot be encoded into a character.
To be more precise, a charset defines how characters are represented as bytes.
Most charsets have more than 256 characters. That is why you need more than one byte to represent a character. UTF-8 and UTF-16 uses up to four bytes.
So you have a mapping between the number space and the character space and this mapping is not bejectiv a priori. So it is very likely that there exist a number in the number space that have no character mapped to it.
The solution #Samuel suggested is foolproof because Base64 uses A–Z, a–z, 0–9, + , / and terminates with = to represent a byte. I would prefer this solution!
If you don't want or cannot use Base64, than you can try just to throw in every byte as it is into the StringBuilder hoping that the server does not do any encoding before you get it.
for (byte b : byteArray) {
stringBuilder.append((char)b);
}
I do not recommand that solution in general, but it may help you to get your stuff done.
I Uploaded one file Tried converting the image to Base64 String through this site http://base64.wutils.com/encoding-online/. When i am copying the base64 string from this site then it is working in my code and image is getting displayed properly
But, when i am trying to convert the image into Base64 String through Base64.encodeBase64URLSafeString the Base64 String which i am getting is not working in my code and image is not getting displayed.
Further i analysed i found out that difference between Base64 String which i copied from site and which i am generated through encodeBase64URLSafeString. Attached the snapshot for reference.Also attached the code for reference.
//this line will fetch the image data from db and i am storing into byte array
byte[] imageData = smpResource.getValue();
//i am adding this byte array into json object and sending.
JSONObject result = new JSONObject();
result.put("image", imageData);
selectedImage.innerHTML = "<img src='data:image/jpg;base64, temp'/>";
Seems like some character encoding problem.Right side of the image is working one copied from site .Can see the diff / replaced with _.How to overcome this problem.Thanks in advance
I create a PIL image string on a python server:
frame = cv.CaptureFromCAM(0)
image = Image.fromstring('RGB', cv.GetSize(frame), frame.tostring(), 'raw', 'BGR')
buffer = cStringIO.stringIO()
image.save(buffer,'JPEG')
udptransmit(buffer.getvalue())
I have a java client trying to read the transmitted image string and reform the jpeg. This however doesn't seem to be working. I created a python client just to check, and I can reform the jpeg correctly using a call to pygame's load method.
The string being sent from python, contains characters 6:10 = JFIF, which is the correct format (also recognised by python's imghdr module.
In java, I ahve tried
simply writing the byte contents of the string received into a file and naming it with a .jpeg extension. The file isn't a valid jpeg.
Using ImageIO to read the bytes from the string. This produces a null image.
Tried to fetch ImageReaderByFormat('JPEG') and parse the bytes with this. This gives me an error stating 'Image is not a JPEG, starts with 0x...'
I really can't see why python recognises the string as a valid jpeg and java doesn't. Do the two use different jpeg decoders? Even if they do, shouldn't both either validate or reject the string?
Just found a solution to the problem
The problem was with the charset used in java while converting the string sent from my python server into bytes in java.
Here's the simple modification that was required in my java client code:
Charset charset = Charset.forName("ISO-8859-1");
Byte[] bytes: Array[Byte] = cam_data.getBytes(charset)
File f = new File("image.jpeg")
FileImageOutputStream fios = new FileImageOutputStream(f)
BufferedImage bim = ImageIO.read(new ByteArrayInputStream(bytes))
ImageIO.write(bim,"jpeg",fios)
The helpful link that lead me to the answer was http://www.java-forums.org/advanced-java/50516-reading-image-files-into-strings.html
I am struggling with the transfer of a simple jpeg file inside an ID3v2 tag from c++ over a TCP socket to java (Android). The library "taglib" offers to extract this file and I am able to save the jpeg as a new file.
The send function looks like this
char *parameter_full = new char[f3->picture().size()+2];
sprintf(parameter_full,"%s\n\0",f3->picture().data());
// send
result = send(c,parameter_full,strlen(parameter_full),0);
delete[] parameter_full;
where
f3->picture().data() returns a pointer to the internal data structure (it returns char*) and
f3->picture().size() returns the size of the array.
Then Android receives it with
String imageString = inFromServer.readLine();
byte[] imageBytes = imageString.getBytes();
Bitmap cover = BitmapFactory.decodeByteArray(imageBytes,0,imageBytes.length);
But somehow decodeByteArray always returns null. My idea is that Java doesn't receive the image correctly because imageString only consists of 4 characters...while the extracted jpeg file has a size of 12.7 KB.
But what has gone wrong?
Martin
You shouldn't use string functions on byte data because 0 values are taken as string terminators. Try looking into memcpy on the C++ side if you need to copy the char* and also the byte[] read functions for InputStream on the Java side.