0

I am working on image upload functionality on Android, I am using these two libraries: https://github.com/natario1/CameraView

https://github.com/gotev/android-upload-service

So, according to CameraView library I can get my picture like that:

mCameraView.addCameraListener(new CameraListener() {
      @Override
      public void onPictureTaken(byte[] jpeg) {
          super.onPictureTaken(jpeg);
      }
});

So I have my picture as byte array. The question here is how can I upload it to my server via multipart? I have my backend ready to accept file. So I believe I have to convert my byte[] to file?

EDIT 1: Sorry for quite unclear question, the question should be narrowed down to "How to write byte[] to file.

yerassyl
  • 2,958
  • 6
  • 42
  • 68

2 Answers2

1

Firstly, You have to store your bytes into file.After storing image to convert in to Multipart

File file = new File(fileUri);
            RequestBody reqFile = RequestBody.create(MediaType.parse("image*//*"), file);
            MultipartBody.Part body =  MultipartBody.Part.createFormData(AppConstants.IMAGE, file.getName(), reqFile);


private File saveImage(byte[] bytes, int rotate) {
        try {
            Bitmap bitmap = decodeSampledBitmapFromResource(bytes, bytes.length, 800, 600, rotate);

            return createFile(bitmap);
        } catch (Exception e) {
            Log.e("Picture", "Exception in photoCallback", e);
        }
        return null;
    }

    public Bitmap decodeSampledBitmapFromResource(byte[] bytes, int length, int reqWidth,
                                                  int reqHeight, int rotate) {

        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeByteArray(bytes, 0, length, options);
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
        options.inJustDecodeBounds = false;
        Bitmap bm = BitmapFactory.decodeByteArray(bytes, 0, length, options);
        Bitmap rotatedBitmap = null;
        if (isFrontfaceing) {
            if (rotate == 90 || rotate == 270) {
                rotatedBitmap = rotateImage(bm, -rotate);
            } else {
                rotatedBitmap = rotateImage(bm, rotate);
            }
        } else {
            rotatedBitmap = rotateImage(bm, rotate);
        }
        rotatedBitmap = Bitmap.createScaledBitmap(rotatedBitmap, reqWidth, reqHeight, true);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        rotatedBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
        return rotatedBitmap;
    }

    public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth,
                                     int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    || (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }


 public File createFile(Bitmap bitmap) {
    File photo =
            new File(getWorkingDirectory().getAbsolutePath()+"yourFileName" + ".jpg");
    FileOutputStream fos = null;
    try {
        fos = new FileOutputStream(photo.getPath());
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
        fos.close();
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
    return photo;
}
himangi
  • 788
  • 4
  • 9
  • Why should that jpg be converted to a bitmap first? And resized? And rotated? What a lot of not needed code. You should directly write those bytes to file without using an intermediate bitmap. – greenapps May 25 '18 at 09:21
  • yes...Thats what I was used for resize my image.You can directly save you bytes to file – himangi May 25 '18 at 09:27
  • @himangi, thanks for answer, it helped me a lot to solve my problem. Basically I think the scope of my question is quite wrong, what I needed is just to learn how to write byte[] to file, which is fairly simple) – yerassyl May 25 '18 at 10:42
0

Basically what we need is to just write our byte[] to file. First of all I create placeholder file for that. Here is the code snipped for that taken from official google documentation (https://developer.android.com/training/camera/photobasics#TaskPhotoView)

    private File createImageFile() throws IOException {
        // Create an image file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        File image = File.createTempFile(
                imageFileName,
                ".jpg",
                storageDir
        );
        
        return image;
    }

Then I write my byte[] to that file.

    try {
       File photoFile = createImageFile();
       FileOutputStream fos = new FileOutputStream(photoFile.getPath());
       fos.write(jpeg);
       // then call uploadImage method and pass aboslutePath of my file
       uploadImage(photoFile.getAbsolutePath());
       } catch (IOException e) {}

uploadImage method handles upload according to android-upload-service: https://github.com/gotev/android-upload-service

yerassyl
  • 2,958
  • 6
  • 42
  • 68
  • `First of all I create placeholder file for that.`. No good. Dont use File.createTempFile(). The file will be created by new FileOutputStream. You only need a file name/path. – greenapps May 25 '18 at 11:43
  • @greenapps actually there is no need for writing to any temporary file - you just have to pass a custom `RequestBody` class accepting your byte array and override `contentType` and `writeTo` methods – pskink May 25 '18 at 19:01
  • @pskink please tell OP. He could use it. You could also post it as an answer. – greenapps May 25 '18 at 19:12
  • @greenapps OP already said: `"thanks for answer, it helped me a lot to solve my problem. Basically I think the scope of my question is quite wrong, what I needed is just to learn how to write byte[] to file, which is fairly simple)"` so i dont think that i could change his mind (but i think i could change your if you need to do such thing in the future) – pskink May 25 '18 at 19:14
  • @pskink Very funny. You probably did not see my first comment: `Just use HttpUrlConnection to post the bytes to the server. You dont need to create a file first`. Indeed... I could have posted that as an answer too ;-). – greenapps May 25 '18 at 19:43
  • @greenapps i so decide what you are proposing as i see: `"You should directly write those bytes to file without using an intermediate bitmap."` - dont you think that using raw `HttpUrlConnection` is a bit of overkill when you have something like `okhttp`? – pskink May 25 '18 at 19:48
  • @pskink Indeed. If one would want to write bytes to file then do it directly. Without a bitmap. Please dont mix that up with what i want. I dont want to write to file to begin with. – greenapps May 25 '18 at 19:51
  • @pskink I did not know that okhttp accepted bytes. Why did you not post that as an answer? Nobody knows! Moreover i did those things with HttpClient and then HttpUrlConnection before all those libraries came in. – greenapps May 25 '18 at 19:54
  • @greenapps of course nobody knows since the default `RequestBody` implementation uses `File` as input - see: https://github.com/square/okhttp/blob/master/okhttp/src/main/java/okhttp3/RequestBody.java#L104 but writing a custom `RequestBody` that writes `byte[]` to `BufferedSink sink` in `writeTo` method is as easy as using [this](https://square.github.io/okio/1.x/okio/okio/BufferedSink.html#write-byte:A-) method - the docs say: *Like OutputStream.write(byte[]), this writes a complete byte array to this sink.* – pskink May 25 '18 at 19:58
  • @greenapps btw i just found [this](https://github.com/square/okhttp/blob/master/okhttp/src/main/java/okhttp3/RequestBody.java#L79) - probably it was added in new version of `okhttp` - i dont know – pskink May 25 '18 at 20:17
  • @pskink. Nice to know. Next time post as answer please. ;-). – greenapps May 25 '18 at 20:18