LJPEG Module and Workflow

Note

While this could be extensible to handle more common lossy JPEGs, it only presently handles lossless JPEGs.

Note

This isn’t a complete implementation of the lossless JPEG standard. Only enough has been implemented to render the available reference DNG files.

Note

While initial validates have made the encode function appear to work, it’s only seen minimal testing refinement so it’s likely slow and potentially has bugs in some edge cases. I’ll get polished when it becomes a priority (the developer needs it or someone reaches out about it).

This is a lossless jpeg encoder and encoder utility. It’s based on the 1992 standard T.81, 10918.1.

While images are often stored and/or represented as 1D arrays; this module does not follow that pattern. Following the more typical pattern can require frequent and verbose calculations to extract actual pixel values from arrays in higher level functions. Using this format, pixel values fall out of the array values:

pixel_color_channel_value = image[color_channel, x_position, y_position]

pixel_color_value = image[:, x_position, y_position]

Additionally, this format is easily reshaped to a more standard shape with numpy.reshape().

Usage

Decoding

Example: Decode a lossless Jpeg and get the red, green, and blue components for the top left pixel as well as the image dimensions.

This assumes that the image is RGB and has all color channels present in each pixel.

import numpy as np

from brilliantimagery.ljpeg import decode

image_bytes = np.fromfile('path/to/image.ljpeg', np.uint8).astype(np.intc)
image_array = decode(image_bytes)

red = image_array[0, 0, 0]
green = image_array[1, 0, 0]
blue = image_array[2, 0, 0]

width = image_array.shape[1]
height = image_array.shape[2]

Encoding

Example: Encode a lossless Jpeg given a 3D numpy array of integers.

This assumes that image_data is a a 3D numpy array of ints and that white is represented by a number no larger than 255 since 8 bits of precision are being used to store the intensity values. Also, the predictor is 2.

import numpy as np

from brilliantimagery.ljpeg import encode

image = encode(image_data, 8, 2)

API

brilliantimagery.ljpeg.decode(int[:] encoded_image)

Decode a Lossless Jpeg according to the 1992 standard T.81, 10918.1, into its raw components.

Returned array properties are to be used to get input image properties such as shape and number of color channels. For a monochromatic image decode(img).shape[0] would equal 1. In a typical DNG tile it would equal 2, and it would equal 3 for an RGB image. Similar procedures can be used to get the image width and length.

Parameters

encoded_image – A 1D Numpy array holding the compressed image. encoded_image can be created with something like np.fromfile('F-18.ljpg', np.uint8).astype(np.intc), note the astype() at the end.

Returns

A 3 dimensional Numpy array with index 0 being the color channel, index 1 being the X coordinate, and index 2 being the Y coordinate.

brilliantimagery.ljpeg.encode(int[:, :, :] image, int precision, int predictor)

Encode a raw image into a Lossless Jpeg according to the 1992 standard T.81, 10918.1.

This is neither highly optimized nor heavily tested.

Parameters
  • image – A 3 dimensional Numpy array with index 0 being the color channel, index 1 being the X coordinate, and index 2 being the Y coordinate.

  • precision – The number of bits of precision for each color value. This can be different from the number of bits of precision used by the array holding the values.

  • predictor – The predictor, Ss from the Jpeg standard, to be used.

Returns

A compressed Lossless Jpeg as a MemoryView to a 1D Numpy array.