jpegn

package module
v0.6.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 28, 2026 License: MIT Imports: 12 Imported by: 3

README ΒΆ

jpegn

Status Go Reference

JPEG image decoder and encoder in pure Go.

No CGo, no dependencies.

SIMD support for amd64 (SSE4.1, AVX2), arm64 (NEON) and riscv64 (RVV, with GORISCV64=rva23u64). Build with -tags noasm for pure Go everywhere.

Decoding

img, err := jpegn.Decode(r)

jpegn.Decode returns the image in its native color space, *image.YCbCr, *image.Gray, *image.CMYK or *image.RGBA, and registers itself with image.RegisterFormat. It can also force RGBA output, pick the chroma upsampling filter, apply the EXIF orientation, and scale by 1/2, 1/4 or 1/8 inside the inverse transform, which costs less than a full decode.

Encoding

err := jpegn.Encode(w, img, &jpegn.EncodeOptions{Quality: 90})

Subsampling follows the source, so an image.YCbCr keeps its native ratio and its planes are encoded without resampling. Progressive mode, optimized Huffman tables, adaptive quantization and restart intervals are all opt-in, and EXIF and anything else, such as an ICC profile, carry through a decode and re-encode.

Supported

The decoder reads baseline and progressive JPEG, 8-bit, grayscale, YCbCr, RGB, CMYK and YCCK, any power-of-two subsampling, and restart intervals. Truncated or corrupt scan data decodes as far as it goes rather than failing. Arithmetic coding and 12-bit samples are refused.

The encoder writes baseline and progressive JPEG, grayscale or YCbCr, at 4:4:4, 4:4:0, 4:2:2 or 4:2:0. Files are within 0.2% of the standard library at the same quality and subsampling, and identical to libjpeg-turbo at quality 50. Optimized Huffman tables save ~4% at quality 50, rising to ~20% at quality 95; progressive mode ~9% more on flat color and hard edges, and little or nothing on detailed photographic content; jpegli's adaptive dead zone ~10% again. All three together are ~17% below plain baseline at ~1.6x the encode time.

Against the standard library, ~1.9x on progressive and ~3.1x on baseline decode, ~2.9x decoding straight to RGBA, and ~4.5x to ~6.3x on encode, in two allocations rather than twelve. SIMD is worth ~1.3x to ~3.7x over -tags noasm. On a machine without AVX2 the SSE4.1 kernels still give ~1.7x to ~2.8x over pure Go.

License

MIT, in LICENSE.

Documentation ΒΆ

Overview ΒΆ

Package jpegn decodes and encodes JPEG images.

img, err := jpegn.Decode(r)

Decode returns the image in its native color space, *image.YCbCr, *image.Gray, *image.CMYK or *image.RGBA. The package registers itself with image.RegisterFormat, so image.Decode works once it is imported for side effects.

It reads baseline and progressive JPEG, 8-bit, grayscale, YCbCr, RGB, CMYK and YCCK, any power-of-two subsampling, and restart intervals. Truncated or corrupt scan data decodes as far as it goes rather than failing, which is what a viewer wants from a partial file. Arithmetic coding and 12-bit samples are refused with ErrUnsupported; a broken file gives ErrSyntax.

Options ΒΆ

Options are passed to any of the decode functions and default to zero:

img, err := jpegn.Decode(r, &jpegn.Options{
	ToRGBA:     true, // RGBA instead of the native color space
	AutoRotate: true, // apply the EXIF orientation
	ScaleDenom: 2,    // decode at half size
})

Options.ScaleDenom downscales inside the inverse transform, so 2, 4 and 8 cost less than a full decode rather than more. Options.UpsampleMethod selects the chroma filter for RGBA output, NearestNeighbor or the slower, smoother CatmullRom.

DecodeConfig reports the dimensions and color model without decoding the image, as they are stored in the frame header and ignoring EXIF orientation.

Encoding ΒΆ

Encode writes baseline JPEG by default:

err := jpegn.Encode(w, img, &jpegn.EncodeOptions{Quality: 90})

Quality runs from 1 to 100 and zero selects DefaultQuality. EncodeOptions.Subsampling follows the source unless it is set, so an *image.YCbCr keeps its native ratio and its planes are encoded without resampling.

Three options trade encode time for size, and all three are off by default because each changes the output:

err := jpegn.Encode(w, img, &jpegn.EncodeOptions{
	Quality:              90,
	OptimizeCoding:       true, // Huffman tables from the real statistics
	Progressive:          true, // spectral selection and successive approximation
	AdaptiveQuantization: true, // drop coefficients the eye is least likely to miss
})

EncodeOptions.OptimizeCoding saves about 4% at quality 50, rising to about 20% at quality 95. EncodeOptions.Progressive saves about 9% more on flat color and hard edges, and little or nothing on detailed photographic content. EncodeOptions.AdaptiveQuantization is jpegli's per-block dead zone, worth about 10% again; it does not vary the quantization table, so the result is an ordinary JPEG that any decoder reads. Together they are about 17% below plain baseline at about 1.6x the encode time.

EncodeOptions.RestartInterval puts a restart marker every so many MCUs, which bounds the damage a corrupt run of bytes can do.

Metadata ΒΆ

DecodeExif parses the EXIF an image carries, and RawExif returns the APP1 segment whole. Both report ErrNoEXIF when the file has none.

exif, err := jpegn.DecodeExif(r)

To carry metadata through a decode and re-encode, hand the raw segment back as EncodeOptions.Exif and anything else, an ICC profile for instance, as EncodeOptions.Segments. EncodeOptions.ResetOrientation rewrites the orientation tag to 1, which is what an encoder that has already applied the rotation should write.

Index ΒΆ

Constants ΒΆ

View Source
const DefaultQuality = 75

DefaultQuality is the quality used when EncodeOptions is nil or Quality is zero.

Variables ΒΆ

View Source
var (
	ErrNoJPEG             = errors.New("not a JPEG file")
	ErrNoEXIF             = errors.New("no EXIF data found")
	ErrUnsupported        = errors.New("unsupported format")
	ErrOutOfMemory        = errors.New("out of memory")
	ErrInternal           = errors.New("internal error")
	ErrSyntax             = errors.New("syntax error")
	ErrMissingHuffmanCode = errors.New("missing Huffman code")
	ErrInvalidSegment     = errors.New("invalid marker segment")
)

Standard error types for JPEG decoding.

Functions ΒΆ

func Decode ΒΆ

func Decode(r io.Reader, opts ...*Options) (image.Image, error)

Decode reads a JPEG image from r and returns it as an image.Image. It accepts an optional Options struct to control decoding parameters.

func DecodeConfig ΒΆ

func DecodeConfig(r io.Reader) (image.Config, error)

DecodeConfig returns the color model and dimensions of a JPEG image without decoding the entire image data. The dimensions returned are as stored in the file (SOF marker), ignoring any EXIF orientation tags.

func Encode ΒΆ added in v0.5.0

func Encode(w io.Writer, m image.Image, opts ...*EncodeOptions) error

Encode writes the image m to w as JPEG, baseline unless EncodeOptions.Progressive is set.

func RawExif ΒΆ added in v0.5.0

func RawExif(r io.Reader) ([]byte, error)

RawExif returns the EXIF APP1 segment verbatim, for EncodeOptions.Exif.

Types ΒΆ

type EncodeOptions ΒΆ added in v0.5.0

type EncodeOptions struct {
	// Quality ranges from 1 (smallest) to 100 (best). Zero selects [DefaultQuality].
	Quality int
	// Subsampling selects the chroma subsampling ratio.
	Subsampling Subsampling
	// OptimizeCoding derives Huffman tables from the coefficient statistics.
	OptimizeCoding bool
	// Progressive writes a progressive JPEG.
	Progressive bool
	// AdaptiveQuantization drops coefficients the eye is least likely to miss.
	AdaptiveQuantization bool
	// RestartInterval is the MCU count between restart markers; zero disables them.
	RestartInterval int
	// Exif is a raw APP1 payload from [RawExif]; it replaces the JFIF APP0 segment.
	Exif []byte
	// ResetOrientation rewrites the embedded EXIF orientation tag to 1.
	ResetOrientation bool
	// Segments are additional marker segments written after the header segment.
	Segments []Segment
}

EncodeOptions specifies encoding parameters.

type Exif ΒΆ added in v0.3.0

type Exif struct {
	// Basic image info
	Orientation int // EXIF orientation (1-8). 1 = normal, values 2-8 indicate rotation/flip.
	Width       int // Image width in pixels (may differ from actual JPEG dimensions if rotated).
	Height      int // Image height in pixels.

	// Camera info
	Make     string // Camera manufacturer (e.g., "Canon").
	Model    string // Camera model (e.g., "Canon EOS 5D Mark III").
	Software string // Software used to process/create the image.

	// Date/Time (format: "YYYY:MM:DD HH:MM:SS")
	DateTime         string // File modification date/time.
	DateTimeOriginal string // Original capture date/time (when photo was taken).

	// Exposure settings
	ExposureTime float64 // Shutter speed in seconds (e.g., 0.004 = 1/250s).
	FNumber      float64 // Aperture f-number (e.g., 5.6 = f/5.6).
	ISOSpeed     int     // ISO speed rating (e.g., 800).
	FocalLength  float64 // Lens focal length in millimeters.
	Flash        int     // Flash mode/status (0 = no flash, non-zero = flash fired).

	// GPS location
	GPSLatitude  float64 // Latitude in decimal degrees (positive = North, negative = South).
	GPSLongitude float64 // Longitude in decimal degrees (positive = East, negative = West).
	GPSAltitude  float64 // Altitude in meters above sea level.

	// Copyright/Author
	Copyright string // Copyright notice.
	Artist    string // Creator/photographer name.
}

Exif contains metadata extracted from a JPEG image's EXIF data.

func DecodeExif ΒΆ added in v0.3.0

func DecodeExif(r io.Reader) (*Exif, error)

DecodeExif reads EXIF metadata from a JPEG image. Absent tags stay zero.

type Options ΒΆ

type Options struct {
	// ToRGBA forces RGBA output instead of the image's native color space.
	ToRGBA bool
	// UpsampleMethod selects the chroma upsampling algorithm, for RGBA output only.
	UpsampleMethod UpsampleMethod
	// AutoRotate applies the EXIF orientation, forcing RGBA output when it transforms.
	AutoRotate bool
	// ScaleDenom downscales during the IDCT. Valid values are 1, 2, 4 and 8; others are clamped.
	ScaleDenom int
}

Options specifies decoding parameters.

type Segment ΒΆ added in v0.5.0

type Segment struct {
	// Marker is an APPn marker (0xE0 to 0xEF) or the comment marker 0xFE.
	Marker byte
	// Data is the segment payload, at most 65533 bytes.
	Data []byte
}

Segment is an application or comment marker segment to embed in the output.

type Subsampling ΒΆ added in v0.5.0

type Subsampling int

Subsampling selects the chroma subsampling of the encoded image.

const (
	// SubsampleAuto follows the source image, defaulting to 4:2:0.
	SubsampleAuto Subsampling = iota
	// Subsample444 keeps chroma at full resolution.
	Subsample444
	// Subsample440 halves chroma vertically.
	Subsample440
	// Subsample422 halves chroma horizontally.
	Subsample422
	// Subsample420 halves chroma in both directions.
	Subsample420
	// SubsampleGray discards chroma and writes a single-component image.
	SubsampleGray
)

type UpsampleMethod ΒΆ

type UpsampleMethod int

UpsampleMethod defines the algorithm used for chroma upsampling.

const (
	// NearestNeighbor is a fast but low-quality upsampling method.
	NearestNeighbor UpsampleMethod = iota
	// CatmullRom is a higher-quality bicubic upsampling method.
	CatmullRom
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL