jpegscaled

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Dec 18, 2025 License: MIT Imports: 5 Imported by: 0

README

go-scaled-jpeg

go-scaled-jpeg is a Go library for decoding JPEG images at reduced resolution using scaled IDCT (Inverse Discrete Cosine Transform). It enables memory-efficient image decoding — ideal for thumbnails or previews. Best performance gain achieved with baseline JPEGs. Progressive JPEGs are supported but memory consumption on par with image/jpeg library.

This library combines Go's standard image/jpeg infrastructure with a translated and adapted version of the Independent JPEG Group (IJG)'s integer IDCT routines.

Features

  • JPEG decoding at reduced resolutions (1/8, 1/4, 1/2, full)
  • Scalable via DCTSizeScaled (1–8)
  • Tolerant mode to decode incomplete images without failing
  • Based on Go standard library and IJG's reference implementation

Installation

go get github.com/m8rge/go-scaled-jpeg

Usage

import (
    "os"
    "github.com/m8rge/go-scaled-jpeg"
)

func main() {
    f, err := os.Open("example.jpg")
    if err != nil {
        panic(err)
    }
    defer f.Close()

    img, err := jpegscaled.Decode(f, 4) // Decode at 1/2 resolution
    if err != nil {
        panic(err)
    }

    // Use img as image.Image
}

Benchmarks

BenchmarkDecodeBaseline
BenchmarkDecodeBaseline/scaled
BenchmarkDecodeBaseline/scaled/dct_size_1
BenchmarkDecodeBaseline/scaled/dct_size_1-10         	    1905	    544793 ns/op	 907.50 MB/s	   14640 B/op	       5 allocs/op
BenchmarkDecodeBaseline/scaled/dct_size_2
BenchmarkDecodeBaseline/scaled/dct_size_2-10         	    2116	    548515 ns/op	 901.34 MB/s	   16944 B/op	       5 allocs/op
BenchmarkDecodeBaseline/scaled/dct_size_3
BenchmarkDecodeBaseline/scaled/dct_size_3-10         	    2077	    576923 ns/op	 856.96 MB/s	   20656 B/op	       5 allocs/op
BenchmarkDecodeBaseline/scaled/dct_size_4
BenchmarkDecodeBaseline/scaled/dct_size_4-10         	    1988	    595975 ns/op	 829.56 MB/s	   26160 B/op	       5 allocs/op
BenchmarkDecodeBaseline/scaled/dct_size_5
BenchmarkDecodeBaseline/scaled/dct_size_5-10         	    2026	    594736 ns/op	 831.29 MB/s	   32944 B/op	       5 allocs/op
BenchmarkDecodeBaseline/scaled/dct_size_6
BenchmarkDecodeBaseline/scaled/dct_size_6-10         	    1911	    626495 ns/op	 789.15 MB/s	   41136 B/op	       5 allocs/op
BenchmarkDecodeBaseline/scaled/dct_size_7
BenchmarkDecodeBaseline/scaled/dct_size_7-10         	    1825	    660812 ns/op	 748.17 MB/s	   54832 B/op	       5 allocs/op
BenchmarkDecodeBaseline/scaled/dct_size_8
BenchmarkDecodeBaseline/scaled/dct_size_8-10         	    1664	    705304 ns/op	 700.97 MB/s	   63024 B/op	       5 allocs/op
BenchmarkDecodeBaseline/optimized
BenchmarkDecodeBaseline/optimized-10                 	    1684	    721496 ns/op	 685.24 MB/s	   63024 B/op	       5 allocs/op
BenchmarkDecodeProgressive
BenchmarkDecodeProgressive/scaled
BenchmarkDecodeProgressive/scaled/dct_size_1
BenchmarkDecodeProgressive/scaled/dct_size_1-10         	    1320	    875977 ns/op	 564.40 MB/s	  211337 B/op	      13 allocs/op
BenchmarkDecodeProgressive/scaled/dct_size_2
BenchmarkDecodeProgressive/scaled/dct_size_2-10         	    1300	    873480 ns/op	 566.01 MB/s	  213632 B/op	      13 allocs/op
BenchmarkDecodeProgressive/scaled/dct_size_3
BenchmarkDecodeProgressive/scaled/dct_size_3-10         	    1383	    879395 ns/op	 562.20 MB/s	  217344 B/op	      13 allocs/op
BenchmarkDecodeProgressive/scaled/dct_size_4
BenchmarkDecodeProgressive/scaled/dct_size_4-10         	    1347	    891384 ns/op	 554.64 MB/s	  222848 B/op	      13 allocs/op
BenchmarkDecodeProgressive/scaled/dct_size_5
BenchmarkDecodeProgressive/scaled/dct_size_5-10         	    1326	    913840 ns/op	 541.01 MB/s	  229632 B/op	      13 allocs/op
BenchmarkDecodeProgressive/scaled/dct_size_6
BenchmarkDecodeProgressive/scaled/dct_size_6-10         	    1276	    922707 ns/op	 535.81 MB/s	  237824 B/op	      13 allocs/op
BenchmarkDecodeProgressive/scaled/dct_size_7
BenchmarkDecodeProgressive/scaled/dct_size_7-10         	    1239	    961199 ns/op	 514.36 MB/s	  251520 B/op	      13 allocs/op
BenchmarkDecodeProgressive/scaled/dct_size_8
BenchmarkDecodeProgressive/scaled/dct_size_8-10         	    1156	   1028548 ns/op	 480.68 MB/s	  259712 B/op	      13 allocs/op
BenchmarkDecodeProgressive/optimized
BenchmarkDecodeProgressive/optimized-10                 	    1147	   1043039 ns/op	 474.00 MB/s	  259712 B/op	      13 allocs/op

License

This project contains code under multiple licenses:

  • MIT License: For original code written for this project (see LICENSE).
  • IJG License: For translated parts from the Independent JPEG Group (e.g., IDCT routines) (see COPYING.IJG).
  • BSD 3-Clause License: For parts derived from the Go standard library (see LICENSE.GOLANG).

Documentation

Overview

Package jpeg implements a JPEG image decoder and encoder.

JPEG is defined in ITU-T T.81: https://www.w3.org/Graphics/JPEG/itu-t81.pdf.

Example
// This example demonstrates decoding a JPEG image and examining its pixels.
package main

import (
	"encoding/base64"
	"fmt"
	"log"
	"strings"
)

func main() {
	// Decode the JPEG data. If reading from file, create a reader with
	//
	// reader, err := os.Open("testdata/video-001.q50.420.jpeg")
	// if err != nil {
	//     log.Fatal(err)
	// }
	// defer reader.Close()
	reader := base64.NewDecoder(base64.StdEncoding, strings.NewReader(data))
	// DCTSizeScaled allowed from 8 to 1: 8 is 100% size, 4 is 50%, 1 is 1/8 of original size
	m, err := Decode(reader, DecodeOptions{DCTSizeScaled: 4})
	if err != nil {
		log.Fatal(err)
	}
	bounds := m.Bounds()

	// Calculate a 16-bin histogram for m's red, green, blue and alpha components.
	//
	// An image's bounds do not necessarily start at (0, 0), so the two loops start
	// at bounds.Min.Y and bounds.Min.X. Looping over Y first and X second is more
	// likely to result in better memory access patterns than X first and Y second.
	var histogram [16][4]int
	for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
		for x := bounds.Min.X; x < bounds.Max.X; x++ {
			r, g, b, a := m.At(x, y).RGBA()
			// A color's RGBA method returns values in the range [0, 65535].
			// Shifting by 12 reduces this to the range [0, 15].
			histogram[r>>12][0]++
			histogram[g>>12][1]++
			histogram[b>>12][2]++
			histogram[a>>12][3]++
		}
	}

	// Print the results.
	fmt.Printf("%-14s %6s %6s %6s %6s\n", "bin", "red", "green", "blue", "alpha")
	for i, x := range histogram {
		fmt.Printf("0x%04x-0x%04x: %6d %6d %6d %6d\n", i<<12, (i+1)<<12-1, x[0], x[1], x[2], x[3])
	}
}

const data = `
/9j/4AAQSkZJRgABAQIAHAAcAAD/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdA
SFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2Nj
Y2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wAARCABnAJYDASIAAhEBAxEB/8QA
HwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIh
MUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVW
V1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG
x8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQF
BgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAV
YnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOE
hYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq
8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDlwKMD0pwzSiuK57QzGDxS7D6in8Y5ximnAPUfSlcq4m3ilUYp
2OKXHvRcVxnTtS7c07HNFK4DQPakC4PNOA+tOx70XAjK/So5gBGP94fzqfvUVx/qxx/EP51UXqRP4WSE
cmgjilP3jSEZqS0IO/NGDnpUiocDg/McDjvV6HTPOdVWYgsM5KcfzzQ2JySM2jp6VYu7SWzmMUwG4cgj
kMPUVBjjtTGtRu0Zopw+lFFxhinrGzuqqMsxAA9yaXFSRv5cqSEcIwYj6GpuZ30O30fSLKzhUpbpNMv3
5XGTn29BV28jt7pPLuIVljPBBFVreYx+VbqAjycgt3x14zRcNOxGyVFHQkIc/wA61exyKLbuzjdZ046d
ftEuTEw3Rk9SPT8P8Kpbea3tchbyVae4JkjbbGpGdwOM89Af6ViFTWUtGdcXoM2+woK1JtpNtTcoZt+l
Jt7ZqTbRtouFyPFRXI/c9D94fzqzioLsfuD/ALw/nVReqIn8LJCOTSY+tSMOTmkIpXLRu+F0t5pJxPHG
wjjUAuBjJJz1+laD6Pai+WaK9SBX6puzn6ZP+NV/Dkdtc6ZNbyAFwxLAHDYPv6VoQ21nPNEEiQGEFRtk
Gf0NaWTOeW7Of8QwGG4MRZnEbYXPJwRnOR0zWNXW+KrqBLUWi5EjbWCgcAA9c/gRXKYqZaGlK/LqMH0F
FLtHvRSNiYD2pSDTgpp6p0ywUHoTULXYxcktzrdCf7Xo8LP/AKyEmMNjJ46dfbFWJ5TDGNwB9lFUvDV9
YrbfYGbyrjcWG88S57g+vtV26ZIvMlumKwwjLZ6V0WfU54yTvYwtbubea2WNWbzg4bYQeBgj8OtYeKhj
u4y2HQxqxOD1xzxmrWAQCCGB6EGsaikndmsJxeiYzBo280/Z7UbayuaXGY5oIp+2lx9KLjIsVDeD/Rj/
ALy/zq1t96r3y4tT/vL/ADq4P3kRP4WSleTSFKkkKoCW4GaqNcMxIjXj1pxjKT0FKrGC1Nrw3vGrKkYz
5kTAr6455/HH510UdwPtRgWCbzF5+YYUf4Vwun39xpmoR3qASMmQUJwGU9Rnt/8AWrpbrxhb8/ZdOmaQ
gAGZwFH5ZJrpVKVlY5ZYhN6kXiu2eO/ikZlIljAAB5yM549OawSOOlPuLqe+umuLqTfM4OSOAo7ADsKh
hl/cRsTuJHPv7mlKi3sVTxNtGP20VJhThgSQaK52mnZnUqsWrpkyeUrr5pABOAPU1AGaXUCWJISHGPfP
P8qL7BiKnsMg46H3qrbzupbj5mPTPTpXVSglG551SpzSsXJ4/MBUgYIxyKpySyGBYJriV1D7kRpCVH4V
bSeNJ4xchni3DeqnBI+td7F4b0mKIRjT45VbktJlzk455+n6VtYzv2PNwFZWBHBGKVJDGVC54/nXQeMN
NttLNkba1jgWVWDmM8bhg4/nzXLSSbXVj6fyNKUdNRp21RtIRJGrjuM0u3FQ2DbodvcEkfQmrW2vLqLl
k0ejCXNFMj2/jQV9qkxSYNRcsZiq2oI32N2CkhWXJxwOe9XMcVt6hoPn6dFaW0wgRpNzvKDlz6+/0rai
ryv2Jm9LHJai+ZRGCBjnr71ErdAxAY9B611t1Y2cunbbaOQ3FvKZI3UqGlZMbiWwfcfhV231iwvLSM3U
lt5Uq52TuZG+hGMA12xXJGxxzjzybOQtNOvb5j9ktZJhnBIHyg+5PFX38JayqK/2eLJIBUTgkDA9q7ex
itrSHFpGsUbndhRgc+g7VNIyfZJAoJZUbb3I46CtFJMylBo8sdWhmYMuCnylc9wef5VUT7+1chc5NS7h
sUZO5RtIPUH3pkBDOxxxmqM9TQtn+WilhHfHaik43KTG3Z4IyPyrNVjGCsZ+dmwv6V3cXhSG8sYpJLud
JJIwxChdoJGcYx/Wkg8DafA4knvLiQr/ALqj+VQpKw3FtnFFfvbiSMgZJ6/jXp2n3d9cQRBTFsKD96EP
oOxPU/8A68VVtbbRtMVntbePKDLTSHJH/Aj/AEqHTvE66rq72VugMMcbSGTnL4wMAfjT5n0HyW3L+s6b
baxaJBdzN+7bcrxkAhun0rz3VNCv7e7lgigknWI43xLu6jjIHTjtXqfkpPGVYsBkghTikgsYIN/lhgXb
cxLkknp/ShczQ7xtY8vtEmhkj8yGRBuCnehUcnHcVtmwfJ/fQ8e7f/E12txZW91C0U6b42xlST2OR/Ko
Bo1gM/uW55/1jf41nOipu7LhV5FZHIGzI6zwj/vr/Ck+yr3uYf8Ax7/CutbQdMb71tn/ALaN/jSf8I/p
X/PoP++2/wAan6rAr6wzkWt0II+1Rc/7Lf4Vd1eeCSKBbdZDdShYoiZNoyfY10P/AAj2lf8APmP++2/x
oPh/SjKspsozIuNrZORjp3qo0FHYPb3OZt7ae3SzjuItsiRSAgnccl/UA+3Q1yNjKLR4ZZYY5VD7tkv3
WwO/+e1evPp9nI257aJm6bioz1z1+tY+s6Hplnot9PbWMMcqwOFcLyOO1bJWMZSTOPHi+9w3mosrlyd2
9lCj02g9P/1e9a3hzxAbl2ikZRcdQueHHt7j864Y8Z4I4oRzG6urFWU5BHBB7HNJxTFGbR6he6Vpmtgm
eLy5zwZI/lb8fX8azIvBUUTHdfSFP4QsYB/HNZ+k+KEnRY75hHOvAk6K/v7H9K6yyvlnQBmDZ6GsnzR0
N0oy1RzOtaN/Y1tHNFO06u+zYy4I4Jzx9KKveJblXuordSGES5b6n/62PzorKVdp2LjQTVyWz8UWEWlq
jSgyxfJt6EgdDzWTdeLIZGO7zHI/hVajGmWWP+PWL8qwlAIURrhpMAHHJA71pRcZrToZzcoEuo6heakA
GHk245CZ6/X1qPTLq40q+W5t2QybSpDAkEEc55/zilk5k2r91eKhLDzWz2rpsczbbuemeD76fUNG865I
MiysmQMZAAwa3a5j4ftu0ByP+fh/5CulkLLG7INzhSVHqe1Fh3uOoqn9qQQxyhndmHIxwOmSR2xQ13KD
KoiBZOV9JBnt707MVy5RWdNdy7wRGf3bfMinnO1jg+vY03WXLaJO3mhQ20b0zwpYf0qlG7S7icrJs08U
VwumgC+YiQyeVtZH567hzj8aSL949oGhE/2v5pJCDkksQwBHC4/+vXQ8LZ2uYxxCavY7us/xCcaBfn0h
b+VP0bnSrb94ZMJgOecj1rl/GfidUE2k2gy5+SeQjgA/wj3rlas2jdao48qrjLAGkSKPk4Gc1WMj92I+
lIJnU8OfxPWo5inBokmtQTmM4OOh71b0q6vbFmWCbaxHyqQGAP0PT8KhSTzVyo5ocSKA5VfTOTmqsmRd
pl99XjPzThzK3zOeOSeveirNmkgg/fIpYsTkYORxRXmzlTjJqx6EVUcU7mhkKCzdAK59QI9zYxtG1fYU
UVtgtmY4nZEa8Ak9aqFv3rfSiiu1nMeifDv/AJF+T/r4f+QrqqKKQwzQenNFFMCOKFIgNuThdoJ5OPSk
ubeK6t3gnXdG4wwziiii/UTKMOg6dbzJLFE4dSCP3rEdeOM8805tDsGMvySgSsS6rM6gk9eAcUUVftZt
3uyVGNthuq3Eei6DK8H7sRR7YuMgHtXkc8rzTNLM26RyWY+p70UVnLY0iEsUipG7rhZBlDkc1HgYoorM
0HwyBXGeRjmrcUhMg2ghezd//rUUVcTKW5s2jZtY/QDaOKKKK8ip8bPRj8KP/9k=
`
Output:
bin               red  green   blue  alpha
0x0000-0x0fff:     67    150   1795      0
0x1000-0x1fff:    160    741    207      0
0x2000-0x2fff:    223    574    278      0
0x3000-0x3fff:    216    591    245      0
0x4000-0x4fff:    160    312    128      0
0x5000-0x5fff:     81    246     82      0
0x6000-0x6fff:     97    101     66      0
0x7000-0x7fff:    151     71     54      0
0x8000-0x8fff:    873     70     74      0
0x9000-0x9fff:    559     74     86      0
0xa000-0xafff:    230     83    102      0
0xb000-0xbfff:     85     90     78      0
0xc000-0xcfff:     80     82     63      0
0xd000-0xdfff:     79     97     73      0
0xe000-0xefff:    125     98     88      0
0xf000-0xffff:    639    445    406   3825

Index

Examples

Constants

View Source
const (
	FIX_0_298631336 = 2446
	FIX_0_390180644 = 3196
	FIX_0_541196100 = 4433
	FIX_0_765366865 = 6270
	FIX_0_899976223 = 7373
	FIX_1_175875602 = 9633
	FIX_1_501321110 = 12299
	FIX_1_847759065 = 15137
	FIX_1_961570560 = 16069
	FIX_2_053119869 = 16819
	FIX_2_562915447 = 20995
	FIX_3_072711026 = 25172
	PASS1_BITS      = 2
	DCTSIZE         = 8
	CONST_BITS      = 13
	ONE             = 1
	RANGE_CENTER    = CENTERJSAMPLE << 2
	RANGE_MASK      = RANGE_CENTER*2 - 1
	MAXJSAMPLE      = 255 // for 8-bit images
	CENTERJSAMPLE   = 128
	RangeTableSize  = RANGE_CENTER*2 + MAXJSAMPLE + 1 // full range
)
View Source
const CONST_SCALE = ONE << CONST_BITS

Variables

This section is empty.

Functions

func DEQUANTIZE

func DEQUANTIZE(a, b int32) int32

Dequantize a coefficient by multiplying it by the multiplier-table * entry; produce an int result. In this module, both inputs and result * are 16 bits or less, so either int or short multiply will work.

func Decode

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

Decode reads a JPEG image from r and returns it as an image.Image.

func FIX

func FIX(a float32) int32

Convert a positive real constant to an integer scaled by CONST_SCALE. * Caution: some C compilers fail to reduce "FIX(constant)" at compile time, * thus causing a lot of useless floating-point operations at run time.

func IRIGHT_SHIFT

func IRIGHT_SHIFT(a, b int32) int32

func MULTIPLY

func MULTIPLY(a, b int32) int32

func RIGHT_SHIFT

func RIGHT_SHIFT(a, b int32) int32

Types

type Config added in v1.1.0

type Config struct {
	image.Config
	JpegType JpegType
}

func DecodeConfig added in v1.1.0

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

DecodeConfig returns jpeg type (Baseline, Progressive), the color model and dimensions of a JPEG image without decoding the entire image.

type DecodeOptions added in v1.2.0

type DecodeOptions struct {
	// DCTSizeScaled allowed from 8 to 1. 8 is 100% size, 4 is 50%, 1 is 1/8 of original size.
	DCTSizeScaled int
	// Tolerant enables lenient decoding of truncated or malformed images.
	Tolerant bool
}

DecodeOptions specifies JPEG decoding parameters.

type FormatError

type FormatError string

A FormatError reports that the input is not a valid JPEG.

func (FormatError) Error

func (e FormatError) Error() string

type JpegType added in v1.1.0

type JpegType int8
const (
	JpegTypeUnsupported JpegType = 0
	JpegTypeBaseline    JpegType = 1
	JpegTypeProgressive JpegType = 2
)

type Reader deprecated

type Reader interface {
	io.ByteReader
	io.Reader
}

Deprecated: Reader is not used by the image/jpeg package and should not be used by others. It is kept for compatibility.

type UnsupportedError

type UnsupportedError string

An UnsupportedError reports that the input uses a valid but unimplemented JPEG feature.

func (UnsupportedError) Error

func (e UnsupportedError) Error() string

Directories

Path Synopsis
internal
imageutil
Package imageutil contains code shared by image-related packages.
Package imageutil contains code shared by image-related packages.

Jump to

Keyboard shortcuts

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