Skip to content
Advertisement

Different number of bytes when storing images to Android Q vs previous versions

we have a situation that we don’t entirely understand. In our app, the user selects images, which are saved to disc and mapped to their pictures folder. Then when the user is ready to upload the selected images, we use ByteArrayOutputStream to turn them each into a byte array, which is then turned into a string of Hex characters. So far this has worked well, even in areas with low-quality data coverage.

Our process for saving the image to disc (cut down for clarity and generally found here in Stack Overflow) is:

ByteArrayOutputStream bytes = new ByteArrayOutputStream();
            inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
            imageDir = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "temp", null);
            bytes.close();

Since MediaStore.Images.Media.insertImage has been deprecated, we have started looking at code for Android Q and above:

ContentValues values = new ContentValues();
            values.put(MediaStore.Images.Media.DISPLAY_NAME, "location_image.jpg");
            values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
            values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);

            Uri uri = inContext.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

            OutputStream imageOutStream = inContext.getContentResolver().openOutputStream(uri);

            imageDir = String.valueOf( uri );
            Boolean b = inImage.compress(Bitmap.CompressFormat.JPEG, 100, imageOutStream);

            imageOutStream.close();

However, when we use ByteArrayOutputStream to upload images stored with this new process for Q and above, the array is 3-4 as large, which in turn is messing up our data upload process. For example, an image that is stored as 1080×1080 in the old process (<Q) typically has a byte array of around length 380k, while with the new process (>=Q) it swells to 1.4M.

Why is this??

We can reduce JPEG quality in the new process to 80-90%, and will get the same length byte array as the old process.

Advertisement

Answer

Answer provided by @Mike M in above comments.

insertImage always sets quality to 50%, newer code just had to match:

Boolean b = inImage.compress(Bitmap.CompressFormat.JPEG, 50, imageOutStream);

Also best in older (deprecated) code to remove:

inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);

as it had no real function.

And in both cases, certain models running Android 10 can have a problem with non-unique image titles. So it helped to change them to:

"image_" + System.currentTimeMillis()+".jpg"
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement