imageprocessor

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Feb 19, 2026 License: MIT Imports: 7 Imported by: 0

README

🖼️ imageprocessor

ماژول پردازش تصویر enterprise-grade برای Go

یک کتابخانه‌ی production-ready، ماژولار، و قابل توسعه برای پردازش تصاویر در حجم بالا
طراحی‌شده با اصول Clean Architecture — بدون global state، با libvips backend، با کارایی واقعی


Go Version License Architecture Backend


📋 فهرست مطالب


🤔 چرا این ماژول؟

مشکل واقعی

وقتی یک سرویس backend نیاز به پردازش تصویر دارد، اغلب با این چالش‌ها روبرو می‌شود:

  • کتابخانه‌های موجود یا بیش از حد ساده هستند (فقط resize) یا بیش از حد وابسته (نیاز به CGO، libvips، ImageMagick)
  • Global state و singleton‌های پنهان که تست را غیرممکن می‌کنند
  • هیچ pipeline قابل توسعه‌ای وجود ندارد — نمی‌توان یک step سفارشی اضافه کرد
  • کنترل ضعیف memory — هر request یک buffer جدید allocate می‌کند
  • بدون worker pool — در بار بالا goroutine explosion رخ می‌دهد
  • بدون مکانیزم retry برای خطاهای گذرا
راه‌حل این ماژول
✅ Clean Architecture بدون وابستگی بین لایه‌ها
✅ Zero global state — هر Processor مستقل است
✅ Plugable pipeline — هر step قابل جایگزینی یا افزودن
✅ libvips backend — 8× سریع‌تر از Go stdlib، 18× کمتر RAM
✅ Buffer pool با sync.Pool — حداقل GC pressure
✅ Worker pool با backpressure — کنترل کامل بار
✅ Retry هوشمند فقط برای خطاهای transient
✅ Context-aware — هر عملیات قابل لغو است

✨ ویژگی‌ها

پردازش تصویر
قابلیت جزئیات
فرمت‌های پشتیبانی‌شده JPEG، PNG، WebP (decode و encode واقعی)
تغییر اندازه (Resize) Lanczos3 با shrink-on-load، دو محور مستقل
برش (Crop) برش دقیق با مختصات مشخص
Thumbnail vips_thumbnail — سریع‌ترین مسیر ممکن
تبدیل فرمت JPEG↔PNG↔WebP در یک pipeline
کنترل کیفیت Quality 1-100 قابل تنظیم per-step
Adaptive Compression کاهش خودکار کیفیت تا رسیدن به حجم هدف
حذف EXIF پاک‌سازی کامل metadata با libvips
Auto Rotate اعمال EXIF orientation بدون pixel copy
Grayscale تبدیل به تصویر سیاه و سفید
Watermark افزودن لایه شفاف روی تصویر
معماری و کارایی
قابلیت جزئیات
libvips Backend SIMD/AVX2، demand-driven pipeline، tile streaming
Worker Pool تعداد worker قابل تنظیم، backpressure داخلی
Batch Processing پردازش موازی چندین تصویر
Async Queue ارسال job و دریافت نتیجه از channel
Multi-Variant تولید چند نسخه از یک تصویر به صورت موازی
Buffer Pool sync.Pool برای صفر allocation تکراری
Context Aware لغو عملیات از طریق context.Context
Retry مکانیزم تلاش مجدد فقط برای خطاهای transient

📦 نصب و راه‌اندازی

پیش‌نیازها
  • Go 1.22 یا بالاتر
  • libvips 8.x نصب‌شده روی سیستم
نصب libvips
# macOS
brew install vips

# Ubuntu / Debian
apt-get install libvips-dev

# Alpine Linux (Docker)
apk add --no-cache vips-dev build-base

# تأیید نصب
vips --version
نصب ماژول
go get github.com/Skryldev/image-processor
Docker (توصیه‌شده برای production)
FROM golang:1.22-alpine AS builder
RUN apk add --no-cache vips-dev build-base
WORKDIR /app
COPY . .
RUN CGO_ENABLED=1 go build -o server ./cmd/server

FROM alpine:3.19
RUN apk add --no-cache vips
COPY --from=builder /app/server /server
ENTRYPOINT ["/server"]

⚡ شروع سریع

package main

import (
    "bytes"
    "context"
    "fmt"
    "os"

    imageprocessor "github.com/Skryldev/image-processor"
    "github.com/Skryldev/image-processor/adapters/vips"
    "github.com/Skryldev/image-processor/core"
    "github.com/Skryldev/image-processor/pipeline"
)

func main() {
    // ۱. ساخت processor
    proc := imageprocessor.New(imageprocessor.DefaultConfig())

    // ۲. فعال‌سازی libvips backend
    backend := vips.NewBackend(vips.BackendConfig{DefaultQuality: 85})
    defer backend.Shutdown()
    vips.RegisterVipsBackend(proc.Inner().Registry(), backend)

    proc.Start()
    defer proc.Stop()

    // ۳. خواندن فایل تصویر
    file, _ := os.Open("photo.jpg")
    defer file.Close()

    reg := proc.Inner().Registry()

    // ۴. پردازش: decode → resize → WebP → encode
    result, err := proc.Process(
        context.Background(),
        imageprocessor.FromReader(file),
        &pipeline.DecodeStep{Registry: reg},
        &vips.VipsResizeStep{Width: 1024}, // Lanczos3 + shrink-on-load
        imageprocessor.ConvertFormat(imageprocessor.WebP),
        imageprocessor.EncodeWith(reg, core.EncodeOptions{Quality: 85}),
    )
    if err != nil {
        panic(err)
    }

    // ۵. ذخیره خروجی
    os.WriteFile("output.webp", result.Primary.Data, 0644)

    fmt.Printf("✅ %dx%d — %d bytes — %.1f ms\n",
        result.Primary.Meta.Width,
        result.Primary.Meta.Height,
        len(result.Primary.Data),
        float64(result.ProcessingTime.Microseconds())/1000,
    )
}

📚 راهنمای کامل استفاده

۱. ساخت و پیکربندی Processor
import (
    imageprocessor "github.com/alienrobotninja/imageprocessor"
    "github.com/alienrobotninja/imageprocessor/adapters/vips"
    "github.com/alienrobotninja/imageprocessor/config"
)

cfg := config.Default()
cfg.WorkerCount    = 8
cfg.QueueSize      = 512
cfg.DefaultQuality = 85
cfg.MaxRetries     = 3
cfg.RetryDelay     = 100 * time.Millisecond
cfg.JobTimeout     = 30 * time.Second
cfg.MaxImageBytes  = 20 * 1024 * 1024 // 20MB

proc := imageprocessor.New(cfg)

backend := vips.NewBackend(vips.BackendConfig{
    DefaultQuality: 85,
    MaxWorkers:     cfg.WorkerCount,
    MaxCacheSize:   100, // MB
})
defer backend.Shutdown()
vips.RegisterVipsBackend(proc.Inner().Registry(), backend)

proc.Start()
defer proc.Stop()

۲. تغییر اندازه (Resize)

از VipsResizeStep به جای ResizeStep استفاده کنید تا از shrink-on-load بهره ببرید:

reg := proc.Inner().Registry()

// عرض ۸۰۰ — ارتفاع خودکار (Lanczos3)
result, _ := proc.Process(ctx, src,
    &pipeline.DecodeStep{Registry: reg},
    &vips.VipsResizeStep{Width: 800},
    imageprocessor.EncodeWith(reg, core.EncodeOptions{Quality: 85}),
)

// هر دو بُعد مشخص
result, _ = proc.Process(ctx, src,
    &pipeline.DecodeStep{Registry: reg},
    &vips.VipsResizeStep{Width: 800, Height: 600},
    imageprocessor.EncodeWith(reg, core.EncodeOptions{Quality: 85}),
)

۳. برش (Crop)
// Crop(x, y, width, height)
result, _ := proc.Process(ctx, src,
    &pipeline.DecodeStep{Registry: reg},
    imageprocessor.Crop(100, 50, 400, 300),
    imageprocessor.EncodeWith(reg, core.EncodeOptions{Quality: 90}),
)

۴. تبدیل فرمت
// JPEG به WebP واقعی (libwebp)
result, _ := proc.Process(ctx, src,
    &pipeline.DecodeStep{Registry: reg},
    imageprocessor.ConvertFormat(imageprocessor.WebP),
    imageprocessor.EncodeWith(reg, core.EncodeOptions{Quality: 80}),
)

// PNG lossless
result, _ = proc.Process(ctx, src,
    &pipeline.DecodeStep{Registry: reg},
    imageprocessor.ConvertFormat(imageprocessor.PNG),
    imageprocessor.EncodeWith(reg, core.EncodeOptions{Lossless: true}),
)

۵. تولید Thumbnail

VipsThumbnailStep مستقیم از bytes کار می‌کند — نیازی به DecodeStep ندارد:

// shrink-on-load + Lanczos3 + centre crop — در یک C function call
result, _ := proc.Process(ctx, src,
    &vips.VipsThumbnailStep{Size: 256}, // نه DecodeStep نیاز است
    imageprocessor.EncodeWith(reg, core.EncodeOptions{Quality: 75}),
)

۶. کنترل کیفیت و Adaptive Compression
// کیفیت ثابت
result, _ := proc.Process(ctx, src,
    &pipeline.DecodeStep{Registry: reg},
    imageprocessor.Quality(70),
    imageprocessor.EncodeWith(reg, core.EncodeOptions{}),
)

// Adaptive Compression: کاهش خودکار کیفیت تا حجم هدف
result, _ = proc.Process(ctx, src,
    &pipeline.DecodeStep{Registry: reg},
    imageprocessor.AdaptiveCompress(
        reg,
        100 * 1024, // هدف: ۱۰۰ کیلوبایت
        30,         // حداقل کیفیت
        92,         // شروع از کیفیت ۹۲
    ),
)

۷. حذف EXIF + Auto Rotate
result, _ := proc.Process(ctx, src,
    &pipeline.DecodeStep{Registry: reg},
    &vips.VipsAutoRotateStep{},  // اعمال EXIF orientation
    &vips.VipsStripEXIFStep{},   // حذف تمام metadata
    imageprocessor.EncodeWith(reg, core.EncodeOptions{
        StripEXIF: true,
        Quality:   85,
    }),
)

۸. پردازش موازی چند خروجی (Variants)
result, err := proc.ProcessVariants(
    ctx,
    imageprocessor.FromReader(uploadedFile),

    // مرحله پایه: یک بار اجرا می‌شود
    []core.Step{
        &pipeline.DecodeStep{Registry: reg},
        &vips.VipsStripEXIFStep{},
    },

    // نسخه‌های موازی
    []core.VariantDefinition{
        {Name: "original", Steps: []core.Step{
            &vips.VipsResizeStep{Width: 1920},
            imageprocessor.EncodeWith(reg, core.EncodeOptions{Quality: 90}),
        }},
        {Name: "medium", Steps: []core.Step{
            &vips.VipsResizeStep{Width: 800},
            imageprocessor.EncodeWith(reg, core.EncodeOptions{Quality: 85}),
        }},
        {Name: "thumb", Steps: []core.Step{
            &vips.VipsThumbnailStep{Size: 256},
            imageprocessor.EncodeWith(reg, core.EncodeOptions{Quality: 75}),
        }},
        {Name: "webp", Steps: []core.Step{
            &vips.VipsResizeStep{Width: 800},
            imageprocessor.ConvertFormat(imageprocessor.WebP),
            imageprocessor.EncodeWith(reg, core.EncodeOptions{Quality: 80}),
        }},
    },
)

for name, variant := range result.Variants {
    fmt.Printf("variant[%-10s]: %dx%d — %d bytes\n",
        name, variant.Meta.Width, variant.Meta.Height, len(variant.Data))
}

۹. پردازش دسته‌ای (Batch)
sources := make([]core.Source, len(files))
for i, f := range files {
    sources[i] = imageprocessor.FromReader(f)
}

results, errs := proc.Batch(ctx, sources,
    &pipeline.DecodeStep{Registry: reg},
    &vips.VipsResizeStep{Width: 800},
    imageprocessor.EncodeWith(reg, core.EncodeOptions{Quality: 85}),
)

۱۰. پردازش غیرهمزمان (Async Worker Pool)
resultCh := make(chan core.JobResult, 1)

err := proc.Submit(core.Job{
    ID:     "upload-" + uploadID,
    Ctx:    context.Background(),
    Source: imageprocessor.FromReader(uploadedFile),
    Steps: []core.Step{
        &pipeline.DecodeStep{Registry: reg},
        &vips.VipsStripEXIFStep{},
        &vips.VipsResizeStep{Width: 1200},
        imageprocessor.EncodeWith(reg, core.EncodeOptions{Quality: 85}),
    },
    ResultCh: resultCh,
})
if err != nil {
    // صف پر است — ErrWorkerPoolFull → HTTP 429
    return http.StatusTooManyRequests
}

go func() {
    select {
    case res := <-resultCh:
        if res.Err != nil {
            log.Printf("job failed: %v", res.Err)
            return
        }
        saveToStorage(res.JobID, res.Result.Primary.Data)
    case <-time.After(60 * time.Second):
        log.Println("job timed out")
    }
}()

۱۱. ذخیره‌سازی
Local Storage
import "github.com/alienrobotninja/imageprocessor/adapters/storage"

localStorage, _ := storage.NewLocal("/var/data/images", 0644)

key := core.StorageKey{Bucket: "uploads", Path: "2024/01/photo.jpg"}
localStorage.Put(ctx, key, bytes.NewReader(result.Primary.Data), map[string]string{
    "width":  strconv.Itoa(result.Primary.Meta.Width),
    "format": string(result.Primary.Format),
})
S3 / MinIO
s3Adapter, _ := storage.NewS3(&myS3Client{client: awsClient}, "my-bucket")
key := core.StorageKey{Path: "processed/photo.webp"}
s3Adapter.Put(ctx, key, bytes.NewReader(data), nil)

۱۲. Observability: لاگ و متریک
import (
    "log/slog"
    "github.com/alienrobotninja/imageprocessor/hooks"
)

logger := hooks.NewSlogLogger(
    slog.New(slog.NewJSONHandler(os.Stdout, nil)),
)
proc.SetLogger(logger)
proc.AddHook(hooks.NewLoggingHook(logger))

metrics := hooks.NewInMemoryMetrics()
proc.AddHook(hooks.NewMetricsHook(metrics))

// --- بعد از پردازش ---
snap := metrics.Snapshot()
for step, count := range snap.StepCalls {
    fmt.Printf("step=%-22s calls=%-3d  avg=%.1fms\n",
        step, count,
        float64(snap.StepDurationsMs[step])/float64(count),
    )
}

processed, errCount := proc.Stats()
fmt.Printf("Processed: %d  Errors: %d\n", processed, errCount)

۱۳. Step سفارشی
type BrightnessStep struct {
    Factor float64
}

func (s *BrightnessStep) Name() string { return "brightness" }

func (s *BrightnessStep) Execute(ctx context.Context, img *core.ImageData) (*core.ImageData, error) {
    if err := ctx.Err(); err != nil {
        return nil, err
    }
    src := img.Image.(image.Image)
    bounds := src.Bounds()
    dst := image.NewRGBA(bounds)
    for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
        for x := bounds.Min.X; x < bounds.Max.X; x++ {
            r, g, b, a := src.At(x, y).RGBA()
            dst.SetRGBA(x, y, color.RGBA{
                R: clamp(float64(r>>8) * s.Factor),
                G: clamp(float64(g>>8) * s.Factor),
                B: clamp(float64(b>>8) * s.Factor),
                A: uint8(a >> 8),
            })
        }
    }
    out := *img
    out.Image = dst
    return &out, nil
}

// استفاده
result, _ := proc.Process(ctx, src,
    &pipeline.DecodeStep{Registry: reg},
    &BrightnessStep{Factor: 1.3},
    imageprocessor.EncodeWith(reg, core.EncodeOptions{Quality: 85}),
)

🌐 استفاده در HTTP Handler

func (h *ImageHandler) Upload(w http.ResponseWriter, r *http.Request) {
    r.Body = http.MaxBytesReader(w, r.Body, 20<<20)

    if err := r.ParseMultipartForm(10 << 20); err != nil {
        http.Error(w, "فایل خیلی بزرگ است", http.StatusBadRequest)
        return
    }
    file, header, err := r.FormFile("image")
    if err != nil {
        http.Error(w, "فایل یافت نشد", http.StatusBadRequest)
        return
    }
    defer file.Close()

    reg := h.proc.Inner().Registry()

    result, err := h.proc.ProcessVariants(
        r.Context(),
        imageprocessor.FromReaderWithMeta(
            file, header.Size,
            header.Header.Get("Content-Type"),
            header.Filename,
        ),
        []core.Step{
            &pipeline.DecodeStep{Registry: reg},
            &vips.VipsAutoRotateStep{},
            &vips.VipsStripEXIFStep{},
        },
        []core.VariantDefinition{
            {Name: "original", Steps: []core.Step{
                imageprocessor.AdaptiveCompress(reg, 500*1024, 60, 92),
            }},
            {Name: "medium", Steps: []core.Step{
                &vips.VipsResizeStep{Width: 800},
                imageprocessor.EncodeWith(reg, core.EncodeOptions{Quality: 85}),
            }},
            {Name: "thumb", Steps: []core.Step{
                &vips.VipsThumbnailStep{Size: 256},
                imageprocessor.EncodeWith(reg, core.EncodeOptions{Quality: 75}),
            }},
        },
    )
    if err != nil {
        http.Error(w, "خطا در پردازش تصویر", http.StatusInternalServerError)
        return
    }

    imageID := generateID()
    urls := map[string]string{}
    for name, variant := range result.Variants {
        key := core.StorageKey{Bucket: "images", Path: imageID + "/" + name + ".jpg"}
        h.storage.Put(r.Context(), key, bytes.NewReader(variant.Data), nil)
        urls[name] = "/images/" + key.Path
    }

    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(map[string]interface{}{
        "id":              imageID,
        "urls":            urls,
        "processing_time": result.ProcessingTime.String(),
    })
}

⚠️ مدیریت خطا

import apperrors "github.com/alienrobotninja/imageprocessor/errors"

result, err := proc.Process(ctx, src, steps...)
if err != nil {
    switch {
    case apperrors.IsCategory(err, apperrors.CategoryDecode):
        http.Error(w, "فایل تصویر معتبر نیست", http.StatusBadRequest)

    case apperrors.IsCategory(err, apperrors.CategoryStorage):
        log.Printf("storage error: %v", err)
        http.Error(w, "خطای ذخیره‌سازی", http.StatusInternalServerError)

    case apperrors.IsRetryable(err):
        http.Error(w, "سرویس موقتاً در دسترس نیست", http.StatusServiceUnavailable)

    default:
        log.Printf("unexpected error: %v", err)
        http.Error(w, "خطای داخلی", http.StatusInternalServerError)
    }
    return
}
Category توضیح
CategoryDecode فرمت ناشناخته، فایل خراب
CategoryEncode خطای رمزگذاری خروجی
CategoryPipeline خطای step در pipeline
CategoryStorage خطای I/O ذخیره‌سازی
CategoryTransient خطای گذرا (retryable)
CategoryInput ورودی نامعتبر

🚀 کارایی و بهینه‌سازی

چرا libvips؟

libvips در سه سطح از Go stdlib سریع‌تر است:

SIMD/AVX2 — libjpeg-turbo 32 پیکسل را در یک CPU cycle پردازش می‌کند در مقابل 1 پیکسل در Go.

Shrink-On-Load — برای thumbnail یک تصویر 4K، libvips به libjpeg-turbo می‌گوید در 1/8 رزولوشن decode کن. نتیجه: 64× کمتر داده قبل از اینکه Go اجرا شود.

Tile Streaming — libvips هیچ‌وقت کل bitmap را در RAM نگه نمی‌دارد. Peak RAM برای 1920×1080: Go stdlib = 11MB، libvips = 600KB.

نتایج بنچمارک (Apple M2)
عملیات Go stdlib libvips بهبود
Decode JPEG 1920×1080 ~28 ms ~3.8 ms 7.5×
Resize 1920→960 ~8 ms ~0.9 ms
Thumbnail 4K → 256px ~91 ms ~9 ms 10×
Encode WebP 800×600 ~1.8 ms واقعی
Pipeline کامل ~68 ms ~8.5 ms
Peak RAM (1920×1080) ~11 MB ~0.6 MB 18× کمتر
# اجرای بنچمارک مقایسه‌ای
go test -bench=. -benchmem -count=3 ./adapters/vips/
Worker Pool و Backpressure
بدون pool (100 request همزمان):   100 goroutine → احتمال OOM
با pool (WorkerCount=8):           8 goroutine فعال + 92 در صف → ثبات کامل
err := proc.Submit(job)
if err == apperrors.ErrWorkerPoolFull {
    // HTTP 429 یا ذخیره در Redis queue
}

🧪 تست و بنچمارک

# تمام تست‌ها
go test ./...

# با race detector
go test -race ./...

# تست‌های خاص
go test -run TestProcess_JPEG_Resize -v ./...
go test -run TestWorkerPool_Async -v ./...
go test -run TestBatch -v ./...

# بنچمارک Go stdlib vs libvips
go test -bench=. -benchmem -count=3 ./adapters/vips/

# بنچمارک کل ماژول
go test -bench=. -benchmem ./...

# پوشش کد
go test -cover ./...
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out

نمونه خروجی بنچمارک:

BenchmarkDecode_Stdlib_1920x1080-8     40    28400000 ns/op   8388608 B/op    12 allocs/op
BenchmarkDecode_Vips_1920x1080-8      300     3800000 ns/op    204800 B/op     4 allocs/op
BenchmarkThumbnail_Stdlib_4K-8         10    91000000 ns/op  22020096 B/op    18 allocs/op
BenchmarkThumbnail_Vips_4K-8          200     9200000 ns/op    409600 B/op     5 allocs/op
BenchmarkPipeline_Stdlib-8             15    68000000 ns/op  11534336 B/op    42 allocs/op
BenchmarkPipeline_Vips-8              120     8500000 ns/op    614400 B/op     8 allocs/op

📊 مقایسه با رقبا

ویژگی imageprocessor disintegration/imaging h2non/bimg davidbyttow/govips
Clean Architecture
Pipeline قابل توسعه
Worker Pool داخلی
Adaptive Compression
Multi-Variant موازی
Async Queue
Custom Storage
Hook/Metrics
libvips Backend
سرعت خام بالا کم بسیار بالا بالا

📦 وابستگی‌ها

پکیج نسخه دلیل
github.com/davidbyttow/govips/v2 v2.14.0 libvips binding — decode، encode، resize، thumbnail
golang.org/x/image v0.18.0 resampling با کیفیت بالا برای Go stdlib steps

🗺️ نقشه راه

  • libvips backend (VipsResizeStep، VipsThumbnailStep، VipsStripEXIFStep، VipsAutoRotateStep)
  • WebP encode واقعی با libwebp
  • پشتیبانی از AVIF و HEIC
  • ادپتر Google Cloud Storage
  • ادپتر Azure Blob Storage
  • پشتیبانی از GIF
  • Redis queue برای async job‌ها
  • Prometheus metrics exporter
  • OpenTelemetry tracing
  • CLI برای پردازش دسته‌ای از command line

🤝 مشارکت در پروژه

git clone https://github.com/alienrobotninja/imageprocessor.git
cd imageprocessor
git checkout -b feature/your-feature

go test -race ./...
go vet ./...

git commit -m "feat: add your feature"
git push origin feature/your-feature

قوانین:

  • هر feature باید unit test داشته باشد
  • رعایت اصل zero global state
  • کامنت‌گذاری به انگلیسی برای سازگاری با Go community

📄 لایسنس

MIT License — آزاد برای استفاده تجاری و شخصی


ساخته‌شده با ❤️ برای جامعه‌ی Go

Documentation

Index

Constants

View Source
const (
	JPEG = core.FormatJPEG
	PNG  = core.FormatPNG
	WebP = core.FormatWebP
)

Re-export Format constants for convenience.

Variables

This section is empty.

Functions

func AdaptiveCompress

func AdaptiveCompress(reg core.Registry, targetBytes int64, minQ, maxQ int) core.Step

AdaptiveCompress returns a step that iteratively reduces quality to hit a target size in bytes.

func ConvertFormat

func ConvertFormat(f core.Format) core.Step

ConvertFormat instructs subsequent steps to use the given output format.

func Crop

func Crop(x, y, width, height int) core.Step

Crop returns a crop step.

func Decode

func Decode() core.Step

Decode returns a step that decodes img.Data → img.Image.

func DecodeWith

func DecodeWith(reg core.Registry) core.Step

DecodeWith returns a decode step bound to the given registry.

func DefaultConfig

func DefaultConfig() config.Config

DefaultConfig returns a sensible production configuration.

func Encode

func Encode() core.Step

Encode returns an encode step with default options. Prefer using the processor's Process method which auto-wires the registry.

func EncodeWith

func EncodeWith(reg core.Registry, opts core.EncodeOptions) core.Step

EncodeWith returns an encode step bound to the given registry and options.

func FromReader

func FromReader(r io.Reader) core.Source

FromReader creates a Source from an io.Reader.

func FromReaderWithMeta

func FromReaderWithMeta(r io.Reader, size int64, contentType, name string) core.Source

FromReaderWithMeta creates a Source with known size and content-type hints.

func Grayscale

func Grayscale() core.Step

Grayscale returns a step that converts the image to grayscale.

func Quality

func Quality(q int) core.Step

Quality stores the desired encode quality (1-100) for the next Encode step.

func Resize

func Resize(width, height int) core.Step

Resize returns a resize step. Pass 0 for one axis to preserve aspect ratio.

func StripEXIF

func StripEXIF() core.Step

StripEXIF returns a step that removes EXIF metadata.

func Thumbnail

func Thumbnail(size int) core.Step

Thumbnail returns a square thumbnail step.

Types

type Processor

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

Processor is the primary entry point.

func New

func New(cfg config.Config) *Processor

New creates a fully wired Processor with default JPEG, PNG, and WebP codecs registered. Pass a custom config.Config to override defaults.

func (*Processor) AddHook

func (p *Processor) AddHook(h core.Hook)

AddHook registers an observer for pipeline step events.

func (*Processor) Batch

func (p *Processor) Batch(ctx context.Context, sources []core.Source, steps ...core.Step) ([]*core.ProcessingResult, []error)

Batch runs the same steps on multiple sources concurrently.

func (*Processor) Inner

func (p *Processor) Inner() *core.Processor

Inner exposes the underlying core.Processor for advanced use (e.g., direct registry access in tests). Prefer the high-level API for normal usage.

func (*Processor) NewPipeline

func (p *Processor) NewPipeline(steps ...core.Step) *pipeline.Pipeline

NewPipeline creates a reusable, standalone pipeline.

func (*Processor) Process

func (p *Processor) Process(ctx context.Context, src core.Source, steps ...core.Step) (*core.ProcessingResult, error)

Process executes the provided steps synchronously and returns the result.

func (*Processor) ProcessVariants

func (p *Processor) ProcessVariants(
	ctx context.Context,
	src core.Source,
	baseSteps []core.Step,
	variants []core.VariantDefinition,
) (*core.ProcessingResult, error)

ProcessVariants runs base steps and then produces named variants in parallel.

func (*Processor) RegisterDecoder

func (p *Processor) RegisterDecoder(f core.Format, d core.Decoder)

RegisterDecoder registers a custom decoder for the given format.

func (*Processor) RegisterEncoder

func (p *Processor) RegisterEncoder(f core.Format, e core.Encoder)

RegisterEncoder registers a custom encoder for the given format.

func (*Processor) SetLogger

func (p *Processor) SetLogger(l core.Logger)

SetLogger attaches a structured logger.

func (*Processor) SetMetrics

func (p *Processor) SetMetrics(m core.MetricsCollector)

SetMetrics attaches a metrics collector.

func (*Processor) Start

func (p *Processor) Start()

Start starts the background worker pool.

func (*Processor) Stats

func (p *Processor) Stats() (processed, errors int64)

Stats returns lightweight processing statistics.

func (*Processor) Stop

func (p *Processor) Stop()

Stop drains and shuts down the worker pool.

func (*Processor) Submit

func (p *Processor) Submit(job core.Job) error

Submit enqueues an async job for the worker pool.

Directories

Path Synopsis
adapters
decoder
Package decoder provides format-specific image decoders.
Package decoder provides format-specific image decoders.
storage
Package storage provides StorageAdapter implementations.
Package storage provides StorageAdapter implementations.
Package hooks provides production-ready Hook and Logger implementations.
Package hooks provides production-ready Hook and Logger implementations.
Package pipeline wires steps together, runs hooks, and handles retries.
Package pipeline wires steps together, runs hooks, and handles retries.

Jump to

Keyboard shortcuts

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