Files
image2api/backend/internal/service/upload.go
T
chiyiandDevin 27d58cfb5d feat(canvas): 画布 Memphis 化并补全编辑功能
- 后端新增 POST /admin/api/my-images 上传接口:图片存入用户
  owner 目录并生成缩略图,复用 /images 服务与 my-images picker
- 本地图片三种入画布路径:上传按钮 / 拖入舞台(落点即拖放
  位置) / Ctrl+V 粘贴
- 节点选中后显示悬浮工具条(预览/复制/置顶/删除)与右下角
  缩放手柄;图片等比缩放,便签自由缩放;Ctrl+D 复制选中(含
  相互连线);双击空白建笔记;按 1 / ⤢ 按钮适应全部内容
- 整套画布 UI 换 Memphis:纸张底+墨点网格、黑边硬影节点、
  黄色贴纸便签、橙色连线/选中态、虚线框选、顶栏/生成面板/
  预览灯箱/图片选择器全部换墨边 chunky 样式,随站点明暗主题

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-08 17:45:41 +08:00

51 lines
1.5 KiB
Go

package service
import (
"bytes"
"context"
"errors"
"fmt"
"image"
_ "image/gif"
_ "image/jpeg"
_ "image/png"
"strings"
"time"
_ "golang.org/x/image/webp"
)
// SaveOwnedImage stores a user-uploaded image under their owner directory so it
// behaves like a generated output: it shows up in the 我的图片 picker, can be
// dropped onto the infinite canvas, and is served by /images/<owner>/<name>.
// format must be a decoder-registered image format ("png", "jpeg", ...).
func (s *AdminReadService) SaveOwnedImage(ctx context.Context, owner, format string, data []byte) (string, error) {
owner = strings.TrimSpace(owner)
if owner == "" || s.store == nil || !s.store.Configured() {
return "", errors.New("storage not configured")
}
ext := strings.ToLower(strings.TrimSpace(format))
contentType := ""
switch ext {
case "jpeg":
ext = "jpg"
contentType = "image/jpeg"
case "png", "gif", "webp":
contentType = "image/" + ext
default:
return "", errors.New("unsupported image format")
}
if _, _, err := image.DecodeConfig(bytes.NewReader(data)); err != nil {
return "", errors.New("invalid image data")
}
key := fmt.Sprintf("%s/up_%d%s.%s", owner, time.Now().Unix(), randomUpper(6), ext)
if err := s.store.Put(ctx, key, data, contentType); err != nil {
return "", err
}
// Best-effort thumbnail, same convention as generated outputs.
if thumb, terr := makeThumbnail(data); terr == nil {
_ = s.store.Put(ctx, ThumbKey(key), thumb, "image/jpeg")
}
return key, nil
}