package admin import ( "context" "database/sql" "encoding/base64" "os" "path/filepath" "regexp" "strings" ) // برخی ابزارها (مثلِ خروجیِ AI) یک PNG را داخلِ یک با base64 قرار می‌دهند. // flutter_svg نمی‌تواند این «SVGِ رستری» را رندر کند، پس آن را به PNG واقعی تبدیل // می‌کنیم. var rasterInSVG = regexp.MustCompile(`data:image/(png|jpe?g);base64,([A-Za-z0-9+/=\s]+)`) // extractEmbeddedRaster اگر محتوای SVG صرفاً یک تصویرِ رستریِ base64 باشد، آن را // استخراج می‌کند (بایت‌های خام + پسوند). برای SVGهای واقعیِ برداری false برمی‌گرداند. func extractEmbeddedRaster(svg []byte) (data []byte, ext string, ok bool) { m := rasterInSVG.FindSubmatch(svg) if m == nil { return nil, "", false } ext = "png" if strings.HasPrefix(string(m[1]), "jp") { ext = "jpg" } b64 := regexp.MustCompile(`\s`).ReplaceAll(m[2], nil) raw, err := base64.StdEncoding.DecodeString(string(b64)) if err != nil || len(raw) == 0 { return nil, "", false } return raw, ext, true } // convertRasterAvatars فایل‌های آواتارِ svg را که در واقع رستر هستند به png/jpg // تبدیل می‌کند و img_ext را در DB به‌روزرسانی می‌کند. یک‌بار در startup اجرا می‌شود // (idempotent). برای رفعِ آواتارهایی که قبلاً به‌صورتِ «svgِ رستری» آپلود شده‌اند. func convertRasterAvatars(ctx context.Context, db *sql.DB, dir string) { if dir == "" { return } rows, err := db.QueryContext(ctx, `SELECT id FROM avatars WHERE img_ext = 'svg'`) if err != nil { return } var ids []string for rows.Next() { var id string if rows.Scan(&id) == nil { ids = append(ids, id) } } rows.Close() for _, id := range ids { svgPath := filepath.Join(dir, id+".svg") content, err := os.ReadFile(svgPath) if err != nil { continue } raw, ext, ok := extractEmbeddedRaster(content) if !ok { continue // SVGِ واقعیِ برداری — دست نزن. } if err := os.WriteFile(filepath.Join(dir, id+"."+ext), raw, 0o644); err != nil { continue } _ = os.Remove(svgPath) _, _ = db.ExecContext(ctx, `UPDATE avatars SET img_ext = ? WHERE id = ?`, ext, id) } } // ConvertRasterAvatars نسخه‌ی عمومی برای فراخوانی از main در startup. func ConvertRasterAvatars(ctx context.Context, db *sql.DB, dir string) { convertRasterAvatars(ctx, db, dir) }