In a android application I'm building, I convert the jpg image to string using Base64.encodeToString() and sending to a server via TCP socket.
The problem is when I try to decode the string back to the image. I can print the string that I receive, it looks like this at the end of the file(The only part I can copy because the file is to big to print everything on the terminal):
....+77DgjRKHqbxBmYCDOzv9vLzFwff4N146snCWin6ZlzbN++HJOIIPodB/JTOoc1NjczeqoHwOju
iWdI6ePeSO0ADz46vh4LODnM7FCJYhbTX0TizmNatXvxSFoVzLiqfn19iYjvAPD/AQnRoUxtpJij
AAAAAElFTkSuQmCC
But when I try to decode and save into a jpg file again I get the following error:
Traceback (most recent call last):
File "tcp.py", line 20, in <module>
file.write(base64.decodestring(msg))
File "/usr/lib/python2.7/base64.py", line 328, in decodestring
return binascii.a2b_base64(s)
binascii.Error: Incorrect padding
Here is a piece of my Android application code used to encode and send the message:
//Function that encodes the Bitmapfile into string
public String BitMapToString(Bitmap bitmap){
ByteArrayOutputStream baos=new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG,100, baos);
byte [] arr=baos.toByteArray();
String result=Base64.encodeToString(arr, Base64.DEFAULT);
return result;
}
class myTask extends AsyncTask<Void,Void,Void>
{
//Faz a conexao entre aparelho e servidor
@Override
protected Void doInBackground(Void... params){
try
{
//create socket and buffer to send the string message
newSocket = new Socket(ipAdress,5000);
printWriter = new PrintWriter(newSocket.getOutputStream());
bufferedWriter = new BufferedWriter(new OutputStreamWriter(newSocket.getOutputStream()));
//Reads the internal storage image and converts into string using Base64
File file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM+"/Reccoon3D/123.jpg");
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
message = BitMapToString(bitmap); //encodes the bitmap
//sends the enconded image
bufferedWriter.write(message);
bufferedWriter.flush();
bufferedWriter.close();
newSocket.close();
}catch (Exception e)
{
e.printStackTrace();
}
return null;
}
}
And here is my python code that receives the message and try to decode it to image again:
import socket
import base64
host = '192.168.1.16'
port = 5000
tcp=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
orig = (host,port)
tcp.bind(orig)
tcp.listen(1)
file=open('file.png','wb')
while True:
con, client = tcp.accept()
print('Conected by', client)
while True:
msg = con.recv(1024000) #Initially 1024 but changet so the message
#would not be sliced into pieces
if not msg: break
#print(msg)
file.write(base64.decodestring(msg))
print('Finalizado com sucesso')
con.close
msg = con.recv(1024000) #Initially 1024 but changet so the message
This will read up to 1024000 bytes from the socket. It might be less than this. And, the size of the chunks read using recv
do not need to have any correlation with the size of the chunks written by the peer, apart from that the total size read over all recv
matches the total size sent.
file.write(base64.decodestring(msg))
A base64 string has always a size which is a multiple of 4 bytes. Even if the decoded data are only one byte the encoded string will be 4 bytes: 2 encoding the input and 2 '=' for padding. If the length of the string used with decodestring
is not a multiple of 4 it will assume a bad padding, i.e. raise binascii.Error: Incorrect padding
.
Your code blindly assumes that the length of msg
will always be a multiple of 4 since you kind of assume that recv
will return all data sent. But, this assumption is wrong and if the length of msg
is not a multiple of 4 you get the error you see.