fastimage

package module
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Jan 9, 2026 License: MIT Imports: 11 Imported by: 0

README

fastimage - fast image info for go

Go Reference Go Report Card

fastimage is a tiny Go helper that sniffs image headers to extract dimensions without fully decoding the file, keeping it lightweight and suitable for hot paths like upload validation, image proxies, or metadata indexing pipelines. It also includes HTTP helpers for remote image probing via progressive range requests.

Typical use-cases:

  • Validate user image uploads (type + size) without decoding the full image
  • Implement lightweight image proxies / thumbnailers
  • Crawl and index image metadata at scale
  • Quickly check remote banner images / avatars in microservices

Differences from upstream

This repo started as a fork of rubenfonseca/fastimage and adds:

  • AVIF support
  • HTTP helpers for concurrent, range-based remote image probing
  • Stream-aware GetInfoReader API for working with io.Reader

Big thanks and deep respect to @rubenfonseca, author of the original repo.

Features

  • Zero Dependencies - stdlib only
  • High Performance - hand-written header parsing (no regex/wildcard)
  • Wide format support – BMP, GIF, JPEG, MNG, PBM, PCX, PGM, PNG, PPM, PSD, RAS, TIFF, WebP, XBM, XPM, AVIF
  • HTTP range helpers – progressive range fetching for remote images
  • Reader API - stream-aware GetInfoReader for files or network responses

Install

Library (modules will fetch it automatically when you import):

import "github.com/kotylevskiy/fastimage"

CLI:

go install github.com/kotylevskiy/fastimage/cmd/fastimage@latest
Getting Started
package main

import (
	"fmt"

	"github.com/kotylevskiy/fastimage"
)

var data = []byte("RIFF,-\x00\x00WEBPVP8X\n\x00\x00\x00" +
    "\x10\x00\x00\x00\x8f\x01\x00,\x01\x00VP8X\n\x00\x00\x00\x10\xb2" +
    "\x01\x00\x00WEB\x01\x00VP8X\n\x00\x00\x00\x10\xb2\x01\x00" +
    "\x00WEB\x01\x00VP8X\n\x00\x00\x00\x10\xb2\x01\x00\x00W" +
    "EB\x01\x00VP8X\n\x00\x00\x00\x10\xb2\x01\x00\x00WEB"")

func main() {
	fmt.Printf("%+v\n", fastimage.GetInfo(data))
}

// Output: {Type:webp Width:400 Height:301}
Reader API
resp, err := http.Get("https://example.com/image.jpg")
if err != nil {
    // handle error
}
defer resp.Body.Close()

info, err := fastimage.GetInfoReader(resp.Body)
if err != nil {
    // handle error
}
fmt.Printf("%+v\n", info)
HTTP Range Helper

The HTTP helper is multithreaded and probes URLs concurrently (bounded by the concurrency options below).

urls := []string{
    "https://example.com/a.jpg",
    "https://example.com/b.png",
}
results := fastimage.GetHTTPImageInfo(context.Background(), urls)
for _, result := range results {
    fmt.Printf("%s %+v err=%v\n", result.URL, result.Info, result.Error)
}
HTTP Concurrency Defaults

GetHTTPImageInfo uses these defaults:

  • CONCURRENT_REQUESTS_FOR_REUSABLE_CONNECTIONS_DEFAULT = 20 (per-origin when range is supported)
  • CONCURRENT_REQUESTS_FOR_NON_REUSABLE_CONNECTIONS_DEFAULT = 5 (per-origin when range is not supported)
  • MAX_CONCURRENT_CONNECTIONS_GLOBAL_DEFAULT = 50 (global cap across origins)

These limits cap concurrent requests; the HTTP transport also sets MaxConnsPerHost to ConcurrentRequestsReusable to avoid excessive connections per origin.

“Reusable” means the server supports HTTP range requests (206 Partial Content), so the client can reuse keep‑alive connections efficiently while fetching multiple byte ranges. “Not reusable” means range is unsupported; each probe may need a full response, so concurrency is reduced to avoid overloading the origin and wasting bandwidth.

For “browser‑like” behavior, the defaults are reasonable. The code uses 20 when range is supported by the remote host (requests multiplexed to a fewer number of connections) and falls back to 5 when it’s not.

To override them, use GetHTTPImageDataWithOptions:

options := fastimage.GetHTTPImageOptions{
    ConcurrentRequestsReusable:    8,
    ConcurrentRequestsNonReusable: 2,
    MaxConcurrentConnections:      16,
}
results := fastimage.GetHTTPImageDataWithOptions(context.Background(), urls, options)
Command Tool
$ go get github.com/kotylevskiy/fastimage/cmd/fastimage
$ fastimage banner.png
png image/png 320 50
$ fastimage https://example.com/banner.png
png image/png 320 50

Documentation

Index

Constants

View Source
const (
	CONCURRENT_REQUESTS_FOR_REUSABLE_CONNECTIONS_DEFAULT = 20
	// CONCURRENT_REQUESTS_FOR_NON_REUSABLE_CONNECTIONS_DEFAULT is the default per-origin concurrency when range requests are not supported.
	CONCURRENT_REQUESTS_FOR_NON_REUSABLE_CONNECTIONS_DEFAULT = 5
	// MAX_CONCURRENT_CONNECTIONS_GLOBAL_DEFAULT is the default global concurrency cap across origins.
	MAX_CONCURRENT_CONNECTIONS_GLOBAL_DEFAULT = 50
)

CONCURRENT_REQUESTS_FOR_REUSABLE_CONNECTIONS_DEFAULT is the default per-origin concurrency when range requests are supported.

Variables

This section is empty.

Functions

This section is empty.

Types

type GetHTTPImageOptions

type GetHTTPImageOptions struct {
	// ConcurrentRequestsReusable is the per-origin limit when range requests are supported.
	ConcurrentRequestsReusable int
	// ConcurrentRequestsNonReusable is the per-origin limit when range requests are not supported.
	ConcurrentRequestsNonReusable int
	// MaxConcurrentConnections is the global limit across all origins.
	MaxConcurrentConnections int
}

GetHTTPImageOptions controls concurrency behavior for HTTP image probing.

type GetHTTPImageResult

type GetHTTPImageResult struct {
	HTTPImageInfo
	Error error `json:"error,omitempty"`
}

GetHTTPImageResult contains image metadata or an error for a given URL.

func GetHTTPImageDataWithOptions

func GetHTTPImageDataWithOptions(ctx context.Context, urls []string, options GetHTTPImageOptions) []GetHTTPImageResult

GetHTTPImageDataWithOptions fetches basic image metadata for a list of URLs using custom options.

Errors:

  • context.Canceled or context.DeadlineExceeded if the context ends.
  • *url.Error from url.Parse or for invalid URLs.
  • http.Client transport errors from http.Client.Do.
  • io.ReadAll errors while reading the response body.
  • *HTTPStatusError for non-200/206 responses.
  • *RetryAfterError for 429/503 responses with parseable Retry-After.
  • *InsufficientBytesError when there is not enough data to detect image info.

func GetHTTPImageInfo

func GetHTTPImageInfo(ctx context.Context, urls []string) []GetHTTPImageResult

GetHTTPImageInfo fetches basic image metadata for a list of URLs using default options.

Errors:

  • context.Canceled or context.DeadlineExceeded if the context ends.
  • *url.Error from url.Parse or for invalid URLs.
  • http.Client transport errors from http.Client.Do.
  • io.ReadAll errors while reading the response body.
  • *HTTPStatusError for non-200/206 responses.
  • *RetryAfterError for 429/503 responses with parseable Retry-After.
  • *InsufficientBytesError when there is not enough data to detect image info.

type HTTPImageInfo

type HTTPImageInfo struct {
	// URL is the original image URL.
	URL string `json:"url"`
	Info
}

HTTPImageInfo holds the URL and detected image metadata.

type HTTPStatusError added in v0.1.1

type HTTPStatusError struct {
	URL        string
	StatusCode int
	Status     string
}

func (*HTTPStatusError) Error added in v0.1.1

func (e *HTTPStatusError) Error() string

type Info

type Info struct {
	Type   Type   `json:"type"`
	Width  uint32 `json:"width"`
	Height uint32 `json:"height"`
}

Info holds the type and dismissons of an image

func GetInfo

func GetInfo(p []byte) (info Info)

GetInfo detects image info from the provided bytes. A zero Info is a normal outcome and means there is insufficient data, not invalid data. Callers should retry with more bytes if they need dimensions. Some formats (for example JPEG) may require more bytes than any fixed prefix.

func GetInfoReader

func GetInfoReader(r io.Reader) (Info, error)

GetInfoReader reads from r until it can determine the image info or EOF.

type InsufficientBytesError added in v0.1.1

type InsufficientBytesError struct {
	URL string
	Got int
	Min int
}

func (*InsufficientBytesError) Error added in v0.1.1

func (e *InsufficientBytesError) Error() string

func (*InsufficientBytesError) Unwrap added in v0.1.1

func (e *InsufficientBytesError) Unwrap() error

Let callers use errors.Is(err, io.ErrUnexpectedEOF).

type RetryAfterError added in v0.1.1

type RetryAfterError struct {
	URL        string
	StatusCode int
	Status     string
	RetryAfter time.Duration
}

func (*RetryAfterError) Error added in v0.1.1

func (e *RetryAfterError) Error() string

type Type

type Type uint64

Type represents the type of the image detected, or `Unknown`.

const (
	// Unknown represents an unknown image type
	Unknown Type = iota
	// BMP represendts a BMP image
	BMP
	// BPM represendts a BPM image
	BPM
	// GIF represendts a GIF image
	GIF
	// JPEG represendts a JPEG image
	JPEG
	// MNG represendts a MNG image
	MNG
	// PBM represendts a PBM image
	PBM
	// PCX represendts a PCX image
	PCX
	// PGM represendts a PGM image
	PGM
	// PNG represendts a PNG image
	PNG
	// PPM represendts a PPM image
	PPM
	// PSD represendts a PSD image
	PSD
	// RAS represendts a RAS image
	RAS
	// RGB represendts a RGB image
	RGB
	// TIFF represendts a TIFF image
	TIFF
	// WEBP represendts a WEBP image
	WEBP
	// XBM represendts a XBM image
	XBM
	// XPM represendts a XPM image
	XPM
	// XV represendts a XV image
	XV
	// AVIF represendts a AVIF image
	AVIF
)

func GetType

func GetType(p []byte) Type

GetType detects an image type from the provided bytes. Unknown is a normal outcome and means there is insufficient data, not invalid data. Callers should retry with more bytes if they need a definitive type.

func (Type) Mime

func (t Type) Mime() string

Mime return mime type of image type

func (Type) String

func (t Type) String() string

String return a lower name of image type

Directories

Path Synopsis
cmd
fastimage command

Jump to

Keyboard shortcuts

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