DNG Module and Workflow

Note

While, between the DNG and LJPEG modules, much of the functionality exists which is required to edit the underlying raw data, this functionality has not yet been fully stitched together to make it fully operational. This will likely happen either when the primary developer has a need for this or when someone reaches out requesting it.

The DNG module allows DNG images to be read, rendered, edited, updated, and saved. Like with most other digital image technology, the top left corner of the image is the origin.

Usage

Example: Getting the top left quarter of the raw image

In this example, a piece of the total image is rendered and returned. Since the area to render is input at [0, 0, 0.5, 0.5], the rendered portion is from the top left corner to the center of the image.

from brilliantimagery.dng import DNG

dng = DNG('path/to/dng.dng')

image = dng.get_image([0, 0, 0.5, 0.5], 'RAW')

Example: Get, update, and save XMP data

When the below code it run:

from brilliantbmagery.dng import DNG

dng = DNG('path/to/dng.dng')

val = dng.get_xmp_attribute(b'xmp:attr')

print(f'Was: {val}')

val += 5

print(f'Is: {val}')

dng.set_xmp_attribute(b'xmp:attr', val)
dng.store_xmp_field()
dng.save()

val = dng.get_xmp_attribute(b'xmp:attr')

print(f'Is still: {val}')

The below lines would be printed assuming the xmp:attr attribute started with a value of 5.5.

Was: 5.5
Is: 10.5
Is still: 10.5

API

class brilliantimagery.dng.DNG(path: str)

A representation of a DNG image file.

Allows reading and editing the underlying file.

It’s based on the DNG 1.4 standard and works for most cameras by most manufacturers but the standard is not fully implemented and not all edge cases for older versions of the standard are fully supported.

Parameters

path (str) – The path to the represented DNG file.

get_brightness(rectangle=None, image=None)

Gets a reference brightness value for the image.

The median green value for the image is used as the reference.

Parameters
  • rectangle (list[int or float]) –

    The bounding box of the portion of the image that’s to be rendered. In the format X1, Y1, X2, Y2 where:

    • X1 is the x position of the top left corner,

    • Y1 is the y position of the top left corner,

    • X2 is the x position of the bottom right corner,

    • Y2 is the y position of the top right corner.

    The input values can either be in fractions of the way across the image from the origin, or pixels from the origin. The top left corner of the cropped area is assumed to be the origin. If no crop is applied by the user than the DefaultCropOrigin field data is used as the origin.

  • image (Numpy.ndarray) –

    A 3D float array holding the rendered image.

    • The first dimension represents the color channels: Red, Green, Blue at indices 0, 1, and 2 respectively.

    • The second represents the width.

    • The third represents the height.

Returns

The median green value from the image as a float in the range from 0 to 1.

Return type

float

get_capture_datetime() → str

Gets when the image was captured.

The return value may be formatted as a datetime or unix time stamp depending on the available information. The format should be consistent between images captured on the same camera and processed with the same workflow.

Returns

A creation time.

Return type

str

get_default_shape() → List[int]

Gets the dimensions of the raw image, before it’s edited or cropped.

Dimensions are in units of pixels.

Returns

A list of ints where the first is the width and the second is the length (height) of the image.

Return type

list[int, int]

get_image(rectangle=[0.0, 0.0, 1.0, 1.0], sub_image_type='RAW') → numpy.ndarray

Get the desired portion of the desired reference image.

No transforms such as white balancing or exposure compensation are performed so the image may not look as expected (they’re often too green).

The rendering algorithm is relatively rudimentary so the results will be less refined than some other renderers.

Note that the output is a float in the range of 0 to 1 so for many applications it’ll have to be scaled.

While many (most?) cameras are supported, or could with relative ease once rare edge cases are pointed out, some Fuji cameras (and presumably others) will require further development (which can potentially happen if it’s requested).

Parameters
  • rectangle (list[int or float]) –

    The bounding box of the portion of the image that’s to be rendered. In the format X1, Y1, X2, Y2 where:

    • X1 is the x position of the top left corner,

    • Y1 is the y position of the top left corner,

    • X2 is the x position of the bottom right corner,

    • Y2 is the y position of the top right corner.

    The input values can either be in fractions of the way across the image from the origin, or pixels from the origin. The top left corner of the cropped area is assumed to be the origin. If no crop is applied by the user than the DefaultCropOrigin field data is used as the origin.

  • sub_image_type (str) –

    selects which sub-image to return from the file.

    RAW to get the original, raw, image.

    thumbnail to get the thumbnail if present.

Returns

A 3D float array holding the rendered image.

  • The first dimension represents the color channels: Red, Green, Blue at indices 0, 1, and 2 respectively.

  • The second represents the width.

  • The third represents the height.

Return type

Numpy.ndarray

static get_relevant_xmp_attributes()

Gets the list of XMP attributes that are relevant to image rendering.

These are attributes that are edited with photo editing software such as exposure, rating, and saturation. Irrelevant attributes, from a photo editing perspective, such as when the photo was taken, are not returned.

Returns

A dict of the below key value pairs:

- key is the property name.
- value is a namedtuple with the follow properties.
- n_decimal_places: int - The number of decimal places to use when storing the attribute value.
- default_value: str - The default value in Lightroom.
- is_vector: bool - True if it always has a sign in a DNG file’s XMP data, otherwise False.
- is_ramped: bool - True if it should be linearly ramped (i.e. Temperature), otherwise False (i.e. Rating or Exposure)

Return type

dict(bytes: namedtuple(int, str, bool, bool))

get_rendered_shape() → List[int]

Gets the dimensions of the raw image, as cropped and rendered.

Dimensions are in units of pixels.

Returns

A list of ints where the first is the width and the second is the length (height) of the image.

Return type

list[int, int]

get_xmp() → Dict[bytes, float]

Gets the stored XMP data from the represented dng file.

The XMP data holds all of the edits that have been made in Lightroom.

Returns

The xmp data as a dict with the keys being the properties as found in the XMP data and values being the associated values as floats.

Return type

dict[bytes, float]

property is_key_frame

Says whether or not an image is a reference frame.

For timelapse sequences, specifies whether or not the given image is intended to be used as a reference frame. This is determined by the image star rating and whether or not it matches the number of stars that a DNG image must have to be considered a reference frame, 3 by default.

Returns

True if it’s a reference frame, otherwise false.

Return type

bool

save() → None

Overwrites the dng’s XMP data with the updated XMP data.

Returns

None

set_xmp_attribute(xmp_attribute: bytes, value: Union[int, float, str]) → bool

Updates the stored value of an XMP attribute.

Cannot update attributes that aren’t already present. If an attribute wasn’t previously present it can’t be updated.

Only updates the representation in the DNG object. DNG.store_xmp_field() and DNG.save() have to be called to permanently save the updated values.

Parameters
  • xmp_attribute – The XMP attribute to be updated. Should be a key from the _dng_constants.XMP_TAGS dict

  • value (int, float, or str) – The number to be assigned to the attribute.

Returns

True if it’s successful, False if it isn’t, presumably because the attribute isn’t present or the value was already stored.

Return type

bool

store_xmp_field() → None

Consolidate updated XMP attributes in the XMP data.

If this isn’t called, the XMP data won’t be updated in the file even if DNG.save() is called.

Returns

None