CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pyturbo-jpeg

A Python wrapper of libjpeg-turbo for decoding and encoding JPEG images.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

transformations.mddocs/

Image Transformations

Lossless transformation operations for JPEG images including cropping, scaling with quality adjustment, multiple crop operations with background filling, and advanced transform operations that work directly in the compressed domain.

Capabilities

Single Crop Operation

Perform lossless crop operations on JPEG images without decompression/recompression quality loss.

def crop(
    jpeg_buf: bytes, 
    x: int, y: int, w: int, h: int, 
    preserve: bool = False, 
    gray: bool = False, 
    copynone: bool = False
) -> bytes:
    """
    Losslessly crop a JPEG image.
    
    Args:
        jpeg_buf: Input JPEG data as bytes
        x: Crop origin X coordinate (must be MCU-aligned unless preserve=True)
        y: Crop origin Y coordinate (must be MCU-aligned unless preserve=True)
        w: Crop width in pixels
        h: Crop height in pixels
        preserve: If True, preserve exact crop boundaries (slower)
        gray: Convert to grayscale during crop
        copynone: Do not copy EXIF metadata
    
    Returns:
        bytes: Cropped JPEG data
    
    Raises:
        OSError: If crop request is invalid or coordinates are not MCU-aligned
    """

Multiple Crop Operations

Perform multiple crop and/or extension operations in a single call with optional background filling.

def crop_multiple(
    jpeg_buf: bytes, 
    crop_parameters: list[tuple[int, int, int, int]], 
    background_luminance: float = 1.0, 
    gray: bool = False, 
    copynone: bool = False
) -> list[bytes]:
    """
    Lossless crop and/or extension operations on JPEG image.
    
    Args:
        jpeg_buf: Input JPEG data as bytes
        crop_parameters: List of (x, y, w, h) tuples for each crop operation
        background_luminance: Luminance level (0-1) for background fill when extending
        gray: Produce grayscale output
        copynone: Do not copy EXIF metadata
    
    Returns:
        list[bytes]: List of cropped/extended JPEG images
    
    Notes:
        - Crop origins must be divisible by MCU block size
        - Extensions beyond image boundaries filled with background_luminance color
        - background_luminance: 0=black, 0.5=gray, 1=white
    """

Scale with Quality

Scale JPEG images while adjusting quality, combining decompression to YUV, scaling, and recompression in one operation.

def scale_with_quality(
    jpeg_buf: bytes, 
    scaling_factor: tuple[int, int] | None = None, 
    quality: int = 85, 
    flags: int = 0
) -> bytes:
    """
    Scale JPEG image and re-encode with specified quality.
    
    Args:
        jpeg_buf: Input JPEG data as bytes
        scaling_factor: Scaling as (numerator, denominator) tuple
        quality: Output JPEG quality (1-100)
        flags: Processing flags (TJFLAG_* constants)
    
    Returns:
        bytes: Scaled and re-encoded JPEG data
    
    Notes:
        - Avoids color conversion step for efficiency
        - Useful for creating thumbnails with size and quality control
    """

Constants

Transform Operations

TJXOP_NONE: int        # No transform
TJXOP_HFLIP: int       # Horizontal flip
TJXOP_VFLIP: int       # Vertical flip  
TJXOP_TRANSPOSE: int   # Transpose
TJXOP_TRANSVERSE: int  # Transverse
TJXOP_ROT90: int       # 90 degree rotation
TJXOP_ROT180: int      # 180 degree rotation
TJXOP_ROT270: int      # 270 degree rotation

Transform Options

TJXOPT_PERFECT: int     # Perfect transform (require exact alignment)
TJXOPT_TRIM: int        # Trim partial MCUs
TJXOPT_CROP: int        # Crop operation
TJXOPT_GRAY: int        # Convert to grayscale
TJXOPT_NOOUTPUT: int    # No output (validation only)
TJXOPT_PROGRESSIVE: int # Progressive output
TJXOPT_COPYNONE: int    # Copy no metadata

MCU Block Sizes

MCU (Minimum Coded Unit) alignment requirements:

tjMCUWidth: list[int]   # MCU width for each subsampling type
tjMCUHeight: list[int]  # MCU height for each subsampling type

# MCU sizes by subsampling:
# TJSAMP_444 (4:4:4): 8x8 pixels
# TJSAMP_422 (4:2:2): 16x8 pixels  
# TJSAMP_420 (4:2:0): 16x16 pixels
# TJSAMP_GRAY: 8x8 pixels
# TJSAMP_440 (4:4:0): 8x16 pixels
# TJSAMP_411 (4:1:1): 32x8 pixels

Structure Definitions

Cropping Region

class CroppingRegion(Structure):
    """Defines a rectangular cropping region."""
    _fields_ = [
        ("x", c_int),    # X coordinate of crop origin
        ("y", c_int),    # Y coordinate of crop origin  
        ("w", c_int),    # Width of crop region
        ("h", c_int)     # Height of crop region
    ]

Scaling Factor

class ScalingFactor(Structure):
    """Defines a scaling factor as numerator/denominator."""
    _fields_ = [
        ("num", c_int),    # Numerator
        ("denom", c_int)   # Denominator
    ]

Background Structure

class BackgroundStruct(Structure):
    """Background fill parameters for image extension operations."""
    _fields_ = [
        ("w", c_int),      # Input image width
        ("h", c_int),      # Input image height
        ("lum", c_int)     # Luminance value for background fill
    ]

Transform Structure

class TransformStruct(Structure):
    """Complete transform operation definition."""
    _fields_ = [
        ("r", CroppingRegion),                 # Crop region
        ("op", c_int),                         # Transform operation (TJXOP_*)
        ("options", c_int),                    # Transform options (TJXOPT_*)
        ("data", POINTER(BackgroundStruct)),   # Background data for extensions
        ("customFilter", CUSTOMFILTER)         # Custom filter function
    ]

Usage Examples

Basic Cropping

from turbojpeg import TurboJPEG

jpeg = TurboJPEG()

# Load JPEG image
with open('input.jpg', 'rb') as f:
    jpeg_data = f.read()

# Get image info for crop planning
width, height, subsample, _ = jpeg.decode_header(jpeg_data)
print(f"Original: {width}x{height}, subsampling: {subsample}")

# Crop from (100, 100) with size 300x200
cropped = jpeg.crop(jpeg_data, 100, 100, 300, 200)

# Save cropped image
with open('cropped.jpg', 'wb') as f:
    f.write(cropped)

MCU-Aligned Cropping

# For 4:2:0 subsampling, MCU is 16x16 pixels
# Crop coordinates should be multiples of 16 for perfect alignment

# MCU-aligned crop (fast, lossless)
aligned_crop = jpeg.crop(jpeg_data, 16, 32, 320, 240)  # All multiples of 16

# Non-aligned crop with preserve=True (slower but exact)
exact_crop = jpeg.crop(jpeg_data, 15, 33, 318, 238, preserve=True)

Multiple Crops

# Define multiple crop regions
crop_regions = [
    (0, 0, 100, 100),      # Top-left corner
    (100, 0, 100, 100),    # Top-right corner  
    (0, 100, 100, 100),    # Bottom-left corner
    (100, 100, 100, 100),  # Bottom-right corner
]

# Perform all crops in one operation
crops = jpeg.crop_multiple(jpeg_data, crop_regions)

# Save each crop
for i, crop_data in enumerate(crops):
    with open(f'crop_{i}.jpg', 'wb') as f:
        f.write(crop_data)

Extended Crops with Background

# Get original image dimensions
width, height, _, _ = jpeg.decode_header(jpeg_data)

# Define crops that extend beyond image boundaries
extended_crops = [
    (0, 0, width + 50, height + 50),      # Extend right and bottom
    (-25, -25, width + 50, height + 50),  # Extend all sides
]

# White background fill (luminance = 1.0)
white_bg_crops = jpeg.crop_multiple(
    jpeg_data, 
    extended_crops, 
    background_luminance=1.0
)

# Gray background fill (luminance = 0.5)  
gray_bg_crops = jpeg.crop_multiple(
    jpeg_data,
    extended_crops,
    background_luminance=0.5
)

# Black background fill (luminance = 0.0)
black_bg_crops = jpeg.crop_multiple(
    jpeg_data,
    extended_crops, 
    background_luminance=0.0
)

Grayscale Cropping

# Convert to grayscale during crop
gray_crop = jpeg.crop(
    jpeg_data, 
    100, 100, 200, 200, 
    gray=True
)

# Multiple grayscale crops
gray_crops = jpeg.crop_multiple(
    jpeg_data,
    [(0, 0, 100, 100), (100, 100, 100, 100)],
    gray=True
)

Scale with Quality

# Scale to half size with quality 70
half_size = jpeg.scale_with_quality(
    jpeg_data,
    scaling_factor=(1, 2),
    quality=70
)

# Scale to quarter size with high quality
quarter_size = jpeg.scale_with_quality(
    jpeg_data, 
    scaling_factor=(1, 4),
    quality=90
)

# Available scaling factors
print("Available scaling factors:", jpeg.scaling_factors)
# Common factors: (1,8), (1,4), (3,8), (1,2), (5,8), (3,4), (7,8), (1,1), (9,8), (5,4), (11,8), (3,2), (13,8), (7,4), (15,8), (2,1)

Strip Metadata

# Remove EXIF and other metadata during crop
no_metadata = jpeg.crop(
    jpeg_data,
    0, 0, width, height,  # Full image crop
    copynone=True  # Strip all metadata
)

# Compare file sizes
print(f"Original size: {len(jpeg_data)} bytes")
print(f"No metadata size: {len(no_metadata)} bytes")

Advanced Transform Example

# Combine multiple operations
def create_thumbnail_gallery(jpeg_data, thumb_size=(150, 150)):
    """Create multiple thumbnail crops with different qualities."""
    
    # Get image info
    width, height, subsample, _ = jpeg.decode_header(jpeg_data)
    
    # Calculate grid positions for thumbnails
    thumb_w, thumb_h = thumb_size
    cols = width // thumb_w
    rows = height // thumb_h
    
    crop_params = []
    for row in range(rows):
        for col in range(cols):
            x = col * thumb_w
            y = row * thumb_h
            crop_params.append((x, y, thumb_w, thumb_h))
    
    # Extract all thumbnails
    thumbnails = jpeg.crop_multiple(jpeg_data, crop_params)
    
    # Scale and adjust quality for web use
    web_thumbs = []
    for thumb in thumbnails:
        web_thumb = jpeg.scale_with_quality(
            thumb,
            scaling_factor=(1, 2),  # Half size
            quality=60  # Web quality
        )
        web_thumbs.append(web_thumb)
    
    return web_thumbs

# Usage
with open('large_image.jpg', 'rb') as f:
    image_data = f.read()

thumbnails = create_thumbnail_gallery(image_data)

for i, thumb in enumerate(thumbnails):
    with open(f'thumb_{i:03d}.jpg', 'wb') as f:
        f.write(thumb)

Install with Tessl CLI

npx tessl i tessl/pypi-pyturbo-jpeg

docs

decoding.md

encoding.md

index.md

transformations.md

utilities.md

tile.json