7

I'm trying to calculate the remaining number of photos that can be taken using my custom camera and show that count to the user. I tried with the following code:

private void numberOfPhotosAvailable() {
        long photosAvailable = 0;
        StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
        resolution=getResolution();
        long bytesPerPhoto=resolution/1048576;
        long bytesAvailable = (long) stat.getAvailableBlocksLong() * (long) stat.getBlockSizeLong();
        long megAvailable = bytesAvailable / 1048576;

        System.out.println("Megs :" + megAvailable);
        photosAvailable = megAvailable / bytesPerPhoto;
        tvAvailablePhotos.setText("" + photosAvailable);
    }

Method for getting resolution.

public long getResolution(){
        long resolution=0;
        Camera.Parameters params=mCamera.getParameters();
        List<Camera.Size> sizes = params.getSupportedPictureSizes();

        Camera.Size size = sizes.get(0);
        int width=size.width;
        int height=size.height;
        resolution=width*height;
       return resolution;
    }

PROBLEM: There is a lot of difference in the count shown in the phone's camera and count that is shown in my app.

So what is the proper way of doing this ?

NOTE: I will only be capturing image in the highest quality available. Therefore I am only calculating count according to one resolution only.

Vivek Mishra
  • 5,669
  • 9
  • 46
  • 84
  • Why would you assume that a photo is going to be 7MB? Those are compressed files. Depending on the data actually captured it could be far less or far more. And that's assuming you don't hit vendor specific per application max storage limits. And you're assuming that all cameras take photos in the same resolution, which is not the case. – Gabe Sechan Sep 14 '17 at 18:25
  • That's why I am asking what is the correct way for doing the calculation. I know above code will not be working for other devices. – Vivek Mishra Sep 15 '17 at 01:53
  • @GabeSechan now check. I am now using a dynamic approach for calculations. – Vivek Mishra Sep 15 '17 at 06:35
  • I also develop a custom camera and would go this direction: when the app launches I would assume that the photo file would roughly take 4 (5? 6?) MB - whatever and let the user know ho many images are remaining in this case. At the same time I would start a low-priority thread that creates a bitmap with randomly colored pixels, with the resolution of your images, writes it to the File System and reads its actual size. After this I would update the number of the remaining images for the user. If you want to be more precise, in the course of the app operation take into account new files. – rommex Sep 20 '17 at 11:40

4 Answers4

4

It is impossible to find the exact size of the output image for JPEG/PNG compression. The compression algorithms are optimized in such a way that they use as less size as possible but preserve the image pixels (although JPEG is slightly lossy).

However, you can estimate the no of images by taking multiple sample photos and calculating the average compression ratio.

From Wikipedia:

JPEG typically achieves 10:1 compression with little perceptible loss in image quality.

So estimated storage size can be calculated as:

int bytes = width * height * 2 / compressionRatio;

Here it is multiplied by 2 because in RGB_565 config, it requires 2 bytes to store 1 pixel.

Nabin Bhandari
  • 15,949
  • 6
  • 45
  • 59
  • How I would get the compression ratio. I think it will too wary from phone to phone – Vivek Mishra Sep 17 '17 at 10:37
  • Yes it will vary from phone to phone, that's why you should consider an average value. Not only from phone to phone, it also varies from photo to photo even in a single phone. You can calculate compression ratio for multiple samples and average them, or search for other's result in google. – Nabin Bhandari Sep 17 '17 at 10:42
  • How do I get compression ratio from photos programmaticlly ? – Vivek Mishra Sep 17 '17 at 10:44
  • Your formulas for calculating compression ratio and bytes are giving really huge numbers in results. I have image of 3744X5376 resolution. – Vivek Mishra Sep 17 '17 at 10:55
  • Yes, it will be huge, because it is in bytes. Use this formula: `float compressionRatio = (width * height * 2) / fileSizeInBytes;` – Nabin Bhandari Sep 17 '17 at 10:57
  • It still gives wrong results . I am getting 110 mb as a result for bytes formula that you have given in the answer – Vivek Mishra Sep 17 '17 at 11:04
  • For my case, I have a photo of size 2560 x 1920 saved in a file of 1.11MB. So the compression ratio would be (2560*1920*2)/(1.11*1024*1024) = 8.44 – Nabin Bhandari Sep 17 '17 at 11:10
2

I think that there is no ultimate solution for images left because there are too much different devices and cameras and also it depends heavily on image content.

One good explanation for that I have found here

As suggested before you can predict image size and calculate images count left based on a device free space. To get that prediction best solution is to try it on your device first. After user starts using the app, you can include his last 10 photo sizes in calculation. If it is not a key feature you can just present it as prediction based on usage, not as a binding fact.

P.S I am using Samsung Galaxy S7 edge and there is no images left count in camera at all. (Or I am just unable to find it)

Matej Vukosav
  • 666
  • 8
  • 12
2

Well after lot of researching and googling, I came to this site.

According to this site, following are the steps to get the file size.

  1. Multiply the detectors number of horizontal pixels by the number of vertical pixels to get the total number of pixels of the detector.
  2. Multiply total number of pixels by the bit depth of the detector (16 bit, 14 bit etc.) to get the total number of bits of data.
  3. Dividing the total number of bits by 8 equals the file size in bytes.
  4. Divide the number of bytes by 1024 to get the file size in kilobytes. Divide by 1024 again and get the file size in megabytes.

So when I followed the above steps, i.e. my detectors resolution is 5376X3024. Proceeding with the above steps I finally got 39 MB as answer for image size.

But the image taken by camera was around 8-10 MB in size which was still not close to what I got in result above.

My phone (HTC Desire 10 pro) has a pro mode settings available. In this mode photos are captured as raw images. So when I checked for the size of the captured raw image, I was amused as the size of the raw file was indeed around 39 MB, which states that above steps are correct for calculating image's original size.

CONCLUSION

With the above steps I came to the conclusion that phone's softwares indeed use some compression algorithms to make image size less. So what I was comparing to was actually compressed images hence the count of images was different.

PROBABLE SOLUTION

The approach that I am now aiming is to get the last clicked image from my camera, get its file size and show count according to that file size. This will also be a approximate result but I don't think there can be any solution for getting exact count.

This is the code I am using to implement the above solution

private void numberOfPhotosAvailable() {
    long photosAvailable = 0;
    StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
    File lastFile=null;
    lastFile=utils.getLatestFilefromDir(prefManager.getString(PrefrenceConstants.STORAGE_PATH));
    if (lastFile!=null){
        double fileSize=(lastFile.length())/(1024*1024);
        long bytesAvailable = (long) stat.getAvailableBlocksLong() * (long) stat.getBlockSizeLong();
        long megAvailable = bytesAvailable / 1048576;

        System.out.println("Megs :" + megAvailable);
        photosAvailable = (long) (megAvailable / fileSize);
        tvAvailablePhotos.setText("" + photosAvailable);
    }else{
        tvAvailablePhotos.setVisibility(View.INVISIBLE);
    }

}
Vivek Mishra
  • 5,669
  • 9
  • 46
  • 84
  • Of course JPEG files are compressed. You specify the level of compression by the setJpegQuality(int) method. I ususally use it in the range 70-90 to keep high quality of images while substantially reducing their size. – rommex Sep 20 '17 at 11:43
  • @rommex didn't understood what you mean by the comment ? – Vivek Mishra Sep 20 '17 at 12:48
  • Basically, I was saying that you _cannot_ predict the size of an image file if you are using non-raw formats. Such formats use compression. – rommex Sep 20 '17 at 19:03
2

I think you can check the DCIM directory(Default Camera Directory) for the number of files and calculate the size of all the files and get the average size by dividing the number of files.

and you will get the average size camera is capturing the images do above steps in Asynctask.

and you already calculated the remaining size in bytes now divide again the remaining size with the average size and you will get the approx number of images you can capture.

Harvinder Singh
  • 1,919
  • 21
  • 15