I have some code that sends string bytes to the server then in mvc c# i take these string bytes convert it into raw bytes and then save the bytes to file. This works great but the problem when i am sending 4 images of string bytes inside of HttpURLConnection the mvc server comes back with saying File Not Found Exception.
So i found out when i sent large images it would fail with this exception, and when i sent images lower that 3080000 bytes it sent the images and saved them to the server.
So now im deciding to show a message to the user displaying a dialog box about the file limit, is this good to do?
This is my code:
Client
try {
if (imgS!=null && imgS.size()>0) {
for (int i = 0; i < imgS.size(); i++) {
if(i == 0){
image1 = Base64.encodeToString(imgS.get(i).bytes, Base64.DEFAULT);
}
if(i == 1){
image2 = Base64.encodeToString(imgS.get(i).bytes, Base64.DEFAULT);
}
if(i == 2){
image3 = Base64.encodeToString(imgS.get(i).bytes, Base64.DEFAULT);
}
if(i == 3){
image4 = Base64.encodeToString(imgS.get(i).bytes, Base64.DEFAULT);
}
}
}
if (!isDelivered) {
deliveredId = 2;
}
if (params[0] != null && (params[0].equals("0.00") || !params[0].equals(""))) {
priceTmp = Double.valueOf(params[0]);
}
if (params[6] != null && (params[6].equals("0.00") || !params[6].equals(""))) {
postageTmp = Double.valueOf(params[6]);
}
String responseText = "";
SharedPreferences preferences = getActivity().getSharedPreferences(PREFERENCE, Context.MODE_PRIVATE);
String json = String.format("{\"p_u_id\": \"%s\",\"price\": \"%.2f\"," +
"\"title\": \"%s\"" +
",\"description\": \"%s\",\"category\": \"%d\",\"tags\": \"%s\"" +
",\"image1\": \"%s\",\"image2\": \"%s\",\"image3\": \"%s\",\"image4\": \"%s\"" +
",\"postcode\": \"%s\",\"postage\": \"%.2f\",\"isDelivered\": \"%d\"}",
preferences.getString("userId", "0"),
priceTmp,
params[1],
params[2],
selectedCategory,
params[4],
image1,
image2,
"",
"",
params[5],
postageTmp,
deliveredId
);
long b = image1.getBytes().length + image2.getBytes().length +image3.getBytes().length + image4.getBytes().length;
if(b > 3080000){
return "FileLimit";
}else{
URL url = new URL("http://xxx/Home/xxxx");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json"); // have tried without this
conn.setRequestProperty("Content-Length", json.getBytes().length + "");
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
os.write(json.getBytes("UTF-8"));
os.close();
conn.connect();
InputStream is = conn.getInputStream();
//here we read and print the response send by server; assuming that response type is text/html (MIME Type)
StringBuilder sb = new StringBuilder();
int ch;
//-1: end of stream
while ((ch = is.read()) != -1) {
sb.append((char) ch);
}
responseText = sb.toString();
conn.disconnect();
JSONObject obj = new JSONObject(responseText);
pid = obj.getInt("id");
serverImage1 = obj.getString("image1");
serverImage2 = obj.getString("image2");
json = String.format("{\"p_id\": \"%d\",\"image1\": \"%s\"," +
"\"image2\": \"%s\",\"p_u_id\": \"%s\"}",
pid,
image3,
image4,
preferences.getString("userId", "0")
);
url = new URL("http://xxx/Home/xxxx");
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json"); // have tried without this
conn.setRequestProperty("Content-Length", json.getBytes().length + "");
conn.setDoOutput(true);
os = conn.getOutputStream();
os.write(json.getBytes("UTF-8"));
os.close();
conn.connect();
is = conn.getInputStream();
//here we read and print the response send by server; assuming that response type is text/html (MIME Type)
sb = new StringBuilder();
ch = 0;
//-1: end of stream
while ((ch = is.read()) != -1) {
sb.append((char) ch);
}
responseText = sb.toString();
return responseText;
}
} catch (Exception e) {
int i = 0;
}
What i have done here is send the first two images to the server then send the next two images after the first two images were sent. This was funny because still if i send images two big the server will come back with an exception again.
So is it good to show a message to the user about file limit?
And how do other apps like shpock n Ebay work when they allow mulitple file uploads?
I tried using some Android Libraries but was unsusseccful.
Would like to know a way of sending maxiumum of four files without showing the user a file limit and just send the 4 images directly.
MVC
if(image.Length > 0)
{
byte[] bytes = Convert.FromBase64String(image);
if (!System.IO.Directory.Exists(Server.MapPath("~/App_Data/products/" + uid)))
{
System.IO.Directory.CreateDirectory(Server.MapPath("~/App_Data/products/") + uid);
}
if (!System.IO.Directory.Exists(Server.MapPath("~/App_Data/products/" + uid + "/" + pid)))
{
System.IO.Directory.CreateDirectory(Server.MapPath("~/App_Data/products/") + uid + "/" + pid);
}
string path = Path.Combine(Server.MapPath("~/App_Data/products/" + uid + "/" + pid), guid + "" + ".jpg");
System.IO.File.WriteAllBytes(path, bytes);
}
When you have a Image you can upload it to a Cloud Database like Firestore or Amazon S3 or whatever and then you send the link instead of the bytes!
Is it a good idea to show file limit to user? Yes it is. Better than errors popping up for them.
Why is it not working for larger than 3MB images? Well, if you look at the Microsoft docs, your Convert.FromBase64String method puts the data into an unsigned 8bit integer array. An unsigned int maxes out at 4.29 Million, so because you have base64 encoded, your image is actually 33% bigger, because it has a ratio of 4:3 when you base64 encode.
Convert.FromBase64String(String) Method
Base64 Padding file size increases
Thus, you cant upload anything bigger than ~3MB.
How do other companies do multi file upload? Well they just call the same file upload endpoint, asynchronously for each file. So if you send 4 files, it will make 4 requests at the same time, and these requests will slowly upload the image (you can usually see each files individual progress bar indicator).
Related
I am running a flask server at the backend. I want to read the image from mobile app and send it to the server to detect faces.
This is the java code(client side) for sending image as bytes -
public class client {
public static void main(String [] args) throws Exception{
String url = "http://127.0.0.1:8080/facial";
// 2. create obj for the URL class
URL obj = new URL(url);
// 3. open connection on the url
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type","image/jpeg");
con.setDoInput(true);
con.setDoOutput(true);
try {
System.out.println("Reading image from disk. ");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.flush();
File file = new File("jpeg.jpg");
BufferedImage image1 = ImageIO.read(file);
ImageIO.write(image1, "jpg", baos);
baos.flush();
System.out.println(baos.size());
byte[] bytes = baos.toByteArray();
baos.close();
System.out.println("Sending image to server. ");
OutputStream out = con.getOutputStream();
DataOutputStream image = new DataOutputStream(out);
image.writeInt(bytes.length);
image.write(bytes, 0, bytes.length);
System.out.println("Image sent to server. ");
image.close();
// close the output stream
out.close();
}catch (Exception e) {
System.out.println("Exception: " + e.getMessage());
}
// define object for the reply from the server
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
//Get response from server
int responseCode = con.getResponseCode();
System.out.println("Response Code : " + responseCode);
// read in the response from the server
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
System.out.println(inputLine);
}
// close the input stream
in.close();
}
}
This is my server code -
def get_facial(data):
face_api_url = 'https://southeastasia.api.cognitive.microsoft.com/face/v1.0/detect'
# Set image_url to the URL of an image that you want to analyze.
headers = {'Ocp-Apim-Subscription-Key': subscription_key,
"Content-Type":"application/octet-stream"
}
params = {
'returnFaceId': 'true',
'returnFaceLandmarks': 'false',
'returnFaceAttributes': 'age,gender,headPose,smile,facialHair,glasses,' +
'emotion,hair,makeup,occlusion,accessories,blur,exposure,noise'
}
response = requests.post(face_api_url, params=params, headers=headers, data=data)
faces = response.json()
res={}
import pdb; pdb.set_trace()
res["status"] = '200'
res["num"] = str(len(faces))
return res
#app.route('/facial',methods=['POST'])
def facial():
import pdb; pdb.set_trace()
data=bytes(request.get_data())
res={}
try:
res = get_facial(data)
except:
res['status'] = '404'
print(res)
return json.dumps(res)
After examining - I sent the same image from another python file and checked the size of the data. It was 102564 bytes and it works but
the same image read and sent from java code is 106208 bytes. I don't know where exactly the mistake is.
Any help is appreciated !!:-)
I found a quick fix to this problem -
Path path = Paths.get("jpeg.jpg");
byte[] fileContents = Files.readAllBytes(path);
image.write(fileContents, 0, fileContents.length);
I don't exactly know why reading from imageio fails. My guess is that its also reading the file headers of the jpg file.
I'm developing an app by enables the user to take a photo and send it to a Keras model for prediction. This model is already deployed in a Google App Engine Service with a Python script that uses Flask for receiving via POST request the image and calling the model to make the prediction. Here's the Python code:
import numpy as np
import flask
import io
import logging
import tensorflow as tf
from keras.preprocessing.image import img_to_array
from keras.applications import imagenet_utils
from keras.models import load_model
from PIL import Image
# initialize our Flask application and the Keras model
app = flask.Flask(__name__)
app.config['PROPAGATE_EXCEPTIONS'] = True
model = None
def recortar(image):
# Function that centers and crop image. Please, asume that it works properly. Return is a numpy array.
return image
#app.route("/predict", methods=["POST"])
def predict():
model = load_model('modelo_1.h5')
graph = tf.get_default_graph()
data = {"success": False}
if flask.request.method == "POST":
if flask.request.files.get("image"):
# read the image in PIL format
image = flask.request.files["image"].read()
image = Image.open(io.BytesIO(image))
image = recortar(image)
app.logger.info('Tamaño: '+str(image.size))
image = img_to_array(image)
image = np.expand_dims(image, axis=0)
with graph.as_default():
preds = model.predict(image)
data['predictions'] = str(np.squeeze(preds).tolist())
data["success"] = True
return flask.jsonify(data)
else:
return "No se ha obtenido la imagen"
else:
return "El HTTP request no era POST"
# if this is the main thread of execution first load the model and
# then start the server
if __name__ == "__main__":
print(("* Loading Keras model and Flask starting server..."
"please wait until server has fully started"))
app.debug = True
app.run()
Sending the image via curl works perfectly: as expected, I obtain a JSON response from the server containing the prediction. Here's the CURL command and the server response:
>> curl -X POST -F image=#nevus.jpg 'https://example.com/predict'
{"predictions":"[0.7404708862304688, 0.25952914357185364]","success":true}
Then I try to repeat the same process, but through an Android app, but I get a 500 error as response. When checking the logs on Stackdriver Error Reporting, I see the following stacktrace:AttributeError:
'NoneType' object has no attribute 'size'
at predict (/home/vmagent/app/main.py:73)
at dispatch_request (/env/lib/python3.6/site-packages/flask/app.py:1799)
at full_dispatch_request (/env/lib/python3.6/site-packages/flask/app.py:1813)
at reraise (/env/lib/python3.6/site-packages/flask/_compat.py:35)
at handle_user_exception (/env/lib/python3.6/site-packages/flask/app.py:1718)
at full_dispatch_request (/env/lib/python3.6/site-packages/flask/app.py:1815)
at wsgi_app (/env/lib/python3.6/site-packages/flask/app.py:2292)
at reraise (/env/lib/python3.6/site-packages/flask/_compat.py:35)
at handle_exception (/env/lib/python3.6/site-packages/flask/app.py:1741)
at wsgi_app (/env/lib/python3.6/site-packages/flask/app.py:2295)
at __call__ (/env/lib/python3.6/site-packages/flask/app.py:2309)
at handle_request (/env/lib/python3.6/site-packages/gunicorn/workers/sync.py:176)
at handle (/env/lib/python3.6/site-packages/gunicorn/workers/sync.py:135)
This error refers to image object, so I assume that, as the code was working properly before, the error must be in the way I send the image through the HTTP request. Recall that the image is taken when a user click a button, because this button sends an intent for taking the photo. When the photo is taken, the user can click a send button, whose code I post bellow. Note that orientedBitmap corresponds to the photo taken in bitmap format.
btn_enviarfoto.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "Botón \"enviar\" pulsado. Codificando imagen.");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
orientedBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
orientedBitmap.recycle();
uploadToServer(byteArray);
}
});
uploadToServer just calls the execute methong of AsynchTask class as shown bellow:
private void uploadToServer(byte[] data) {
Bitmap bitmapOrg = BitmapFactory.decodeByteArray(data, 0, data.length);
Log.d(TAG, "Imagen codificada. Enviando al servidor.");
ObtenerPrediccionTask task = new ObtenerPrediccionTask();
task.execute(bitmapOrg);
}
And finally and most important, this is the code for the ObtenerPrediccionTask class:
public class ObtenerPrediccionTask extends AsyncTask<Bitmap, Void, String> {
#Override
protected String doInBackground(Bitmap... imagen) {
ByteArrayOutputStream bao = new ByteArrayOutputStream();
HttpURLConnection connection = null;
DataOutputStream outputStream = null;
String probabilidad_melanoma = "";
JsonReader jsonReader = null;
try {
for (int i = 0; i < imagen.length; i++) {
Bitmap imagen2 = imagen[i];
imagen2.compress(Bitmap.CompressFormat.JPEG, 90, bao);
byte[] ba = bao.toByteArray();
InputStream fileInputStream = new ByteArrayInputStream(ba);
URL url = new URL("https://example.com/predict"); // not the real URL
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "xxxxxxxx";
String str = twoHyphens + boundary + lineEnd;
connection = (HttpURLConnection) url.openConnection();
// Allow Inputs & Outputs
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
// Enable POST method
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
outputStream = new DataOutputStream(connection.getOutputStream());
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
outputStream.writeBytes("Content-Disposition: form-data; name=\"" +
"image" + "\";filename=\"" +
"foto.jpg" + "\"" + lineEnd);
outputStream.writeBytes(lineEnd);
int bytesAvailable = fileInputStream.available();
int bufferSize = Math.min(bytesAvailable, 1024);
byte[] buffer = new byte[bufferSize];
// Read file
int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
outputStream.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, 1024);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// Responses from the server (code and message)
int responseCode = connection.getResponseCode();
connection.getResponseMessage();
fileInputStream.close();
outputStream.flush();
outputStream.close();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream responseStream = new
BufferedInputStream(connection.getInputStream());
BufferedReader responseStreamReader =
new BufferedReader(new InputStreamReader(responseStream));
String line = "";
StringBuilder stringBuilder = new StringBuilder();
while ((line = responseStreamReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
responseStreamReader.close();
String response = stringBuilder.toString();
Log.d(TAG, "Imagen recibida por el servidor y pasada al modelo. Esta es la respuesta: " + response);
jsonReader = new JsonReader(new StringReader(response));
probabilidad_melanoma = readJson(jsonReader);
} else {
Log.d(TAG, Integer.toString(responseCode));
}
}
return probabilidad_melanoma;
} catch (MalformedURLException malformedURLException) {
Log.e(TAG, malformedURLException.toString());
return null;
} catch (IOException io) {
Log.e(TAG, io.toString());
return null;
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
protected void onPostExecute(String probabilidad_melanoma) {
if (probabilidad_melanoma != null) {
Log.d(TAG, "Probabilidad melanoma: " + probabilidad_melanoma);
} else {
Log.w(TAG, "La respuesta ha sido nula");
}
}
}
readJson function is also working properly, so don't get bothered by it.
This last chunk of code is the result of an extensive search in SO of a way to properly send an image, but as nothing has worked yet, I've run out of ideas. What's the problem with my code?
The crash traceback indicates that at this line image is None:
app.logger.info('Tamaño: '+str(image.size))
Which means that recortar() returns None, despite your comments:
# Function that centers and crop image. Please, asume that it works properly. Return is a numpy array.
So your the error must be in the way I send the image through the HTTP request assumption might be wrong. Before spending time on that I'd first add checks to ensure that recortar() works properly.
We have a hybrid app where most of the code is handled in Javascript (including logging in via Google Sign In and some uploading to Google Drive). On iOS, we have other Google Drive uploading code, but I can't figure out how to accomplish the same thing in Android. I'm trying avoid having the user log into the web portion and then again for Android.
The iOS code that is being used to upload is...
let mutableURLRequest = NSMutableURLRequest(URL: NSURL(string: "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart")!)
mutableURLRequest.HTTPMethod = "POST"
let boundaryConstant = generateBoundaryString()
let contentType = "multipart/related; boundary="+boundaryConstant
// Set the headers
mutableURLRequest.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
mutableURLRequest.addValue("Keep-Alive", forHTTPHeaderField: "Connection")
mutableURLRequest.addValue(contentType, forHTTPHeaderField: "Content-Type")
mutableURLRequest.addValue("\(requestData.length)", forHTTPHeaderField: "Content-Length")
// create upload data to send
let uploadData = NSMutableData()
uploadData.appendData("\r\n--\(boundaryConstant)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
let date = NSDate()
let calendar = NSCalendar.currentCalendar()
let components = calendar.components([.Day, .Month, .Year], fromDate: date)
let fileName = "\(components.year)-\(components.month)-\(components.day).\(ext)"
// Add parameters
let params = [
"name": fileName,
"mimeType": mimeType,
"parents": ["\(slnFldrId)"],
"convert": true
]
// Add the file meta data (JSON format)
uploadData.appendData("Content-Type: application/json; charset=UTF-8\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
uploadData.appendData("\(getJsonString(params))\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
uploadData.appendData("\r\n--\(boundaryConstant)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
// Add the file
uploadData.appendData("Content-Type: \(mimeType)\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
uploadData.appendData(requestData)
uploadData.appendData("\r\n--\(boundaryConstant)--\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
mutableURLRequest.HTTPBody = uploadData
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
let task = session.uploadTaskWithStreamedRequest(mutableURLRequest)
task.resume()
...So it's just using the REST endpoint and works nicely. For Android, I've tried using the HttpClient with HttpPost and setting headers, etc., but I always get a 400 error (Bad request).
String ext = fileName.substring(fileName.lastIndexOf(".") + 1);
String mimeType = mimeTypeFromTypeId(typeId);
String boundary = getBoundary();
String tail = "\r\n-"+ boundary +"--\r\n";
HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 30000);
HttpConnectionParams.setSoTimeout(httpParams, 30000);
HttpClient httpClient = new DefaultHttpClient(httpParams);
HttpPost httpPost = new HttpPost("https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart");
httpPost.addHeader("Authorization", "Bearer "+ Common.accessToken);
httpPost.addHeader("Content-Length", ""+ file.length());
String json = "{\"name\":\"Android upload."+ ext +"\",\"mimeType\":\""+ mimeType +"\",\"parents\":[\""+ Common.slnFldrId +"\"],\"convert\":true}";
MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
entityBuilder.setBoundary(boundary);
entityBuilder.setCharset(MIME.UTF8_CHARSET);
entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
entityBuilder.addTextBody("", json, ContentType.APPLICATION_JSON);
entityBuilder.addBinaryBody("", file, ContentType.create(mimeType), "Android upload."+ ext);
httpPost.setEntity(entityBuilder.build());
httpPost.setHeader(HTTP.CONTENT_TYPE, "multipart-related; boundary="+ boundary);
try
{
return httpClient.execute(httpPost);
}
catch(ConnectTimeoutException e)
{
throw e;
}
...I think the headers are causing the bad request error. Even though I'm setting the Content-Type header to multipart/related, it is always converted to multipart/form-data (I think by the MultipartEntityBuilder).
As far as I can tell, the Google Client libraries all require an authorization process (in that I can't set the accessToken that I already have from the web login into them), which is why I'm not using them.
Any help or suggestions would be greatly appreciated.
The solution I found is based off the article at http://www.codejava.net/java-se/networking/upload-files-by-sending-multipart-request-programmatically
Here is the code with some changes to make it work correctly with the Google Drive API.
URL url = null;
HttpURLConnection connection = null;
try
{
// Set up some constants and "global" variables
String BOUNDARY = getBoundary();
String LINE_FEED = "\r\n";
String UTF8 = "UTF-8";
String fileName = file.getName();
String ext = fileName.substring(fileName.lastIndexOf(".") + 1);
String mimeType = mimeTypeFromTypeId(typeId);
// Use the calendar to give the file a name
Calendar cal = Calendar.getInstance();
int cYear = cal.get(Calendar.YEAR);//calender year starts from 1900 so you must add 1900 to the value recevie.i.e., 1990+112 = 2012
int cMonth = cal.get(Calendar.MONTH);//this is april so you will receive 3 instead of 4.
int cDay = cal.get(Calendar.DAY_OF_MONTH);
int cHour = cal.get(Calendar.HOUR_OF_DAY);
int cMin = cal.get(Calendar.MINUTE);
int cSec = cal.get(Calendar.SECOND);
String name = cYear +"-"+ cMonth +"-"+ cDay +"-"+ cHour +"-"+ cMin +"-"+ cSec +"."+ ext;
// JSON meta-data part
String json = "{\"name\":\""+ name +"\",\"mimeType\":\""+ mimeType +"\",\"parents\":[\""+ Common.slnFldrId +"\"],\"convert\":true}";
String META_PART1 = "--"+ BOUNDARY + LINE_FEED
+ "Content-Type: application/json; charset="+ UTF8 + LINE_FEED + LINE_FEED
+ json + LINE_FEED + LINE_FEED;
// File meta-data part
String META_PART2 = "--"+ BOUNDARY + LINE_FEED
+ "Content-Type: "+ mimeType + LINE_FEED + LINE_FEED;
// Tail
String TAIL = LINE_FEED +"--"+ BOUNDARY +"--";
long contentLength = META_PART1.length() + META_PART2.length() + file.length() + TAIL.length();
// Set up the HttpUrlConnection
url = new URL("https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart");
connection = (HttpURLConnection) url.openConnection();
connection.setReadTimeout(10000);
connection.setConnectTimeout(15000);
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setInstanceFollowRedirects(false);
connection.setRequestProperty("Authorization", "Bearer "+ Common.accessToken);
connection.setRequestProperty("Content-Type", "multipart/related; boundary="+ BOUNDARY);
connection.setRequestProperty("Content-Length", ""+ contentLength);
connection.connect();
// Get the connection's output stream
OutputStream outputStream = connection.getOutputStream();
// Write the META_PART1 (JSON) and flush
outputStream.write(META_PART1.getBytes(UTF8));
outputStream.flush();
// Write the META_PART2 (file's contentType) and flush
outputStream.write(META_PART2.getBytes(UTF8));
outputStream.flush();
// Write the FILE
int totalRead = 0;
int bytesRead = -1;
byte[] buffer = new byte[4096];
FileInputStream inputStream = new FileInputStream(file);
while ((bytesRead = inputStream.read(buffer)) != -1)
{
outputStream.write(buffer, 0, bytesRead);
outputStream.flush();
totalRead += bytesRead;
float progress = totalRead / (float)contentLength;
delegate.onUploadProgress(progress);
}
// Flush the last of the file data and close the inputStream
outputStream.flush();
inputStream.close();
// Flush the TAIL and close the outputStream
outputStream.write(TAIL.getBytes(UTF8));
outputStream.flush();
outputStream.close();
// Get the server response
int responseCode = connection.getResponseCode();
if(responseCode == HTTP_SUCCESS)
{
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = "";
StringBuilder builder = new StringBuilder();
while ((line = reader.readLine()) != null)
{
builder.append(line);
}
// Send the completed message to the delegate
delegate.onUploadComplete(builder.toString(), typeId);
}
else
{
// Send the error message to the delegate
delegate.onUploadError(file);
}
}catch(IOException e)
{
// Send the error message to the delegate
delegate.onUploadError(file);
}finally
{
if(connection != null)
{
connection.disconnect();
}
}
I'm trying to upload some photos taken by an application in a distant database. To be clear :
I take a piture from my app
I send if to a web service (witten in .net, svc file)
The WS upload it in the database
The way i'm doing it : i'm sending the byte[] recovered from the picture that way
String url = MyAddress + "insert_img?login='"
+ login_result + "'&epc='" + code + "'&title='" + t
+ "'&image='" + base64EncodedString + "'&descrip='" + d
+ "'";
BufferedReader inStream = null;
System.out.println(url);
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpR = new HttpGet(url);
httpR.setHeader("Accept", "application/json");
httpR.setHeader("Content-type", "application/json");
HttpResponse response = httpClient.execute(httpR);
My problem is that I have to compress A LOT the picture in order it to be send. The picture, or base64EncodedString field, is created like that :
Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
mImageView.setImageDrawable(null);
mImageView.setImageBitmap(thumbnail);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
thumbnail.compress(Bitmap.CompressFormat.JPEG, 1, baos);
byte[] outputByteArray = baos.toByteArray();
base64EncodedString = Base64.encodeToString(outputByteArray, Base64.NO_WRAP + Base64.URL_SAFE);
As you can see, the image is very very very compressed, and when I recover it it's more or less a 4-colors stamp. And if I do not compress it a lot, image is not inserted.
So first of all : Am I doing it the right way to deal ? And also, why is there no insertion when the picture is too big and how, if possible, to track the error ?
Thanks !
EDIT :
I've modified my code that way, server side :
public string insert_report(Stream stream)
{
string login = "";
string epc = "";
string title = "";
string image = "";
string descrip = "";
MultipartParser parser = new MultipartParser(stream);
Entities entities = new Entities();
string res = "";
if (parser != null && parser.Success)
{
res += parser.Filename;
foreach (var content in parser.MyContents)
{
string name = content.PropertyName;
string str = Encoding.UTF8.GetString(content.Data);
res += "name : " + name +"---";
res += "content : " + str+"---";
if (name.Contains("login"))
{
login = str;
}
if (name.Contains("epc"))
{
epc = str;
}
if (name.Contains("title"))
{
title = str;
}
if (name.Contains("image"))
{
image = str;
}
if (name.Contains("descrip"))
{
descrip = str;
}
}
}
res+= " res returned by server : "+ entities.insert_report(login, epc, title, image, descrip);
entities.SaveChanges();
return res;
}
But there are some problems : the insert_report function return -1... How do I recover the error given by that function ?
Do you receive 414 (Request-URI Too Long) error? You should use HTTP POST method to upload your images as POST body - no Base64 encoding will be also required. Look at https://stackoverflow.com/a/7632849/2714032
I'm trying to make a simple chat server. It works fine on the iphone, but not all the chats are going through on the android.
My idear was to use the http protocol so I can use the standard sfkd on the iphone and android to talk to my server
I'm using the URLConnection connection class on the android.
When I was tacing the code on my server, I noticed that I was getting the length of the post data sent in the header. I'm not setting any length value on the URLConnection class. I figured since I was not setting the size in the header that is why its not working. I could not find any info about this.
code that reads in haeder on my server
I have my server code and android code below,
public int ReadHeader()
{
// read in one line
int PageId=0;
// try{
request = new StringBuffer(1000);
System.out.println("get connection reading in header \r");
//InputStream in = new BufferedInputStream( connection.getInputStream() );
StopFlag=false;
String out;
// the first line shouls have the page
out=ReadLine();
int p;
p=out.lastIndexOf("stop");
if (p!=-1)
PageId=1;
p=out.lastIndexOf("enter");
if (p!=-1)
PageId=2;
p=out.lastIndexOf("add");
if (p!=-1)
PageId=3;
p=out.lastIndexOf("exit");
if (p!=-1)
PageId=4;
p=out.lastIndexOf("update");
if (p!=-1)
PageId=5;
int MessageSize=0;
do{
out=ReadLine();
// check for content size
// GET SIZR OF DATA SENT
if (out.contains("Length"))
{
System.out.println("found length \r");
int pes=out.indexOf(' ');
String Length=out.substring(pes+1);
System.out.println("found size");
System.out.println(Length);
//MessageSize=(int)Length;
MessageSize= Integer.parseInt( Length) ;
//MessageSize=36;
}
} while(out!="finish header" && out!="");
System.out.println("finsih header \r");
ClientMessage=ReadSize(MessageSize);
/*
} catch(IOException ec)
{
System.out.println(ec.getMessage());
}
*/
return PageId;
}
// CODE ON ANDROID
String data = URLEncoder.encode("username", "UTF-8") + "=" + URLEncoder.encode( cGlobals.UserName, "UTF-8"); data += "&" + URLEncoder.encode("comment", "UTF-8") + "=" + URLEncoder.encode( s, "UTF-8");
cGlobals.Message=""; // THIS IS NOT TKING IN ANY INFO ABOUT THE LENGTH OF data URLConnection conn = url.openConnection();
// set timeouts to 5 seconds
// conn.setConnectTimeout(1000*5);
// conn.setReadTimeout(5*1000);
conn.setDoOutput(true);
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(data);
wr.flush();
wr.close();