image/jpeg
| Language | Go (standard library) |
|---|---|
| License | BSD-3-Clause |
| Repository | go.googlesource.com/go |
| Documentation | pkg.go.dev/image/jpeg |
| Depends on | nothing |
| Read / write | yes / yes; decodes baseline and progressive (8-bit, grayscale, YCbCr, CMYK); encodes baseline 4:2:0 |
image/jpeg is the JPEG codec of the Go standard library, written in pure Go. jpeg.Decode returns an *image.YCbCr for color images (or *image.Gray, *image.CMYK), jpeg.Encode writes any image.Image. Registering the package with a blank import also lets image.Decode detect JPEG files.
It doesn’t read or write metadata: Exif, ICC and XMP segments are skipped on decode and not written on encode, so phone photos may appear rotated. The encoder writes only baseline JPEG with standard Huffman tables and 4:2:0 subsampling (grayscale images are written as 1-component JPEG). It’s slower than libjpeg-turbo, which has SIMD code.
Installation#
Part of the standard library:
import "image/jpeg"
Basic usage: decode and encode a JPEG#
package main
import (
"fmt"
"image/jpeg"
"log"
"os"
)
func main() {
in, err := os.Open("in.jpg")
if err != nil {
log.Fatal(err)
}
defer in.Close()
img, err := jpeg.Decode(in)
if err != nil {
log.Fatal(err)
}
b := img.Bounds()
fmt.Printf("%d x %d, %T\n", b.Dx(), b.Dy(), img) // *image.YCbCr for color photos
out, err := os.Create("out.jpg")
if err != nil {
log.Fatal(err)
}
defer out.Close()
if err := jpeg.Encode(out, img, &jpeg.Options{Quality: 85}); err != nil {
log.Fatal(err)
}
}
Quality ranges from 1 to 100; nil options means 75.
How to get JPEG width and height without decoding#
jpeg.DecodeConfig reads markers up to the frame header:
f, err := os.Open("in.jpg")
if err != nil {
log.Fatal(err)
}
defer f.Close()
cfg, err := jpeg.DecodeConfig(f)
if err != nil {
log.Fatal(err)
}
fmt.Println(cfg.Width, cfg.Height, cfg.ColorModel)
How to detect the format and decode any image#
A blank import registers a format with image.Decode:
import (
"image"
_ "image/jpeg"
_ "image/png"
)
img, format, err := image.Decode(f) // format is "jpeg", "png", ...
How to convert PNG with transparency to JPEG#
Draw onto an opaque background first; the encoder drops alpha and transparent pixels would turn black:
package main
import (
"image"
"image/color"
"image/draw"
"image/jpeg"
"image/png"
"log"
"os"
)
func main() {
in, err := os.Open("logo.png")
if err != nil {
log.Fatal(err)
}
defer in.Close()
src, err := png.Decode(in)
if err != nil {
log.Fatal(err)
}
dst := image.NewRGBA(src.Bounds())
draw.Draw(dst, dst.Bounds(), &image.Uniform{color.White}, image.Point{}, draw.Src)
draw.Draw(dst, dst.Bounds(), src, src.Bounds().Min, draw.Over)
out, err := os.Create("logo.jpg")
if err != nil {
log.Fatal(err)
}
defer out.Close()
if err := jpeg.Encode(out, dst, &jpeg.Options{Quality: 90}); err != nil {
log.Fatal(err)
}
}
Tips#
- Decoding untrusted files: check
DecodeConfigfirst and reject huge dimensions before callingDecode, which allocates the full image. golang.org/x/image/drawhasCatmullRomandApproxBiLinearscalers for resizing; the standardimage/drawdoesn’t resize.- To keep Exif when re-encoding, copy the
APP1segment bytes from the source file and insert them afterSOIin the output yourself;image/jpeghas no API for it.