A Python wrapper of libjpeg-turbo for decoding and encoding JPEG images.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Core decoding functionality for converting JPEG data to numpy arrays, with support for various pixel formats, scaling factors, direct rescaling during decode, YUV output formats, and in-place decoding for memory efficiency.
Decode JPEG header information without full image decompression to get image properties and metadata.
def decode_header(jpeg_buf: bytes) -> tuple[int, int, int, int]:
"""
Decode JPEG header and return image properties.
Args:
jpeg_buf: JPEG data as bytes
Returns:
tuple: (width, height, jpeg_subsample, jpeg_colorspace)
- width: Image width in pixels
- height: Image height in pixels
- jpeg_subsample: Subsampling type (TJSAMP_* constants)
- jpeg_colorspace: Color space (TJCS_* constants)
"""Decode JPEG data to numpy arrays with various pixel format options, scaling, and performance flags.
def decode(
jpeg_buf: bytes,
pixel_format: int = TJPF_BGR,
scaling_factor: tuple[int, int] | None = None,
flags: int = 0,
dst: np.ndarray | None = None
) -> np.ndarray:
"""
Decode JPEG memory buffer to numpy array.
Args:
jpeg_buf: JPEG data as bytes
pixel_format: Output pixel format (TJPF_* constants)
scaling_factor: Optional scaling as (numerator, denominator) tuple
flags: Decoding flags (TJFLAG_* constants)
dst: Optional pre-allocated output array for in-place decoding
Returns:
np.ndarray: Decoded image array with shape (height, width, channels)
"""Decode JPEG directly to YUV format, useful for video processing and when avoiding color space conversion.
def decode_to_yuv(
jpeg_buf: bytes,
scaling_factor: tuple[int, int] | None = None,
pad: int = 4,
flags: int = 0
) -> tuple[np.ndarray, list[tuple[int, int]]]:
"""
Decode JPEG memory buffer to YUV array.
Args:
jpeg_buf: JPEG data as bytes
scaling_factor: Optional scaling as (numerator, denominator) tuple
pad: Padding bytes for YUV planes
flags: Decoding flags (TJFLAG_* constants)
Returns:
tuple: (buffer_array, plane_sizes)
- buffer_array: YUV data as numpy array
- plane_sizes: List of (height, width) tuples for each plane
"""
def decode_to_yuv_planes(
jpeg_buf: bytes,
scaling_factor: tuple[int, int] | None = None,
strides: tuple[int, int, int] = (0, 0, 0),
flags: int = 0
) -> list[np.ndarray]:
"""
Decode JPEG memory buffer to separate YUV planes.
Args:
jpeg_buf: JPEG data as bytes
scaling_factor: Optional scaling as (numerator, denominator) tuple
strides: Stride values for each plane (0 = automatic)
flags: Decoding flags (TJFLAG_* constants)
Returns:
list[np.ndarray]: List of YUV planes as separate arrays
"""TJPF_RGB: int # RGB pixel format
TJPF_BGR: int # BGR pixel format (default)
TJPF_RGBX: int # RGBX pixel format
TJPF_BGRX: int # BGRX pixel format
TJPF_XBGR: int # XBGR pixel format
TJPF_XRGB: int # XRGB pixel format
TJPF_GRAY: int # Grayscale pixel format
TJPF_RGBA: int # RGBA pixel format
TJPF_BGRA: int # BGRA pixel format
TJPF_ABGR: int # ABGR pixel format
TJPF_ARGB: int # ARGB pixel format
TJPF_CMYK: int # CMYK pixel formatTJCS_RGB: int # RGB color space
TJCS_YCbCr: int # YCbCr color space
TJCS_GRAY: int # Grayscale color space
TJCS_CMYK: int # CMYK color space
TJCS_YCCK: int # YCCK color spaceTJFLAG_BOTTOMUP: int # Bottom-up pixel order
TJFLAG_FASTUPSAMPLE: int # Fast upsampling (lower quality)
TJFLAG_FASTDCT: int # Fast DCT (lower quality)
TJFLAG_ACCURATEDCT: int # Accurate DCT (higher quality)
TJFLAG_STOPONWARNING: int # Stop on warning
TJFLAG_LIMITSCANS: int # Limit progressive scansTJSAMP_444: int # 4:4:4 subsampling (no subsampling)
TJSAMP_422: int # 4:2:2 subsampling
TJSAMP_420: int # 4:2:0 subsampling
TJSAMP_GRAY: int # Grayscale
TJSAMP_440: int # 4:4:0 subsampling
TJSAMP_411: int # 4:1:1 subsampling
TJSAMP_441: int # 4:4:1 subsamplingfrom turbojpeg import TurboJPEG, TJPF_RGB
jpeg = TurboJPEG()
# Decode to BGR (default)
with open('image.jpg', 'rb') as f:
bgr_image = jpeg.decode(f.read())
# Decode to RGB
with open('image.jpg', 'rb') as f:
rgb_image = jpeg.decode(f.read(), pixel_format=TJPF_RGB)
# Decode to grayscale
with open('image.jpg', 'rb') as f:
gray_image = jpeg.decode(f.read(), pixel_format=TJPF_GRAY)# Decode at half resolution
with open('image.jpg', 'rb') as f:
half_image = jpeg.decode(f.read(), scaling_factor=(1, 2))
# Check available scaling factors
print("Available scaling factors:", jpeg.scaling_factors)from turbojpeg import TJFLAG_FASTUPSAMPLE, TJFLAG_FASTDCT
# Fast decoding (lower quality, higher speed)
with open('image.jpg', 'rb') as f:
fast_image = jpeg.decode(
f.read(),
flags=TJFLAG_FASTUPSAMPLE|TJFLAG_FASTDCT
)import numpy as np
# Pre-allocate array for in-place decoding
with open('image.jpg', 'rb') as f:
# Get dimensions first
width, height, _, _ = jpeg.decode_header(f.read())
# Create pre-allocated array
f.seek(0)
img_array = np.empty((height, width, 3), dtype=np.uint8)
# Decode in-place
result = jpeg.decode(f.read(), dst=img_array)
assert result is img_array # Same object# Decode to YUV buffer
with open('image.jpg', 'rb') as f:
yuv_buffer, plane_sizes = jpeg.decode_to_yuv(f.read())
print("YUV buffer size:", yuv_buffer.size)
print("Plane sizes:", plane_sizes)
# Decode to separate YUV planes
with open('image.jpg', 'rb') as f:
yuv_planes = jpeg.decode_to_yuv_planes(f.read())
print("Y plane shape:", yuv_planes[0].shape)
print("U plane shape:", yuv_planes[1].shape)
print("V plane shape:", yuv_planes[2].shape)Install with Tessl CLI
npx tessl i tessl/pypi-pyturbo-jpeg