0

I have made image compression long ago. It was working well until Android X, but above Android it’s not working.

public class ImageCompress {

    private static final int IMAGE_QUALITY = 99;
    private static final int MAX_SIZE_PIXELS = 1200;

    public static Bitmap decodeFile(File file, int width, int height) {
        try {
            // Decode image size
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(new FileInputStream(file), null, options);

            // The new size we want to scale to
            final int REQUIRED_WIDTH = width;
            final int REQUIRED_HIGHT = height;

            // Find the correct scale value. It should be the power of 2.
            int scale = 1;
            while (options.outWidth / scale / 2 >= REQUIRED_WIDTH
                    && options.outHeight / scale / 2 >= REQUIRED_HIGHT)
                scale *= 2;

            // Decode with inSampleSize
            BitmapFactory.Options newOptions = new BitmapFactory.Options();
            newOptions.inSampleSize = scale;
            return BitmapFactory.decodeStream(new FileInputStream(file), null, newOptions);

        } catch (FileNotFoundException e) {
            return null;
        }
    }

    public static File compressImage(final File file, String outputDirectory, Context context) {
        String path = file.getPath();
        String format = path.substring(path.lastIndexOf(".")).substring(1);
        Bitmap source;
        try {
            source = decodeFile(file, MAX_SIZE_PIXELS, MAX_SIZE_PIXELS);
        } catch (Exception e) {
            Log.d(ImageCompress.class.toString(), e.toString() + " Something happened wrong");
            return null;
        }

        Bitmap.CompressFormat compressFormat;

        // If PNG or WebP have the allowed resolution, then do not compress it
        if ("png".equals(format) || "webp".equals(format)) return file;

        // Select format
        switch (format) {
            case "png":
                compressFormat = Bitmap.CompressFormat.PNG;
                break;
            case "webp":
                compressFormat = Bitmap.CompressFormat.WEBP;
                break;
            case "gif":
                return file;
            default:
                compressFormat = Bitmap.CompressFormat.JPEG;
        }

        // Resize image
        Bitmap resizedBmp;
    // I am getting an error on the source.getHeight() line
        if (source.getHeight() > MAX_SIZE_PIXELS || source.getWidth() > MAX_SIZE_PIXELS) {
            resizedBmp = resizeBitmap(source, MAX_SIZE_PIXELS);
        } else {
            resizedBmp = source;
        }
        File result = null;
        OutputStream fOut = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            ContentResolver resolver = BaseApplication.getInstance().getContentResolver();
            ContentValues contentValues = new ContentValues();
            contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, file.getName());
            contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/" + format);
            contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Constants.MULTIMEDIA_CHATROOM_11);
            Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
            try {
                fOut = resolver.openOutputStream(imageUri);
                result = new File(Utils.getPath(BaseApplication.getInstance(), imageUri));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        } else {
            // create directory if not exist
            File directory = new File(outputDirectory);
            int code = context.getPackageManager().checkPermission(
                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    context.getPackageName());
            if (code == PackageManager.PERMISSION_GRANTED) {
                Log.i(ImageCompress.class.getSimpleName(), "creating directory");
                if (!directory.isDirectory() || !directory.exists()) {
                    directory.mkdirs();
                }
            } else {
                Log.i(ImageCompress.class.getSimpleName(), "failed access");
            }

            // Compress image
            result = new File(outputDirectory, file.getName());

            try {
                if (!result.exists()) {
                    result.createNewFile();
                    fOut = new FileOutputStream(result);
                } else {
                    fOut = new FileOutputStream(result);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            resizedBmp.compress(compressFormat, IMAGE_QUALITY, fOut);
            fOut.flush();
            fOut.close();
            source.recycle();
            resizedBmp.recycle();

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

        // Copy EXIF orientation from the original image
        try {
            ExifInterface oldExif = new ExifInterface(file.getPath());
            String exifOrientation = oldExif.getAttribute(ExifInterface.TAG_ORIENTATION);
            if (exifOrientation != null) {
                ExifInterface newExif = new ExifInterface(result.getPath());
                newExif.setAttribute(ExifInterface.TAG_ORIENTATION, exifOrientation);
                newExif.saveAttributes();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    private static Bitmap resizeBitmap(Bitmap source, int maxSizePixels) {
        int targetWidth, targetHeight;
        double aspectRatio;

        if (source.getWidth() > source.getHeight()) {
            targetWidth = maxSizePixels;
            aspectRatio = (double) source.getHeight() / (double) source.getWidth();
            targetHeight = (int) (targetWidth * aspectRatio);
        } else {
            targetHeight = maxSizePixels;
            aspectRatio = (double) source.getWidth() / (double) source.getHeight();
            targetWidth = (int) (targetHeight * aspectRatio);
        }

        return Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
    }
}

My app is made for social entertainment purposes, so I don't have storage access like before due to policies. So we can use only the session scope way to access files. I am getting an error at line source.getHeight() and source.getWidth() as both are zero. How can I fix this this issue for all Android versions?

Error:

Getting error

Please note: I noticed this error comes in a few pictures from the gallery.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • Please describe in detail what "not working" means. What errors does it cause? – Robert Jul 03 '23 at 20:30
  • Hi, robert I mentioned comment in code already. the comment is "//getting error on source.getHeight() line" basically we can do only media query to fetch image if want to publish app in playstore. the source.getHeight() returning 0. – DEEPAK MAURYA Jul 04 '23 at 03:18
  • What error do you get? Do you simply get 0 as return value or an exception? If you get an exception please include the full output into your question (not in comments!). – Robert Jul 04 '23 at 07:16
  • @Robert done sir. and am very glad that you are trying to helping me. – DEEPAK MAURYA Jul 04 '23 at 08:54
  • Please never paste stack traces as image into question. Just copy & paste the text. Fro what I see the most likely error is that you run into the catch block `FileNotFoundException` in `decodeFile`. Thus the return value is null and so `source` becomes `null`. => never catch an Exception and return null if your code can not handle this. So I assume your error is you try to load a non-existant file. – Robert Jul 04 '23 at 10:00
  • @Robert Thank you so much sir for writing again. Yes you are correct about FileNotFoundException I diagnose that permission was denied. so I check what permissions are restricted I found photos and videos permission was denied in my samsung phone. so finally figure out because of you. now I need to know what is minimum api level which need these special permissions (images and videos, music and audio). Also I request you to write in answer so I can mark it as answer sir. – DEEPAK MAURYA Jul 04 '23 at 12:03
  • Please review *[Why not upload images of code/errors when asking a question?](https://meta.stackoverflow.com/questions/285551/)* (e.g., *"Images should only be used to illustrate problems that* ***can't be made clear in any other way,*** *such as to provide screenshots of a user interface."*) and [do the right thing](https://stackoverflow.com/posts/76605043/edit). Thanks in advance. – Peter Mortensen Jul 29 '23 at 00:35

2 Answers2

1

If you get a NullPointerException on source.getHeight() then this means source has been set to null.

The only point where sourceis set is on the line

source = decodeFile(file, MAX_SIZE_PIXELS, MAX_SIZE_PIXELS);

This means the method decodeFile has to return a null value.

Looking at the method decodeFile you can see tha there are only two different code paths that return a value. The first code path returns the value of BitmapFactory.decodeStream(..) which AFAIK should never return null.

The it is most likely the other code path in the FileNotFoundException catch clause.

public static Bitmap decodeFile(File file, int width, int height) {
    try {
        ....
        return BitmapFactory.decodeStream(new FileInputStream(file), null, newOptions);

    } catch (FileNotFoundException e) {
        return null;
    }
}

This leads to the conclusion that at some point you are trying to read a File that does not exist or on that you don't have read permissions.

As your app is older the chance is high that if it is a permission problem and the file is on the shared storage (/sdcard or subfolder) this is because the app does not make use of scoped storage system introduced with Android 10/11.

Robert
  • 39,162
  • 17
  • 99
  • 152
-2
public File compressImage(File fileimage) {
  Bitmap icon = BitmapFactory.decodeFile(String.valueOf(fileimage));
  ByteArrayOutputStream bytes = new ByteArrayOutputStream();
  icon.compress(Bitmap.CompressFormat.JPEG, 70, bytes);
  String folder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS + "/" + "Images") + "/";
  File directory = new File(folder);
  if (!directory.exists()) {
    directory.mkdirs();
  }
  File f = new File(folder + System.currentTimeMillis() + ".jpg");
  try {
    f.createNewFile();
    FileOutputStream fo = new FileOutputStream(f);
    fo.write(bytes.toByteArray());
  } catch (IOException e) {
    e.printStackTrace();
  }
  return f;
}
Tyler2P
  • 2,324
  • 26
  • 22
  • 31
  • Your answer could be improved by adding more information on what the code does and how it helps the OP. – Tyler2P Jul 05 '23 at 20:16