Skip to content

Commit

Permalink
Config: Disable use of libvips with PHOTOPRISM_DISABLE_VIPS #3981 #4296
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Mayer <michael@photoprism.app>
  • Loading branch information
lastzero committed May 24, 2024
1 parent 49d2892 commit b2f2823
Show file tree
Hide file tree
Showing 15 changed files with 79 additions and 57 deletions.
6 changes: 3 additions & 3 deletions internal/config/config_convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ func (c *Config) ImageMagickBin() string {
return findBin(c.options.ImageMagickBin, "convert")
}

// ImageMagickSkip returns the file extensions not to be used with ImageMagick.
func (c *Config) ImageMagickSkip() string {
return c.options.ImageMagickSkip
// ImageMagickExclude returns the file extensions not to be used with ImageMagick.
func (c *Config) ImageMagickExclude() string {
return c.options.ImageMagickExclude
}

// ImageMagickEnabled checks if ImageMagick can be used for converting media files.
Expand Down
2 changes: 1 addition & 1 deletion internal/config/config_features.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func (c *Config) DisableHeifConvert() bool {
return c.options.DisableHeifConvert
}

// DisableVips checks if conversion of RAW images with SIPS is disabled.
// DisableVips checks if the use of libvips is disabled.
func (c *Config) DisableVips() bool {
return c.options.DisableVips
}
Expand Down
10 changes: 10 additions & 0 deletions internal/config/config_features_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,16 @@ func TestConfig_DisableImageMagick(t *testing.T) {
assert.Equal(t, missing, c.DisableImageMagick())
}

func TestConfig_DisableVips(t *testing.T) {
c := NewConfig(CliTestContext())

assert.Equal(t, false, c.DisableVips())
c.options.DisableVips = true
assert.True(t, c.DisableVips())
c.options.DisableVips = false
assert.Equal(t, false, c.DisableVips())
}

func TestConfig_DisableSips(t *testing.T) {
c := NewConfig(CliTestContext())
missing := c.SipsBin() == ""
Expand Down
18 changes: 9 additions & 9 deletions internal/config/config_raw.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ func (c *Config) DarktableBin() string {
return findBin(c.options.DarktableBin, "darktable-cli")
}

// DarktableSkip returns the file extensions no not be used with Darktable.
func (c *Config) DarktableSkip() string {
return c.options.DarktableSkip
// DarktableExclude returns the file extensions no not be used with Darktable.
func (c *Config) DarktableExclude() string {
return c.options.DarktableExclude
}

// DarktableConfigPath returns the darktable config directory.
Expand Down Expand Up @@ -74,9 +74,9 @@ func (c *Config) RawTherapeeBin() string {
return findBin(c.options.RawTherapeeBin, "rawtherapee-cli")
}

// RawTherapeeSkip returns the file extensions no not be used with RawTherapee.
func (c *Config) RawTherapeeSkip() string {
return c.options.RawTherapeeSkip
// RawTherapeeExclude returns the file extensions no not be used with RawTherapee.
func (c *Config) RawTherapeeExclude() string {
return c.options.RawTherapeeExclude
}

// RawTherapeeEnabled checks if RawTherapee is enabled for RAW conversion.
Expand All @@ -94,9 +94,9 @@ func (c *Config) SipsBin() string {
return findBin(c.options.SipsBin, "sips")
}

// SipsSkip returns the file extensions no not be used with Sips.
func (c *Config) SipsSkip() string {
return c.options.SipsSkip
// SipsExclude returns the file extensions no not be used with Sips.
func (c *Config) SipsExclude() string {
return c.options.SipsExclude
}

// HeifConvertBin returns the heif-convert executable file name.
Expand Down
20 changes: 13 additions & 7 deletions internal/config/config_raw_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ func TestConfig_RawTherapeeBin(t *testing.T) {
assert.True(t, strings.Contains(c.RawTherapeeBin(), "/bin/rawtherapee-cli"))
}

func TestConfig_RawTherapeeSkip(t *testing.T) {
func TestConfig_RawTherapeeExclude(t *testing.T) {
c := NewConfig(CliTestContext())

c.options.RawTherapeeSkip = "foo,bar"
assert.Equal(t, "foo,bar", c.RawTherapeeSkip())
c.options.RawTherapeeSkip = ""
assert.Equal(t, "", c.RawTherapeeSkip())
c.options.RawTherapeeExclude = "foo,bar"
assert.Equal(t, "foo,bar", c.RawTherapeeExclude())
c.options.RawTherapeeExclude = ""
assert.Equal(t, "", c.RawTherapeeExclude())
}

func TestConfig_RawTherapeeEnabled(t *testing.T) {
Expand All @@ -42,10 +42,10 @@ func TestConfig_DarktableBin(t *testing.T) {
assert.True(t, strings.Contains(c.DarktableBin(), "/bin/darktable-cli"))
}

func TestConfig_DarktableSkip(t *testing.T) {
func TestConfig_DarktableExclude(t *testing.T) {
c := NewConfig(CliTestContext())

assert.Equal(t, "raf,cr3", c.DarktableSkip())
assert.Equal(t, "raf, cr3", c.DarktableExclude())
}

func TestConfig_DarktablePresets(t *testing.T) {
Expand Down Expand Up @@ -74,6 +74,12 @@ func TestConfig_SipsEnabled(t *testing.T) {
assert.NotEqual(t, c.DisableSips(), c.SipsEnabled())
}

func TestConfig_SipsExclude(t *testing.T) {
c := NewConfig(CliTestContext())

assert.Equal(t, "avif, avifs, thm", c.SipsExclude())
}

func TestConfig_HeifConvertBin(t *testing.T) {
c := NewConfig(CliTestContext())

Expand Down
4 changes: 4 additions & 0 deletions internal/config/config_thumb.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ func (c *Config) JpegQuality() thumb.Quality {

// ThumbLibrary returns the name of the image processing library to be used for generating thumbnails.
func (c *Config) ThumbLibrary() string {
if c.DisableVips() {
return thumb.LibImaging
}

switch c.options.ThumbLibrary {
case thumb.LibVips, thumb.LibAuto:
return thumb.LibVips
Expand Down
16 changes: 8 additions & 8 deletions internal/config/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -693,10 +693,10 @@ var Flags = CliFlags{
EnvVar: EnvVar("SIPS_BIN"),
}}, {
Flag: cli.StringFlag{
Name: "sips-skip",
Name: "sips-exclude",
Usage: "file `EXTENSIONS` not to be used with Sips *macOS only*",
Value: "avif, avifs, thm",
EnvVar: EnvVar("SIPS_SKIP") + ", " + EnvVar("SIPS_BLACKLIST"),
EnvVar: EnvVar("SIPS_EXCLUDE") + ", " + EnvVar("SIPS_BLACKLIST"),
}}, {
Flag: cli.StringFlag{
Name: "darktable-bin",
Expand All @@ -705,10 +705,10 @@ var Flags = CliFlags{
EnvVar: EnvVar("DARKTABLE_BIN"),
}}, {
Flag: cli.StringFlag{
Name: "darktable-skip",
Name: "darktable-exclude",
Usage: "file `EXTENSIONS` not to be used with Darktable",
Value: "thm",
EnvVar: EnvVar("DARKTABLE_SKIP") + ", " + EnvVar("DARKTABLE_BLACKLIST"),
EnvVar: EnvVar("DARKTABLE_EXCLUDE") + ", " + EnvVar("DARKTABLE_BLACKLIST"),
}}, {
Flag: cli.StringFlag{
Name: "darktable-cache-path",
Expand All @@ -729,10 +729,10 @@ var Flags = CliFlags{
EnvVar: EnvVar("RAWTHERAPEE_BIN"),
}}, {
Flag: cli.StringFlag{
Name: "rawtherapee-skip",
Name: "rawtherapee-exclude",
Usage: "file `EXTENSIONS` not to be used with RawTherapee",
Value: "dng, thm",
EnvVar: EnvVar("RAWTHERAPEE_SKIP") + ", " + EnvVar("RAWTHERAPEE_BLACKLIST"),
EnvVar: EnvVar("RAWTHERAPEE_EXCLUDE") + ", " + EnvVar("RAWTHERAPEE_BLACKLIST"),
}}, {
Flag: cli.StringFlag{
Name: "imagemagick-bin",
Expand All @@ -741,10 +741,10 @@ var Flags = CliFlags{
EnvVar: EnvVar("IMAGEMAGICK_BIN"),
}}, {
Flag: cli.StringFlag{
Name: "imagemagick-skip",
Name: "imagemagick-exclude",
Usage: "file `EXTENSIONS` not to be used with ImageMagick",
Value: "heif, heic, heics, avif, avifs, jxl, thm",
EnvVar: EnvVar("IMAGEMAGICK_SKIP") + ", " + EnvVar("IMAGEMAGICK_BLACKLIST"),
EnvVar: EnvVar("IMAGEMAGICK_EXCLUDE") + ", " + EnvVar("IMAGEMAGICK_BLACKLIST"),
}}, {
Flag: cli.StringFlag{
Name: "heifconvert-bin",
Expand Down
8 changes: 4 additions & 4 deletions internal/config/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,15 +148,15 @@ type Options struct {
FFmpegMapAudio string `yaml:"FFmpegMapAudio" json:"FFmpegMapAudio" flag:"ffmpeg-map-audio"`
ExifToolBin string `yaml:"ExifToolBin" json:"-" flag:"exiftool-bin"`
SipsBin string `yaml:"SipsBin" json:"-" flag:"sips-bin"`
SipsSkip string `yaml:"SipsSkip" json:"-" flag:"sips-skip"`
SipsExclude string `yaml:"SipsExclude" json:"-" flag:"sips-exclude"`
DarktableBin string `yaml:"DarktableBin" json:"-" flag:"darktable-bin"`
DarktableCachePath string `yaml:"DarktableCachePath" json:"-" flag:"darktable-cache-path"`
DarktableConfigPath string `yaml:"DarktableConfigPath" json:"-" flag:"darktable-config-path"`
DarktableSkip string `yaml:"DarktableSkip" json:"-" flag:"darktable-skip"`
DarktableExclude string `yaml:"DarktableExclude" json:"-" flag:"darktable-exclude"`
RawTherapeeBin string `yaml:"RawTherapeeBin" json:"-" flag:"rawtherapee-bin"`
RawTherapeeSkip string `yaml:"RawTherapeeSkip" json:"-" flag:"rawtherapee-skip"`
RawTherapeeExclude string `yaml:"RawTherapeeExclude" json:"-" flag:"rawtherapee-exclude"`
ImageMagickBin string `yaml:"ImageMagickBin" json:"-" flag:"imagemagick-bin"`
ImageMagickSkip string `yaml:"ImageMagickSkip" json:"-" flag:"imagemagick-skip"`
ImageMagickExclude string `yaml:"ImageMagickExclude" json:"-" flag:"imagemagick-exclude"`
HeifConvertBin string `yaml:"HeifConvertBin" json:"-" flag:"heifconvert-bin"`
RsvgConvertBin string `yaml:"RsvgConvertBin" json:"-" flag:"rsvgconvert-bin"`
DownloadToken string `yaml:"DownloadToken" json:"-" flag:"download-token"`
Expand Down
8 changes: 4 additions & 4 deletions internal/config/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,15 +209,15 @@ func (c *Config) Report() (rows [][]string, cols []string) {
{"ffmpeg-map-audio", c.FFmpegMapAudio()},
{"exiftool-bin", c.ExifToolBin()},
{"sips-bin", c.SipsBin()},
{"sips-skip", c.SipsSkip()},
{"sips-exclude", c.SipsExclude()},
{"darktable-bin", c.DarktableBin()},
{"darktable-cache-path", c.DarktableCachePath()},
{"darktable-config-path", c.DarktableConfigPath()},
{"darktable-skip", c.DarktableSkip()},
{"darktable-exclude", c.DarktableExclude()},
{"rawtherapee-bin", c.RawTherapeeBin()},
{"rawtherapee-skip", c.RawTherapeeSkip()},
{"rawtherapee-exclude", c.RawTherapeeExclude()},
{"imagemagick-bin", c.ImageMagickBin()},
{"imagemagick-skip", c.ImageMagickSkip()},
{"imagemagick-exclude", c.ImageMagickExclude()},
{"heifconvert-bin", c.HeifConvertBin()},
{"rsvgconvert-bin", c.RsvgConvertBin()},
{"jpegxldecoder-bin", c.JpegXLDecoderBin()},
Expand Down
6 changes: 4 additions & 2 deletions internal/config/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,8 @@ func CliTestContext() *cli.Context {
globalSet.Int("backup-retain", config.BackupRetain, "doc")
globalSet.String("backup-schedule", config.BackupSchedule, "doc")
globalSet.String("darktable-cli", config.DarktableBin, "doc")
globalSet.String("darktable-skip", config.DarktableSkip, "doc")
globalSet.String("darktable-exclude", config.DarktableExclude, "doc")
globalSet.String("sips-exclude", config.SipsExclude, "doc")
globalSet.String("wakeup-interval", "1h34m9s", "doc")
globalSet.Bool("detect-nsfw", config.DetectNSFW, "doc")
globalSet.Bool("debug", false, "doc")
Expand Down Expand Up @@ -270,7 +271,8 @@ func CliTestContext() *cli.Context {
LogErr(c.Set("backup-retain", strconv.Itoa(config.BackupRetain)))
LogErr(c.Set("backup-schedule", config.BackupSchedule))
LogErr(c.Set("darktable-cli", config.DarktableBin))
LogErr(c.Set("darktable-skip", "raf,cr3"))
LogErr(c.Set("darktable-exclude", "raf, cr3"))
LogErr(c.Set("sips-exclude", "avif, avifs, thm"))
LogErr(c.Set("wakeup-interval", "1h34m9s"))
LogErr(c.Set("detect-nsfw", "true"))
LogErr(c.Set("debug", "false"))
Expand Down
22 changes: 11 additions & 11 deletions internal/photoprism/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,22 @@ import (

// Convert represents a converter that can convert RAW/HEIF images to JPEG.
type Convert struct {
conf *config.Config
cmdMutex sync.Mutex
sipsSkip fs.ExtList
darktableSkip fs.ExtList
rawtherapeeSkip fs.ExtList
imagemagickSkip fs.ExtList
conf *config.Config
cmdMutex sync.Mutex
sipsExclude fs.ExtList
darktableExclude fs.ExtList
rawTherapeeExclude fs.ExtList
imageMagickExclude fs.ExtList
}

// NewConvert returns a new converter and expects the config as argument.
func NewConvert(conf *config.Config) *Convert {
c := &Convert{
conf: conf,
sipsSkip: fs.NewExtList(conf.SipsSkip()),
darktableSkip: fs.NewExtList(conf.DarktableSkip()),
rawtherapeeSkip: fs.NewExtList(conf.RawTherapeeSkip()),
imagemagickSkip: fs.NewExtList(conf.ImageMagickSkip()),
conf: conf,
sipsExclude: fs.NewExtList(conf.SipsExclude()),
darktableExclude: fs.NewExtList(conf.DarktableExclude()),
rawTherapeeExclude: fs.NewExtList(conf.RawTherapeeExclude()),
imageMagickExclude: fs.NewExtList(conf.ImageMagickExclude()),
}

return c
Expand Down
2 changes: 1 addition & 1 deletion internal/photoprism/convert_fix.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func (c *Convert) FixJpeg(f *MediaFile, force bool) (*MediaFile, error) {

logName := clean.Log(f.RootRelName())

if c.conf.DisableImageMagick() || !c.imagemagickSkip.Allow(fs.ExtJPEG) {
if c.conf.DisableImageMagick() || !c.imageMagickExclude.Allow(fs.ExtJPEG) {
return nil, fmt.Errorf("convert: ImageMagick must be enabled to re-encode %s", logName)
}

Expand Down
8 changes: 4 additions & 4 deletions internal/photoprism/convert_image_jpeg.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func (c *Convert) JpegConvertCommands(f *MediaFile, jpegName string, xmpName str
maxSize := strconv.Itoa(c.conf.JpegSize())

// Apple Scriptable image processing system: https://ss64.com/osx/sips.html
if (f.IsRaw() || f.IsHEIF()) && c.conf.SipsEnabled() && c.sipsSkip.Allow(fileExt) {
if (f.IsRaw() || f.IsHEIF()) && c.conf.SipsEnabled() && c.sipsExclude.Allow(fileExt) {
result = append(result, exec.Command(c.conf.SipsBin(), "-Z", maxSize, "-s", "format", "jpeg", "--out", jpegName, f.FileName()))
}

Expand All @@ -39,7 +39,7 @@ func (c *Convert) JpegConvertCommands(f *MediaFile, jpegName string, xmpName str

// RAW files may be concerted with Darktable and RawTherapee.
if f.IsRaw() && c.conf.RawEnabled() {
if c.conf.DarktableEnabled() && c.darktableSkip.Allow(fileExt) {
if c.conf.DarktableEnabled() && c.darktableExclude.Allow(fileExt) {
var args []string

// Set RAW, XMP, and JPEG filenames.
Expand Down Expand Up @@ -72,7 +72,7 @@ func (c *Convert) JpegConvertCommands(f *MediaFile, jpegName string, xmpName str
result = append(result, exec.Command(c.conf.DarktableBin(), args...))
}

if c.conf.RawTherapeeEnabled() && c.rawtherapeeSkip.Allow(fileExt) {
if c.conf.RawTherapeeEnabled() && c.rawTherapeeExclude.Allow(fileExt) {
jpegQuality := fmt.Sprintf("-j%d", c.conf.JpegQuality())
profile := filepath.Join(conf.AssetsPath(), "profiles", "raw.pp3")

Expand All @@ -94,7 +94,7 @@ func (c *Convert) JpegConvertCommands(f *MediaFile, jpegName string, xmpName str
}

// Try ImageMagick for other image file formats if allowed.
if c.conf.ImageMagickEnabled() && c.imagemagickSkip.Allow(fileExt) &&
if c.conf.ImageMagickEnabled() && c.imageMagickExclude.Allow(fileExt) &&
(f.IsImage() && !f.IsJpegXL() && !f.IsRaw() && !f.IsHEIF() || f.IsVector() && c.conf.VectorEnabled()) {
quality := fmt.Sprintf("%d", c.conf.JpegQuality())
resize := fmt.Sprintf("%dx%d>", c.conf.JpegSize(), c.conf.JpegSize())
Expand Down
4 changes: 2 additions & 2 deletions internal/photoprism/convert_image_png.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func (c *Convert) PngConvertCommands(f *MediaFile, pngName string) (result []*ex
maxSize := strconv.Itoa(c.conf.PngSize())

// Apple Scriptable image processing system: https://ss64.com/osx/sips.html
if (f.IsRaw() || f.IsHEIF()) && c.conf.SipsEnabled() && c.sipsSkip.Allow(fileExt) {
if (f.IsRaw() || f.IsHEIF()) && c.conf.SipsEnabled() && c.sipsExclude.Allow(fileExt) {
result = append(result, exec.Command(c.conf.SipsBin(), "-Z", maxSize, "-s", "format", "png", "--out", pngName, f.FileName()))
}

Expand All @@ -46,7 +46,7 @@ func (c *Convert) PngConvertCommands(f *MediaFile, pngName string) (result []*ex
if c.conf.RsvgConvertEnabled() && f.IsSVG() {
args := []string{"-a", "-f", "png", "-o", pngName, f.FileName()}
result = append(result, exec.Command(c.conf.RsvgConvertBin(), args...))
} else if c.conf.ImageMagickEnabled() && c.imagemagickSkip.Allow(fileExt) &&
} else if c.conf.ImageMagickEnabled() && c.imageMagickExclude.Allow(fileExt) &&
(f.IsImage() && !f.IsJpegXL() && !f.IsRaw() && !f.IsHEIF() || f.IsVector() && c.conf.VectorEnabled()) {
resize := fmt.Sprintf("%dx%d>", c.conf.PngSize(), c.conf.PngSize())
args := []string{f.FileName(), "-flatten", "-resize", resize, pngName}
Expand Down
2 changes: 1 addition & 1 deletion internal/photoprism/convert_video_avc.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ func (c *Convert) AvcConvertCommand(f *MediaFile, avcName string, encoder ffmpeg
}

// Try to transcode animated WebP images with ImageMagick.
if c.conf.ImageMagickEnabled() && f.IsWebP() && c.imagemagickSkip.Allow(fileExt) {
if c.conf.ImageMagickEnabled() && f.IsWebP() && c.imageMagickExclude.Allow(fileExt) {
return exec.Command(c.conf.ImageMagickBin(), f.FileName(), avcName), false, nil
}

Expand Down

0 comments on commit b2f2823

Please sign in to comment.