quality

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 12, 2025 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package quality provides thumbnail quality assurance and diagnostic tools.

It implements instrumented thumbnail generation with detailed tracking of orientation correction, color space handling, resizing operations, and quality metrics. The package supports sampling-based quality validation and artifact generation for debugging.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ApplyOrientation

func ApplyOrientation(img image.Image, orientation int) (image.Image, bool)

ApplyOrientation applies EXIF orientation transformation to an image orientation values follow EXIF standard (1-8) Returns the oriented image and true if orientation was applied

func ComputeDeltaE

func ComputeDeltaE(img1, img2 image.Image) float64

ComputeDeltaE computes the average Delta-E (CIE76) color difference between two images Returns the mean Delta-E across all pixels

func ComputeMSE

func ComputeMSE(img1, img2 image.Image) float64

ComputeMSE calculates Mean Squared Error between two images Lower values indicate more similar images

func ComputePSNR

func ComputePSNR(img1, img2 image.Image) (float64, error)

ComputePSNR calculates Peak Signal-to-Noise Ratio between two images Returns value in dB (typically 20-50 dB, higher is better) Infinite PSNR means images are identical

func ComputeSSIM

func ComputeSSIM(img1, img2 image.Image) (float64, error)

ComputeSSIM calculates the Structural Similarity Index between two images Based on the Wang et al. 2004 paper "Image Quality Assessment: From Error Visibility to Structural Similarity" Returns value between 0 (completely different) and 1 (identical)

func ComputeSharpness

func ComputeSharpness(img image.Image) float64

ComputeSharpness calculates the Laplacian variance as a measure of sharpness Higher values indicate sharper images Based on the "variance of Laplacian" method commonly used in focus detection

func CountClippedPixels

func CountClippedPixels(img image.Image) (low, high int)

CountClippedPixels counts pixels that are clipped (pure black or pure white)

func GenerateHTMLReport

func GenerateHTMLReport(data ReportData, w io.Writer) error

GenerateHTMLReport creates an HTML comparison report

func LogToStderr

func LogToStderr(diag *ImageDiag)

LogToStderr logs diagnostics to stderr in a human-readable format

func OrientationString

func OrientationString(orientation int) string

OrientationString returns a human-readable description of the orientation

Types

type ApproachConfig

type ApproachConfig struct {
	Name          string                       // Human-readable name
	ResizeMethod  resize.InterpolationFunction // Resize algorithm
	JPEGQuality   int                          // JPEG quality (1-100)
	PreSharpen    bool                         // Apply sharpening before resize
	PostSharpen   bool                         // Apply sharpening after resize
	SharpenAmount float64                      // Sharpening strength (0.0-1.0)
}

ApproachConfig defines a thumbnail generation approach to test

func GetStandardApproaches

func GetStandardApproaches() []ApproachConfig

GetStandardApproaches returns a set of standard approaches to compare

type ArtifactManager

type ArtifactManager struct {
	// contains filtered or unexported fields
}

ArtifactManager handles saving QA artifacts

func NewArtifactManager

func NewArtifactManager(baseDir string, enabled bool) (*ArtifactManager, error)

NewArtifactManager creates a new artifact manager

func (*ArtifactManager) SaveArtifacts

func (am *ArtifactManager) SaveArtifacts(imgID string, artifacts *Artifacts, diag *ImageDiag) error

SaveArtifacts saves intermediate images and diagnostics for a sample

type Artifacts

type Artifacts struct {
	AfterDecode      image.Image
	AfterOrientColor image.Image
	Resized          image.Image
	Final            []byte // Encoded thumbnail
}

Artifacts holds intermediate images for QA sampling

type BenchmarkSummary

type BenchmarkSummary struct {
	ApproachName      string
	ImageCount        int
	AvgSSIM           float64
	AvgPSNR           float64
	AvgSharpness      float64
	AvgProcessingTime time.Duration
	AvgFileSize       int
	TotalSize         int64
}

BenchmarkSummary provides aggregate statistics across multiple images

func SummarizeResults

func SummarizeResults(results []*ComparisonResult) BenchmarkSummary

SummarizeResults creates aggregate statistics for an approach across multiple images

type ComparisonResult

type ComparisonResult struct {
	Config         ApproachConfig
	Metrics        Metrics
	ThumbnailData  []byte        // The actual thumbnail bytes
	ProcessingTime time.Duration // Time to generate thumbnail
	ThumbnailSize  int           // Size in bytes
	WidthPx        int           // Actual width in pixels
	HeightPx       int           // Actual height in pixels
}

ComparisonResult holds the results of comparing a thumbnail approach

func CompareApproaches

func CompareApproaches(reference image.Image, configs []ApproachConfig, targetSize uint) ([]*ComparisonResult, error)

CompareApproaches tests multiple approaches on a single image

func TestApproach

func TestApproach(reference image.Image, config ApproachConfig, targetSize uint) (*ComparisonResult, error)

TestApproach generates a thumbnail using a specific approach and measures quality reference: the full-resolution source image config: the approach configuration to test targetSize: the longest edge size for the thumbnail

type EncodeDiag

type EncodeDiag struct {
	Format      string `json:"format"` // "jpeg","webp","avif"
	Quality     int    `json:"quality"`
	Chroma      string `json:"chroma"` // "420","422","444"
	Progressive bool   `json:"progressive"`
	Bytes       int    `json:"bytes"`
}

EncodeDiag contains diagnostics about encoding

type ImageDiag

type ImageDiag struct {
	ImgID       string       `json:"img_id"`
	Source      SourceDiag   `json:"source"`
	Pipeline    PipelineDiag `json:"pipeline"`
	Metrics     MetricsDiag  `json:"metrics"`
	TimingMS    TimingDiag   `json:"timing_ms"`
	Warnings    []string     `json:"warnings"`
	Version     VersionDiag  `json:"version"`
	GeneratedAt time.Time    `json:"generated_at"`
}

ImageDiag contains comprehensive diagnostics for a single thumbnail generation

func FromJSON

func FromJSON(data []byte) (*ImageDiag, error)

FromJSON deserializes diagnostics from JSON

func GenerateThumbnailsWithDiag

func GenerateThumbnailsWithDiag(ctx context.Context, img image.Image, meta ImageMetadata, cfg ThumbnailConfig) (map[models.ThumbnailSize][]byte, *ImageDiag, error)

GenerateThumbnailsWithDiag generates thumbnails with full instrumentation

func NewImageDiag

func NewImageDiag(imgID string) *ImageDiag

NewImageDiag creates a new ImageDiag with default values

func (*ImageDiag) AddWarning

func (d *ImageDiag) AddWarning(warning string)

AddWarning adds a warning to the diagnostics

func (*ImageDiag) HasWarnings

func (d *ImageDiag) HasWarnings() bool

HasWarnings returns true if there are any warnings

func (*ImageDiag) IsFallback

func (d *ImageDiag) IsFallback() bool

IsFallback returns true if a fallback decode path was used

func (*ImageDiag) IsUpscale

func (d *ImageDiag) IsUpscale() bool

IsUpscale returns true if the image was upscaled

func (*ImageDiag) ToJSON

func (d *ImageDiag) ToJSON() ([]byte, error)

ToJSON serializes the diagnostics to JSON

func (*ImageDiag) ToJSONString

func (d *ImageDiag) ToJSONString() (string, error)

ToJSONString serializes the diagnostics to a JSON string

type ImageMetadata

type ImageMetadata struct {
	FilePath       string
	Orientation    int    // EXIF orientation (1-8)
	ColorSpace     string // "sRGB", "AdobeRGB", etc.
	HasICCProfile  bool
	ICCDescription string
	Width          int
	Height         int
}

ImageMetadata contains metadata needed for thumbnail generation

type ImageReport

type ImageReport struct {
	ImageName   string
	ImageWidth  int
	ImageHeight int
	Results     []*ComparisonResult
}

ImageReport holds comparison results for a single source image

type Logger

type Logger struct {
	// contains filtered or unexported fields
}

Logger handles structured logging of diagnostics

func NewLogger

func NewLogger(logPath string) (*Logger, error)

NewLogger creates a new diagnostics logger If logPath is empty, logging is disabled

func (*Logger) Close

func (l *Logger) Close() error

Close closes the log file

func (*Logger) Log

func (l *Logger) Log(diag *ImageDiag) error

Log writes a diagnostic entry to the log

type Metrics

type Metrics struct {
	SSIM      float64 // Structural Similarity Index (0-1, higher is better)
	PSNR      float64 // Peak Signal-to-Noise Ratio (dB, higher is better)
	Sharpness float64 // Laplacian variance (higher is sharper)
	MSE       float64 // Mean Squared Error (lower is better)
}

Metrics holds quality assessment metrics for a thumbnail

func ComputeAllMetrics

func ComputeAllMetrics(reference, test image.Image) (Metrics, error)

ComputeAllMetrics computes all quality metrics between a reference and test image

type MetricsDiag

type MetricsDiag struct {
	SSIMVsRef         float64 `json:"ssim_vs_ref"`
	PSNRVsRefDB       float64 `json:"psnr_vs_ref_db"`
	LapVar            float64 `json:"lap_var"`
	DeltaEMean        float64 `json:"delta_e_mean"`
	ClippedPixelsLow  int     `json:"clipped_pixels_low"`
	ClippedPixelsHigh int     `json:"clipped_pixels_high"`
	BandingScore      float64 `json:"histogram_banding_score"`
}

MetricsDiag contains quality metrics

type OrientationError

type OrientationError struct {
	Message string
	Applied int // The orientation value already applied
	Attempt int // The orientation value attempting to be applied
}

OrientationError is returned when orientation is applied incorrectly

func (*OrientationError) Error

func (e *OrientationError) Error() string

type OrientationTracker

type OrientationTracker struct {
	// contains filtered or unexported fields
}

ValidateOrientationAppliedOnce checks that orientation hasn't been applied twice This is a helper for guardrails - we track orientation state through the pipeline

func NewOrientationTracker

func NewOrientationTracker() *OrientationTracker

NewOrientationTracker creates a new orientation tracker

func (*OrientationTracker) Apply

func (ot *OrientationTracker) Apply(orientation int) error

Apply marks orientation as applied and records the value Returns error if already applied

func (*OrientationTracker) IsApplied

func (ot *OrientationTracker) IsApplied() bool

IsApplied returns true if orientation has been applied

func (*OrientationTracker) Value

func (ot *OrientationTracker) Value() int

Value returns the orientation value that was applied

type PipelineDiag

type PipelineDiag struct {
	OrientationApplied bool       `json:"orientation_applied"`
	ColorspaceIn       string     `json:"colorspace_in"`
	ColorspaceOut      string     `json:"colorspace_out"`
	GammaLinearized    bool       `json:"gamma_linearized"`
	Resize             ResizeDiag `json:"resize"`
	Encode             EncodeDiag `json:"encode"`
}

PipelineDiag contains diagnostics about the processing pipeline

type RawDiag

type RawDiag struct {
	LibRawEnabled bool   `json:"libraw_enabled"`
	Demosaic      string `json:"demosaic"`     // "AHD","DCB","PPG","unknown"
	OutputBPS     int    `json:"output_bps"`   // 8|16
	OutputColor   string `json:"output_color"` // "sRGB","AdobeRGB","linear","unknown"
	UseCameraWB   bool   `json:"use_camera_wb"`
	HalfSize      bool   `json:"half_size"`
}

RawDiag contains diagnostics about RAW file decode

func DecodeRawWithDiag

func DecodeRawWithDiag(path string) (image.Image, *RawDiag, error)

DecodeRawWithDiag decodes a RAW file and captures diagnostics This wraps the inokone/golibraw library (limited diagnostic information)

type ReportData

type ReportData struct {
	GeneratedAt  time.Time
	ImageReports []ImageReport
	Summaries    []BenchmarkSummary
}

ReportData holds all data needed to generate a comparison report

type ResizeDiag

type ResizeDiag struct {
	TargetLongEdge int         `json:"target_long_edge"`
	Filter         string      `json:"filter"`
	PreSharpen     SharpenDiag `json:"pre_sharpen"`
	PostSharpen    SharpenDiag `json:"post_sharpen"`
	Upscale        bool        `json:"upscale"`
}

ResizeDiag contains diagnostics about resize operation

type SharpenDiag

type SharpenDiag struct {
	Enabled bool    `json:"enabled"`
	Amount  float64 `json:"amount"`
	Radius  float64 `json:"radius"`
}

SharpenDiag contains sharpening configuration

type SourceDiag

type SourceDiag struct {
	Format          string  `json:"format"`
	InputW          int     `json:"input_w"`
	InputH          int     `json:"input_h"`
	HasICC          bool    `json:"has_icc"`
	ICCDesc         string  `json:"icc_desc"`
	EXIFOrientation int     `json:"exif_orientation"`
	Raw             RawDiag `json:"raw,omitempty"`
	FallbackReason  string  `json:"fallback_reason"` // "none|no_cgo|decode_error|no_raw|embedded_only"
}

SourceDiag contains diagnostics about the source image

type ThumbnailConfig

type ThumbnailConfig struct {
	// Quality settings per size
	QualityTiers map[models.ThumbnailSize]int // e.g., {ThumbnailSmall: 80, ThumbnailMedium: 85}

	// Resize filter
	Filter resize.InterpolationFunction

	// Sharpening
	PostSharpen   bool
	SharpenAmount float64
	SharpenRadius float64

	// Policies
	AllowUpscale bool
	LinearResize bool // Gamma-correct resizing

	// QA/Sampling
	QASample           float64 // 0.01 = 1%
	QADir              string  // Where to store artifacts
	QADisableArtifacts bool
}

ThumbnailConfig contains configuration for thumbnail generation

func DefaultThumbnailConfig

func DefaultThumbnailConfig() ThumbnailConfig

DefaultThumbnailConfig returns the default configuration

type ThumbnailResult

type ThumbnailResult struct {
	Size        models.ThumbnailSize
	Data        []byte
	Diagnostics *ImageDiag
}

ThumbnailResult contains the generated thumbnail and diagnostics

type TimingDiag

type TimingDiag struct {
	Decode  float64 `json:"decode"`
	Orient  float64 `json:"orient"`
	Color   float64 `json:"color"`
	Resize  float64 `json:"resize"`
	Sharpen float64 `json:"sharpen"`
	Encode  float64 `json:"encode"`
	Store   float64 `json:"store"`
	Total   float64 `json:"total"`
}

TimingDiag contains timing information for each stage

type VersionDiag

type VersionDiag struct {
	ThumbPipeline string `json:"thumb_pipeline"`
	LibRaw        string `json:"libraw"`
	Encoder       string `json:"encoder"`
}

VersionDiag contains version information

Jump to

Keyboard shortcuts

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