Search code examples
androidandroid-studioibm-watsonvisual-recognition

Watson Visual Recognition error "Invalid image data. Supported formats are JPG, PNG, and GIF" when uploading image from Android Studio


I have been wrecking my brain over this for a while and would really appreciate if someone who have some insight into this problem could help me out!

I am trying to upload an image to Watson's Visual Recognition API using POST from Android Studio (by taking a picture using a camera).

I have managed to - save image after taking a picture with a camera - show it as a bitmap image on the app

and I am trying to upload the file to the Watson API, but I keep getting this error

"description": "Invalid image data. Supported formats are JPG, PNG, and GIF."

I would really appreciate if anyone could provide some insight to what I am doing wrong here. Thanks in advance!

I am using HttpUrlConnection and DataOutputStream to POST right now and the code is as follows:

imgName and imgPath are all correctly identified, and name="images_file" is how Watson Visual Recognition API requests name to be

public void uploadImage(){
    HttpURLConnection conn = null;
    DataOutputStream dos = null;
    String lineEnd = "\r\n";
    String twoHyphens = "--";
    String boundary = "*****";
    int bytesRead, bytesAvailable, bufferSize;
    byte[] buffer;
    int maxBufferSize = 1 * 1024 * 1024;
    try{

        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();

        StrictMode.setThreadPolicy(policy);

        URL url = new URL("https://gateway-a.watsonplatform.net/visual-recognition/api/v3/classify?api_key=APIKEY&version=2016-05-20");
        conn= (HttpURLConnection) url.openConnection();
        FileInputStream fileInputStream = new FileInputStream(file);
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Connection", "Keep-Alive");
        conn.setRequestProperty("ENCTYPE", "multipart/form-data");
        conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
        conn.setRequestProperty("images_file", imgPath);

        dos = new DataOutputStream(conn.getOutputStream());

        dos.writeBytes(twoHyphens + boundary + lineEnd);
        dos.writeBytes("Content-Disposition: form-data; name=\"images_file\"; filename = \"" + imgName + "\"" + lineEnd);
        dos.writeBytes(lineEnd);


        bytesAvailable = fileInputStream.available();
        bufferSize = Math.min(bytesAvailable, maxBufferSize);
        buffer = new byte[bufferSize];

        bytesRead = fileInputStream.read(buffer, 0, bufferSize);
        while (bytesRead > 0) {

            dos.write(buffer, 0, bufferSize);
            bytesAvailable = fileInputStream.available();
            bufferSize = Math.min(bytesAvailable, maxBufferSize);
            bytesRead = fileInputStream.read(buffer, 0, bufferSize);

        }

        // send multipart form data necesssary after file data...
        dos.writeBytes(lineEnd);
        dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

        // Responses from the server (code and message)
        serverResponseCode = conn.getResponseCode();
        String serverResponseMessage = conn.getResponseMessage();

        Log.i("uploadFile", "HTTP Response is : "
                + serverResponseMessage + ": " + serverResponseCode);

        if(serverResponseCode == 200){

            BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
            StringBuilder sb = new StringBuilder();
            String output;
            while ((output = br.readLine()) !=null) {
                sb.append(output);
            }
            Log.d("debugging", sb.toString());

            runOnUiThread(new Runnable() {
                public void run() {

                    String msg = "File Upload Completed.\n\n See uploaded file here : \n\n"
                            +" http://www.androidexample.com/media/uploads/"
                            +imgName;


                    Toast.makeText(getApplicationContext(), "File Upload Complete.",
                            Toast.LENGTH_SHORT).show();


                }
            });
        }

        //close the streams //
        fileInputStream.close();
        dos.flush();
        dos.close();

    } catch (MalformedURLException ex) {

        ex.printStackTrace();

        runOnUiThread(new Runnable() {
            public void run() {
                Toast.makeText(getApplicationContext(), "MalformedURLException",
                        Toast.LENGTH_SHORT).show();
            }
        });

        Log.e("Upload file to server", "error: " + ex.getMessage(), ex);
    } catch (Exception e) {

        e.printStackTrace();

        runOnUiThread(new Runnable() {
            public void run() {
                Toast.makeText(getApplicationContext(), "Got Exception : see logcat ",
                        Toast.LENGTH_SHORT).show();
            }
        });
        Log.e("Debugging", "Exception : "
                + e.getMessage(), e);
    }
    Log.d("Debugging", "responseCode:" + serverResponseCode);
}

Solution

  • Visual Recognition has an SDK(client library) in Java. You just need to add the dependency to your build.gradle.

      compile 'com.ibm.watson.developer_cloud:java-sdk:3.2.0'
    

    Then

    VisualRecognition service = new VisualRecognition(VisualRecognition.VERSION_DATE_2016_05_20);
    service.setApiKey("<api-key>");
    
    ClassifyImagesOptions options = new ClassifyImagesOptions.Builder()
      .images(new File("car.png"))
      .build();
    
    VisualClassification result = service.classify(options)
      .enqueue(new ServiceCallback<List<Dialog>>() {
          @Override
          public void onResponse(List<Dialog> response) {
            System.out.println(response);
          }
    
          @Override
          public void onFailure(Exception e) {
          // on failure
          }}
      );
    

    This example has a CameraHelper class with utility methods to get the file path or InputStream of a picture in Android.