Retrieve the shutter count of DSLR cameras easily with this Python 3 script

The shutter count in DSLR cameras is what the odometer is for cars. Use this simple Python 3 script to quickly find out the current "milage" if your camera.

So, I’m into photography, and I like to keep an eye on the shutter count of my camera. It’s a vital metric: The higher it gets, the more likely it is to start causing problems.

My Nikon D850 is supposed to be good for 200,000 shots, but I’ve seen cameras that have way exceeded that and still work fine. However, I’m not planning on selling mine anytime soon, but I wanted a quick way to check the count using just a raw photo from the camera as a CLI (Command-Line Interface).

The Python package exifread gives access to that number, even though some customization is still required because the EXIF (Exchangeable Image File Format) parameters for the shutter count aren’t always the same.

So, I’ve created a Python script to tackle this and turned it into a handy CLI tool. Head over to the post to grab the entire code, complete with plenty of comments to walk you through every step, or clone the git repository.

Overview

This is not a documentation. For a thorough documentation, please see the README.md file inside the repository on GitLab or GitHub.

Installation

To use my Python Shutter Count CLI, you can clone the repository:

git clone https://gitlab.com/thaikolja/python-shutter-counter.git

If you only want the files without the Git commits baked in, you can also download it as a .zip file.

Usage

Use the CLI either as a local tool for your command line. The easiest way to do this is by creating a Bash alias in your .zshrc (macOS) or .bashrc (Linux) file:

alias shuttercounter="python3 /absolute/path/to/main.py"

After that, you can simply run shuttercounter path/to/image.jpg in your terminal to display the total shutter count of the camera with which the image was taken. Run shuttercounter --help for the list of available arguments.

Code

from exifread import process_file
from logging import basicConfig, warning, ERROR, error
from sys import exit, version_info, argv

# Set the logging level to ERROR
basicConfig(level=ERROR)


class ShutterCounter:
    """
    A class used to represent a Shutter Counter

    Attributes
    ----------
    image_path : str
        a formatted string to print out the path where the image is located
    shutter_tag : str
        a string representing the shutter tag (default is 'MakerNote TotalShutterReleases')
    supported_models : list
        a list containing the supported camera models (default is ['NIKON D850', 'NIKON D810', 'NIKON D800'])

    Methods
    -------
    get_shutter_count(output_type: int or str = 'int') -> int or str or None:
        Returns the shutter count of the image if possible, else returns None
    """

    def __init__(self, image_path, shutter_tag='MakerNote TotalShutterReleases'):
        """
        Constructs all the necessary attributes for the ShutterCounter object.

        Parameters
        ----------
            image_path : str
                the path where the image is located
            shutter_tag : str
                the shutter tag (default is 'MakerNote TotalShutterReleases')
        """

        self.image_path = image_path
        self.shutter_tag = shutter_tag
        self.supported_models = [
            'NIKON D850',
            'NIKON D810',
            'NIKON D800'
        ]

    def get_shutter_count(self, output_type: int or str = 'int') -> int or str or None:
        """
        Returns the shutter count of the image if possible, else returns None

        Parameters
        ----------
            output_type : int or str
                the type of the output (default is 'int')

        Returns
        -------
            int or str or None
                the shutter count if possible, else None
        """

        try:
            with open(self.image_path, 'rb') as file:
                tags = process_file(file)
                camera_model = str(tags['Image Model'])

                if camera_model not in self.supported_models:
                    error(f" Your camera model {camera_model} is currently not supported.")
                    exit(1)

                if self.shutter_tag in tags:
                    shutter_count_str = str(tags[self.shutter_tag])

                    try:
                        output = str(f"Shutter count: {shutter_count_str}")

                        if len(argv) > 2 and argv[2] == 'int':
                            output = int(shutter_count_str)

                        return output

                    except ValueError:
                        error(f" Could not convert shutter count to ${output_type}: {shutter_count_str}")
                        exit(1)
                else:
                    warning(f" The shutter count could not be found in the EXIF data.")
                    exit(1)

        except (FileNotFoundError, IOError):
            error(f" Could not find or open the image file: {self.image_path}")
            exit(1)


# Main execution
if __name__ == "__main__":
    result_type = 'int'

    # Check if the image path is provided as an argument
    if len(argv) < 2:
        print('Please provide an image path as an argument.')
        exit(1)

    # Check if the result type is provided as an argument
    if len(argv) > 2 and argv[2] == 'str':
        result_type = argv[2]

    # Check if help is requested
    if argv[1] == '-h' or argv[1] == '--help':
        print('Usage: python main.py <image_path> (int|str)')
        exit(1)

    # Check if the Python version is 3 or above
    if version_info[0] < 3:
        error(" This script requires Python 3.")
        exit(1)

    # Create a ShutterCounter object
    counter = ShutterCounter(argv[1])

    # Get the shutter count
    shutter_count = counter.get_shutter_count()

    # Print the shutter count
    print(shutter_count)

Feel free to collaborate or create pull requests by creating a fork if you think you can improve this little tool!