web: картинки заметки отдаются через ресайз
Раньше страница ссылалась прямо на файлы Memos, и в браузер уезжали
исходники с телефона на десятки мегабайт. Теперь вложения идут через
эндпоинт /image/{uid}: скачиваем тем же клиентом, что и телеграм-часть,
ужимаем ImageMagick до 1600px по большей стороне и кэшируем результат
в памяти (FIFO на 20 картинок) плюс Cache-Control на час.
GIF и SVG отдаются без конверсии: анимация и вектор в JPEG теряются.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,10 @@ import (
|
||||
|
||||
const maxTelegramPhotoSize = 10 * 1024 * 1024 // 10 MB
|
||||
|
||||
// webImageMaxSide — максимальная сторона картинки, отдаваемой на веб-страницу.
|
||||
// Экран всё равно не покажет больше, а исходники с телефона весят десятки мегабайт.
|
||||
const webImageMaxSide = 1600
|
||||
|
||||
// CompressImage compresses an image if it exceeds Telegram's 10 MB photo limit.
|
||||
// It uses ImageMagick's magick command to convert via stdin/stdout.
|
||||
// Returns the (possibly compressed) data, updated filename, and any error.
|
||||
@@ -43,6 +47,36 @@ func CompressImage(ctx context.Context, data []byte, filename string) (out []byt
|
||||
return out, newFilename, nil
|
||||
}
|
||||
|
||||
// ResizeForWeb downscales an image to webImageMaxSide and re-encodes it as JPEG.
|
||||
// Images smaller than the limit are only re-encoded (ImageMagick's ">" modifier
|
||||
// never enlarges). Returns the data and the resulting MIME type.
|
||||
func ResizeForWeb(ctx context.Context, data []byte, mimeType string) ([]byte, string, error) {
|
||||
// GIF (анимация) и SVG (вектор) при конверсии в JPEG теряют смысл — отдаём как есть.
|
||||
if !resizableMIME(mimeType) {
|
||||
return data, mimeType, nil
|
||||
}
|
||||
|
||||
out, err := runMagick(ctx, data,
|
||||
"-auto-orient",
|
||||
"-resize", fmt.Sprintf("%dx%d>", webImageMaxSide, webImageMaxSide),
|
||||
"-quality", "85",
|
||||
"-strip",
|
||||
)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("resize image: %w", err)
|
||||
}
|
||||
|
||||
return out, "image/jpeg", nil
|
||||
}
|
||||
|
||||
func resizableMIME(mimeType string) bool {
|
||||
switch mimeType {
|
||||
case "image/gif", "image/svg+xml":
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func runMagick(ctx context.Context, data []byte, args ...string) ([]byte, error) {
|
||||
cmdArgs := append([]string{"-"}, args...)
|
||||
cmdArgs = append(cmdArgs, "jpeg:-")
|
||||
|
||||
Reference in New Issue
Block a user