[feature] migrate to monorepo
Some checks failed
Build Backend / Build Docker Image (push) Successful in 3m33s
Test Backend / test (push) Failing after 31s

This commit is contained in:
CDN 2025-02-21 00:49:20 +08:00
commit 05ddc1f783
Signed by: CDN
GPG key ID: 0C656827F9F80080
267 changed files with 75165 additions and 0 deletions

View 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
}
}

View 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")
}
}