first commit
This commit is contained in:
113
pkg/images/processor.go
Normal file
113
pkg/images/processor.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package images
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/h2non/bimg"
|
||||
)
|
||||
|
||||
type ProcessOptions struct {
|
||||
Width int
|
||||
Height int
|
||||
Quality int
|
||||
Format string // webp, avif, png, jpg, jpeg
|
||||
Cover bool
|
||||
}
|
||||
|
||||
const (
|
||||
DefaultQuality = 90
|
||||
DefaultFormat = "avif"
|
||||
)
|
||||
|
||||
func NormalizeOptions(opts ProcessOptions) (ProcessOptions, error) {
|
||||
if opts.Width < 0 || opts.Height < 0 {
|
||||
return ProcessOptions{}, fmt.Errorf("width/height negatif olamaz")
|
||||
}
|
||||
|
||||
if opts.Quality == 0 {
|
||||
opts.Quality = DefaultQuality
|
||||
}
|
||||
if opts.Quality < 1 || opts.Quality > 100 {
|
||||
return ProcessOptions{}, fmt.Errorf("quality 1-100 araliginda olmali")
|
||||
}
|
||||
|
||||
format := strings.ToLower(strings.TrimSpace(opts.Format))
|
||||
if format == "" {
|
||||
format = DefaultFormat
|
||||
}
|
||||
if format == "jpg" {
|
||||
format = "jpeg"
|
||||
}
|
||||
|
||||
switch format {
|
||||
case "webp", "avif", "png", "jpeg":
|
||||
opts.Format = format
|
||||
default:
|
||||
return ProcessOptions{}, fmt.Errorf("desteklenmeyen format: %s", format)
|
||||
}
|
||||
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
func ProcessImage(buffer []byte, opts ProcessOptions) ([]byte, error) {
|
||||
normalized, err := NormalizeOptions(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
img := bimg.NewImage(buffer)
|
||||
|
||||
origSize, _ := img.Size()
|
||||
origType := img.Type()
|
||||
origKB := len(buffer) / 1024
|
||||
|
||||
options := bimg.Options{
|
||||
Width: normalized.Width,
|
||||
Height: normalized.Height,
|
||||
Quality: normalized.Quality,
|
||||
}
|
||||
|
||||
// Cover mode: Enlarge and crop to fill the dimensions
|
||||
if normalized.Cover {
|
||||
options.Crop = true
|
||||
options.Enlarge = true
|
||||
}
|
||||
|
||||
format := normalized.Format
|
||||
switch format {
|
||||
case "webp":
|
||||
options.Type = bimg.WEBP
|
||||
case "avif":
|
||||
options.Type = bimg.AVIF
|
||||
case "png":
|
||||
options.Type = bimg.PNG
|
||||
case "jpg", "jpeg":
|
||||
options.Type = bimg.JPEG
|
||||
}
|
||||
|
||||
log.Printf("[IMAGE-PROCESS-START] Original: %dx%d (%s, %dKB). Target -> W:%d, H:%d, Q:%d, Format:%v, Cover:%v",
|
||||
origSize.Width, origSize.Height, origType, origKB,
|
||||
options.Width, options.Height, options.Quality, options.Type, normalized.Cover)
|
||||
|
||||
newImage, err := img.Process(options)
|
||||
if err != nil {
|
||||
log.Printf("[IMAGE-PROCESS-ERROR] Failed after %v: %v", time.Since(startTime), err)
|
||||
return nil, fmt.Errorf("failed to process image: %w", err)
|
||||
}
|
||||
|
||||
newKB := len(newImage) / 1024
|
||||
diff := origKB - newKB
|
||||
|
||||
log.Printf("[IMAGE-PROCESS-DONE] Success in %v! New Size: %dKB (Difference: %dKB)", time.Since(startTime), newKB, diff)
|
||||
|
||||
return newImage, nil
|
||||
}
|
||||
|
||||
func GetSize(buffer []byte) (bimg.ImageSize, error) {
|
||||
img := bimg.NewImage(buffer)
|
||||
return img.Size()
|
||||
}
|
||||
44
pkg/images/processor_test.go
Normal file
44
pkg/images/processor_test.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package images
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNormalizeOptionsDefaults(t *testing.T) {
|
||||
opts, err := NormalizeOptions(ProcessOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if opts.Quality != DefaultQuality {
|
||||
t.Fatalf("expected default quality %d, got %d", DefaultQuality, opts.Quality)
|
||||
}
|
||||
if opts.Format != DefaultFormat {
|
||||
t.Fatalf("expected default format %q, got %q", DefaultFormat, opts.Format)
|
||||
}
|
||||
if opts.Width != 0 || opts.Height != 0 {
|
||||
t.Fatalf("expected width/height to stay 0 when not provided")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeOptionsJPGAlias(t *testing.T) {
|
||||
opts, err := NormalizeOptions(ProcessOptions{Format: "jpg", Quality: 10})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if opts.Format != "jpeg" {
|
||||
t.Fatalf("expected jpeg alias, got %q", opts.Format)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeOptionsRejectsInvalidValues(t *testing.T) {
|
||||
cases := []ProcessOptions{
|
||||
{Width: -1, Quality: 90, Format: "avif"},
|
||||
{Height: -1, Quality: 90, Format: "avif"},
|
||||
{Quality: 101, Format: "avif"},
|
||||
{Quality: 90, Format: "gif"},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
if _, err := NormalizeOptions(tc); err == nil {
|
||||
t.Fatalf("expected error for case: %+v", tc)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user