popiart-server
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

197 lines
4.0 KiB

package server
import (
"fmt"
"strconv"
"strings"
)
var imageAspectRatioSeparators = strings.NewReplacer(
":", ":",
"/", ":",
"/", ":",
"×", ":",
"*", ":",
"x", ":",
"X", ":",
)
var canonicalImageAspectRatioLabels = map[string]string{
"7:3": "21:9",
"16:9": "16:9",
"4:3": "4:3",
"3:2": "3:2",
"1:1": "1:1",
"9:16": "9:16",
"3:4": "3:4",
"2:3": "2:3",
"5:4": "5:4",
"4:5": "4:5",
}
var seedreamAspectRatioSizes = map[string]string{
"21:9": "2520x1080",
"16:9": "2048x1152",
"4:3": "2048x1536",
"3:2": "2304x1536",
"1:1": "2048x2048",
"9:16": "1152x2048",
"3:4": "1536x2048",
"2:3": "1536x2304",
"5:4": "1920x1536",
"4:5": "1536x1920",
}
var exactImageSizeAspectRatios = map[string]string{
"1024x1024": "1:1",
"1920x1920": "1:1",
"1536x1024": "3:2",
"1024x1536": "2:3",
"1792x1024": "16:9",
"1024x1792": "9:16",
}
func normalizeImageAspectRatio(value string) string {
width, height, ok := parseAspectRatioDimensions(value)
if !ok {
return strings.TrimSpace(value)
}
return canonicalAspectRatioLabel(width, height)
}
func parseAspectRatioDimensions(value string) (int, int, bool) {
value = strings.TrimSpace(value)
if value == "" {
return 0, 0, false
}
normalized := imageAspectRatioSeparators.Replace(value)
parts := strings.Split(normalized, ":")
if len(parts) != 2 {
return 0, 0, false
}
width, errWidth := strconv.Atoi(strings.TrimSpace(parts[0]))
height, errHeight := strconv.Atoi(strings.TrimSpace(parts[1]))
if errWidth != nil || errHeight != nil || width <= 0 || height <= 0 {
return 0, 0, false
}
return width, height, true
}
func canonicalAspectRatioLabel(width, height int) string {
rw, rh := reduceImageRatio(width, height)
key := fmt.Sprintf("%d:%d", rw, rh)
if label, ok := canonicalImageAspectRatioLabels[key]; ok {
return label
}
return key
}
func reduceImageRatio(width, height int) (int, int) {
g := imageGCD(width, height)
if g == 0 {
return width, height
}
return width / g, height / g
}
func imageGCD(a, b int) int {
for b != 0 {
a, b = b, a%b
}
if a < 0 {
return -a
}
return a
}
func parseExactImageSize(value string) (int, int, bool) {
value = strings.TrimSpace(strings.ToLower(value))
if value == "" {
return 0, 0, false
}
parts := strings.Split(value, "x")
if len(parts) != 2 {
return 0, 0, false
}
width, errWidth := strconv.Atoi(strings.TrimSpace(parts[0]))
height, errHeight := strconv.Atoi(strings.TrimSpace(parts[1]))
if errWidth != nil || errHeight != nil || width <= 0 || height <= 0 {
return 0, 0, false
}
return width, height, true
}
func normalizeImageSizeToken(value string) string {
value = strings.TrimSpace(value)
if value == "" {
return ""
}
switch strings.ToUpper(value) {
case "1K", "2K", "4K":
return strings.ToUpper(value)
}
width, height, ok := parseExactImageSize(value)
if !ok {
return value
}
return fmt.Sprintf("%dx%d", width, height)
}
func deriveAspectRatioFromImageSize(value string) string {
value = normalizeImageSizeToken(value)
if ratio, ok := exactImageSizeAspectRatios[value]; ok {
return ratio
}
width, height, ok := parseExactImageSize(value)
if !ok {
if ratio := normalizeImageAspectRatio(value); ratio != "" {
return ratio
}
return ""
}
return canonicalAspectRatioLabel(width, height)
}
func geminiImageSizeFromValue(value string) string {
value = normalizeImageSizeToken(value)
switch value {
case "1K", "2K", "4K":
return value
}
width, height, ok := parseExactImageSize(value)
if !ok {
return ""
}
longEdge := width
if height > longEdge {
longEdge = height
}
switch {
case longEdge <= 1024:
return "1K"
case longEdge <= 2560:
return "2K"
default:
return "4K"
}
}
func seedreamImageSizeFromAspectRatio(value string) string {
if ratio := normalizeImageAspectRatio(value); ratio != "" {
if size, ok := seedreamAspectRatioSizes[ratio]; ok {
return size
}
}
return ""
}
func supportedSeedreamSize(modelID, value string) bool {
value = strings.ToUpper(strings.TrimSpace(value))
if value == "" {
return false
}
_, ok := supportedSeedreamSizes(modelID)[value]
return ok
}