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  }