Introduces the Go photo-api service, nginx/systemd deploy wiring, and Next.js gallery/lightbox pages so event photos can be managed and browsed. Co-authored-by: Cursor <cursoragent@cursor.com>
31 lines
1.3 KiB
Go
31 lines
1.3 KiB
Go
package imaging
|
|
|
|
import "bytes"
|
|
|
|
// Sniff identifies an image by magic bytes, ignoring the client-supplied
|
|
// filename and Content-Type — same policy as backend/src/routes/media.ts
|
|
// detectImageType. Returns the canonical content type and extension, or
|
|
// ok=false with a human-readable reason.
|
|
func Sniff(head []byte) (contentType, ext string, ok bool, reason string) {
|
|
switch {
|
|
case len(head) >= 3 && bytes.Equal(head[:3], []byte{0xFF, 0xD8, 0xFF}):
|
|
return "image/jpeg", ".jpg", true, ""
|
|
case len(head) >= 8 && bytes.Equal(head[:8], []byte{0x89, 'P', 'N', 'G', 0x0D, 0x0A, 0x1A, 0x0A}):
|
|
return "image/png", ".png", true, ""
|
|
case len(head) >= 6 && (bytes.Equal(head[:6], []byte("GIF87a")) || bytes.Equal(head[:6], []byte("GIF89a"))):
|
|
return "image/gif", ".gif", true, ""
|
|
case len(head) >= 12 && bytes.Equal(head[:4], []byte("RIFF")) && bytes.Equal(head[8:12], []byte("WEBP")):
|
|
return "image/webp", ".webp", true, ""
|
|
}
|
|
if len(head) >= 12 && bytes.Equal(head[4:8], []byte("ftyp")) {
|
|
brand := string(head[8:12])
|
|
switch brand {
|
|
case "heic", "heix", "hevc", "hevx", "mif1", "msf1":
|
|
return "image/heic", ".heic", true, ""
|
|
case "avif", "avis":
|
|
return "", "", false, "AVIF is not supported, please upload JPEG, PNG, WebP, GIF or HEIC"
|
|
}
|
|
}
|
|
return "", "", false, "unsupported file type, please upload JPEG, PNG, WebP, GIF or HEIC"
|
|
}
|