github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/pkg/thumb/vips.go (about) 1 package thumb 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 model "github.com/cloudreve/Cloudreve/v3/models" 8 "github.com/cloudreve/Cloudreve/v3/pkg/util" 9 "github.com/gofrs/uuid" 10 "io" 11 "os/exec" 12 "path/filepath" 13 "strings" 14 ) 15 16 func init() { 17 RegisterGenerator(&VipsGenerator{}) 18 } 19 20 type VipsGenerator struct { 21 exts []string 22 lastRawExts string 23 } 24 25 func (v *VipsGenerator) Generate(ctx context.Context, file io.Reader, src, name string, options map[string]string) (*Result, error) { 26 vipsOpts := model.GetSettingByNames("thumb_vips_path", "thumb_vips_exts", "thumb_encode_quality", "thumb_encode_method", "temp_path") 27 28 if v.lastRawExts != vipsOpts["thumb_vips_exts"] { 29 v.exts = strings.Split(vipsOpts["thumb_vips_exts"], ",") 30 } 31 32 if !util.IsInExtensionList(v.exts, name) { 33 return nil, fmt.Errorf("unsupported image format: %w", ErrPassThrough) 34 } 35 36 outputOpt := ".png" 37 if vipsOpts["thumb_encode_method"] == "jpg" { 38 outputOpt = fmt.Sprintf(".jpg[Q=%s]", vipsOpts["thumb_encode_quality"]) 39 } 40 41 cmd := exec.CommandContext(ctx, 42 vipsOpts["thumb_vips_path"], "thumbnail_source", "[descriptor=0]", outputOpt, options["thumb_width"], 43 "--height", options["thumb_height"]) 44 45 tempPath := filepath.Join( 46 util.RelativePath(vipsOpts["temp_path"]), 47 "thumb", 48 fmt.Sprintf("thumb_%s", uuid.Must(uuid.NewV4()).String()), 49 ) 50 51 thumbFile, err := util.CreatNestedFile(tempPath) 52 if err != nil { 53 return nil, fmt.Errorf("failed to create temp file: %w", err) 54 } 55 56 defer thumbFile.Close() 57 58 // Redirect IO 59 var vipsErr bytes.Buffer 60 cmd.Stdin = file 61 cmd.Stdout = thumbFile 62 cmd.Stderr = &vipsErr 63 64 if err := cmd.Run(); err != nil { 65 util.Log().Warning("Failed to invoke vips: %s", vipsErr.String()) 66 return nil, fmt.Errorf("failed to invoke vips: %w", err) 67 } 68 69 return &Result{Path: tempPath}, nil 70 } 71 72 func (v *VipsGenerator) Priority() int { 73 return 100 74 } 75 76 func (v *VipsGenerator) EnableFlag() string { 77 return "thumb_vips_enabled" 78 }