[feature] migrate to monorepo
This commit is contained in:
commit
05ddc1f783
267 changed files with 75165 additions and 0 deletions
59
backend/pkg/imageutil/processor.go
Normal file
59
backend/pkg/imageutil/processor.go
Normal file
|
@ -0,0 +1,59 @@
|
|||
package imageutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image"
|
||||
_ "image/gif"
|
||||
_ "image/jpeg"
|
||||
_ "image/png"
|
||||
"io"
|
||||
|
||||
"github.com/chai2010/webp"
|
||||
)
|
||||
|
||||
type ProcessOptions struct {
|
||||
Lossless bool
|
||||
Quality float32 // 0-100
|
||||
Compression int // 0-6
|
||||
}
|
||||
|
||||
// DefaultOptions returns default processing options
|
||||
func DefaultOptions() ProcessOptions {
|
||||
return ProcessOptions{
|
||||
Lossless: true,
|
||||
Quality: 90,
|
||||
Compression: 4,
|
||||
}
|
||||
}
|
||||
|
||||
// ProcessImage converts any supported image to WebP format
|
||||
func ProcessImage(input io.Reader, opts ProcessOptions) ([]byte, error) {
|
||||
// Decode the original image
|
||||
img, _, err := image.Decode(input)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode image: %w", err)
|
||||
}
|
||||
|
||||
// Encode to WebP
|
||||
var buf bytes.Buffer
|
||||
if err := webp.Encode(&buf, img, &webp.Options{
|
||||
Lossless: opts.Lossless,
|
||||
Quality: opts.Quality,
|
||||
Exact: true,
|
||||
}); err != nil {
|
||||
return nil, fmt.Errorf("failed to encode to WebP: %w", err)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// IsImageFormat checks if the given format is a supported image format
|
||||
func IsImageFormat(contentType string) bool {
|
||||
switch contentType {
|
||||
case "image/jpeg", "image/png", "image/gif", "image/webp":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
100
backend/pkg/imageutil/processor_test.go
Normal file
100
backend/pkg/imageutil/processor_test.go
Normal file
|
@ -0,0 +1,100 @@
|
|||
package imageutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIsImageFormat(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
contentType string
|
||||
want bool
|
||||
}{
|
||||
{"JPEG", "image/jpeg", true},
|
||||
{"PNG", "image/png", true},
|
||||
{"GIF", "image/gif", true},
|
||||
{"WebP", "image/webp", true},
|
||||
{"Invalid", "image/invalid", false},
|
||||
{"Empty", "", false},
|
||||
{"Text", "text/plain", false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := IsImageFormat(tt.contentType); got != tt.want {
|
||||
t.Errorf("IsImageFormat(%q) = %v, want %v", tt.contentType, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultOptions(t *testing.T) {
|
||||
opts := DefaultOptions()
|
||||
|
||||
if !opts.Lossless {
|
||||
t.Error("DefaultOptions().Lossless = false, want true")
|
||||
}
|
||||
if opts.Quality != 90 {
|
||||
t.Errorf("DefaultOptions().Quality = %v, want 90", opts.Quality)
|
||||
}
|
||||
if opts.Compression != 4 {
|
||||
t.Errorf("DefaultOptions().Compression = %v, want 4", opts.Compression)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessImage(t *testing.T) {
|
||||
// Create a test image
|
||||
img := image.NewRGBA(image.Rect(0, 0, 100, 100))
|
||||
for y := 0; y < 100; y++ {
|
||||
for x := 0; x < 100; x++ {
|
||||
img.Set(x, y, color.RGBA{R: 255, G: 0, B: 0, A: 255})
|
||||
}
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := png.Encode(&buf, img); err != nil {
|
||||
t.Fatalf("Failed to create test PNG: %v", err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
opts ProcessOptions
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Default options",
|
||||
opts: DefaultOptions(),
|
||||
},
|
||||
{
|
||||
name: "Custom quality",
|
||||
opts: ProcessOptions{
|
||||
Lossless: false,
|
||||
Quality: 75,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
reader := bytes.NewReader(buf.Bytes())
|
||||
result, err := ProcessImage(reader, tt.opts)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ProcessImage() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !tt.wantErr && len(result) == 0 {
|
||||
t.Error("ProcessImage() returned empty result")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Test with invalid input
|
||||
_, err := ProcessImage(bytes.NewReader([]byte("invalid image data")), DefaultOptions())
|
||||
if err == nil {
|
||||
t.Error("ProcessImage() with invalid input should return error")
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue