imageMaxBytes = 20 << 20
)
+var (
+ errImageSize = errors.New("image exceeds 20 MB")
+ errImageFormat = errors.New("use a JPEG, PNG, or WebP image")
+)
+
// ImageStore holds immutable images shared by the root, children, and
// subagents. Names are the SHA-256 of the bytes with the decoded format as
// extension. Publication is atomic and does not replace an existing image.
func imageFormat(data []byte) (string, error) {
if len(data) > imageMaxBytes {
- return "", errors.New("image exceeds 20 MB")
+ return "", errImageSize
}
config, format, err := image.DecodeConfig(bytes.NewReader(data))
if err != nil || config.Width <= 0 || config.Height <= 0 {
- return "", errors.New("use a JPEG, PNG, or WebP image")
+ return "", errImageFormat
}
switch format {
case "png", "webp":
return format, nil
default:
- return "", errors.New("use a JPEG, PNG, or WebP image")
+ return "", errImageFormat
}
}
}
if len(data) > imageMaxBytes {
- return nil, errors.New("image exceeds 20 MB")
+ return nil, errImageSize
}
return data, nil
}
func imageText(names []string, caption string) string {
- var text strings.Builder
-
+ lines := make([]string, 0, len(names)+1)
for _, name := range names {
- text.WriteString("[image " + name + "]\n")
+ lines = append(lines, "[image "+name+"]")
}
- text.WriteString(caption)
+ if caption != "" {
+ lines = append(lines, caption)
+ }
- return strings.TrimSuffix(text.String(), "\n")
+ return strings.Join(lines, "\n")
}