A 35mm film camera represented in Python object

D.M. Procida real-not-anti-spam-address at apple-juice.co.uk
Sun Mar 7 05:19:34 EST 2021


Hi everyone, I've created <https://github.com/evildmp/C-is-for-Camera> -
a representation of a Canonet G-III QL17 in Python.

There's also documentation: <https://c-is-for-camera.readthedocs.io>.

It's a pure Python model of the physical sub-systems of a camera and
their interactions. So far it's at a fairly high level - I haven't yet
got down to the level of individual springs and levers yet.

I spend quite a bit of my time repairing old cameras. To me they feel
like computer programs encoded into physical objects, and figuring out
how a mechanism works feels like working out how code works (but more
fun).

The Canonet G-III QL17 is one of my favourites. One of my reasons for
writing this code is to appreciate the intricate mechanical logic
embodied in the machine.

You can do things like advance the film, release the shutter, meter the
scene with the built-in light meter (if the camera has a battery of
course) and even spoil your film if you make the mistake of opening the
back in daylight.

    >>> from camera import Camera
    >>> c = Camera()

    >>> c.state()
    ================== Camera state =================

    ------------------ Controls ---------------------
    Selected speed:            1/120

    ------------------ Mechanical -------------------
    Back closed:               True
    Lens cap on:               False
    Film advance mechanism:    False
    Frame counter:             0
    Shutter cocked:            False
    Shutter timer:             1/128 seconds
    Iris aperture:             ƒ/16
    Camera exposure settings:  15.0 EV

    ------------------ Metering ---------------------
    Light meter reading:        4096 cd/m^2
    Exposure target:            15.0 EV
    Mode:                       Shutter priority
    Battery:                    1.44 V
    Film speed:                 100 ISO

    ------------------ Film -------------------------
    Speed:                      100 ISO
    Rewound into cartridge:     False
    Exposed frames:             0 (of 24)
    Ruined:                     False

    ------------------ Environment ------------------
    Scene luminosity:           4096 cd/m^2

    >>> c.film_advance_mechanism.advance()
    Cocking shutter
    Cocked

    >>> c.shutter.trip()
    Shutter opens
    Shutter closes
    Shutter opened for 1/128 seconds
    Shutter uncocked

You can't do impossible things:

    >>> c.shutter_speed = 1/33
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/Users/daniele/Repositories/camera/camera.py", line 29, in 
        shutter_speed
        raise self.NonExistentShutterSpeed(f"Possible shutter speeds are
          {possible_settings}")
    camera.NonExistentShutterSpeed: Possible shutter speeds are 1/4, 
      1/8, 1/15, 1/30, 1/60, 1/120, 1/240, 1/500

But you can also do things that you shouldn't do, like opening the back
of the camera in daylight with a partially-exposed roll of film inside -
which will spoil the film::

    >>> c.back.open()
    Opening back
    Resetting frame counter to 0
    'Film is ruined'

I hope this interesting to someone.

Daniele


More information about the Python-list mailing list