diff --git a/Dockerfile b/Dockerfile index 87525a57..fb9d2cc1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -74,7 +74,6 @@ RUN export $(cat /env) \ && cp -a include/* /usr/local/include/ \ && cp -a pkgconfig/* ${PKG_CONFIG_PATH} \ && cp -a lib/* /usr/local/lib/ \ - && cp -a bin/* /usr/local/bin/ \ && ldconfig \ && apt-get install -y ./deb/jellyfin-ffmpeg.deb @@ -116,8 +115,6 @@ RUN --mount=type=bind,from=api,source=/dependencies/,target=/dependencies/ \ # Install self-building libs && cd /dependencies \ && cp -a lib/*.so* /usr/local/lib/ \ - && cp -a bin/* /usr/local/bin/ \ - && cp -a etc/* /usr/local/etc/ \ && ldconfig \ && apt-get install -y ./deb/jellyfin-ffmpeg.deb \ && ln -s /usr/lib/jellyfin-ffmpeg/ffmpeg /usr/local/bin/ \ diff --git a/api/go.mod b/api/go.mod index 118450ea..50c9ec6d 100644 --- a/api/go.mod +++ b/api/go.mod @@ -23,6 +23,7 @@ require ( github.com/xor-gate/goexif2 v1.1.0 golang.org/x/crypto v0.38.0 golang.org/x/text v0.25.0 + gopkg.in/gographics/imagick.v3 v3.7.2 gopkg.in/vansante/go-ffprobe.v2 v2.2.1 gorm.io/driver/mysql v1.5.7 gorm.io/driver/postgres v1.6.0 diff --git a/api/go.sum b/api/go.sum index 24c5ab9a..b7858be5 100644 --- a/api/go.sum +++ b/api/go.sum @@ -118,6 +118,8 @@ golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/gographics/imagick.v3 v3.7.2 h1:PmsYCf60YS/7f1omBTDaoS6yp4817Wv61S0JpWH4cMc= +gopkg.in/gographics/imagick.v3 v3.7.2/go.mod h1:7I4S9VWdwr88yzYi7g+ZL4H8oZuH9cmSQI7GsZCcYFM= gopkg.in/vansante/go-ffprobe.v2 v2.2.1 h1:sFV08OT1eZ1yroLCZVClIVd9YySgCh9eGjBWO0oRayI= gopkg.in/vansante/go-ffprobe.v2 v2.2.1/go.mod h1:qF0AlAjk7Nqzqf3y333Ly+KxN3cKF2JqA3JT5ZheUGE= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/api/scanner/media_encoding/encode_photo.go b/api/scanner/media_encoding/encode_photo.go index dac001c7..a7fff3fd 100644 --- a/api/scanner/media_encoding/encode_photo.go +++ b/api/scanner/media_encoding/encode_photo.go @@ -21,6 +21,35 @@ type Dimension struct { Height int } +// ThumbnailScale generates a new dimension for thumbnails. +func (d *Dimension) ThumbnailScale() Dimension { + if d.Height == 0 || d.Width == 0 { + return Dimension{Width: 0, Height: 0} + } + + aspect := float64(d.Width) / float64(d.Height) + + var width, height int + + if aspect > 1 { + width = 1024 + height = int(1024 / aspect) + } else { + width = int(1024 * aspect) + height = 1024 + } + + if width > d.Width { + width = d.Width + height = d.Height + } + + return Dimension{ + Width: width, + Height: height, + } +} + // GetPhotoDimensions returns the dimension of the image `imagePath`. func GetPhotoDimensions(imagePath string) (Dimension, error) { w, h, err := executable_worker.Magick.IdentifyDimension(imagePath) @@ -29,19 +58,30 @@ func GetPhotoDimensions(imagePath string) (Dimension, error) { } return Dimension{ - Width: w, - Height: h, + Width: int(w), + Height: int(h), }, nil } // EncodeThumbnail encodes a thumbnail of `inputPath`, and store it as `outputPath`. // It returns the dimension of the thumbnail. The thumbnail will be not bigger than 1024x1024. func EncodeThumbnail(db *gorm.DB, inputPath string, outputPath string) (Dimension, error) { - if err := executable_worker.Magick.GenerateThumbnail(inputPath, outputPath, 1024, 1024); err != nil { + w, h, err := executable_worker.Magick.IdentifyDimension(inputPath) + if err != nil { return Dimension{}, fmt.Errorf("can't generate thumbnail of file %q: %w", inputPath, err) } - return GetPhotoDimensions(outputPath) + origin := Dimension{ + Width: int(w), + Height: int(h), + } + thumbnail := origin.ThumbnailScale() + + if err := executable_worker.Magick.GenerateThumbnail(inputPath, outputPath, uint(thumbnail.Width), uint(thumbnail.Height)); err != nil { + return Dimension{}, fmt.Errorf("can't generate thumbnail of file %q: %w", inputPath, err) + } + + return thumbnail, nil } // EncodeMediaData is used to easily decode media data, with a cache so expensive operations are not repeated diff --git a/api/scanner/media_encoding/executable_worker/executable_worker.go b/api/scanner/media_encoding/executable_worker/executable_worker.go index d54d64b6..b390cec7 100644 --- a/api/scanner/media_encoding/executable_worker/executable_worker.go +++ b/api/scanner/media_encoding/executable_worker/executable_worker.go @@ -13,16 +13,22 @@ import ( var ErrNoDependency = errors.New("dependency not found") var ErrDisabledFunction = errors.New("function disabled") -func init() { - Magick = newMagickCli() +// Initialize Initializes all workers. It returns a function to terminate workers, which should be called before the program closing. +func Initialize() func() { + Magick = newMagickWand() Ffmpeg = newFfmpegCli() if err := SetFfprobePath(); err != nil { log.Error("Init ffprobe fail.", "error", err) } + + return func() { + Magick.Terminate() + Magick = nil + } } -var Magick *MagickCli = nil +var Magick *MagickWand = nil var Ffmpeg *FfmpegCli = nil type ExecutableWorker interface { diff --git a/api/scanner/media_encoding/executable_worker/magick_cli.go b/api/scanner/media_encoding/executable_worker/magick_cli.go deleted file mode 100644 index c6171dce..00000000 --- a/api/scanner/media_encoding/executable_worker/magick_cli.go +++ /dev/null @@ -1,133 +0,0 @@ -package executable_worker - -import ( - "bytes" - "encoding/json" - "fmt" - "os/exec" - "strings" - - "github.com/photoview/photoview/api/log" - "github.com/photoview/photoview/api/utils" -) - -type MagickCli struct { - path string - err error -} - -func newMagickCli() *MagickCli { - if utils.EnvDisableRawProcessing.GetBool() { - log.Warn("Executable magick worker disabled", utils.EnvDisableRawProcessing.GetName(), utils.EnvDisableRawProcessing.GetValue()) - return &MagickCli{ - err: ErrDisabledFunction, - } - } - - path, err := exec.LookPath("magick") - if err != nil { - log.Error("Executable magick worker not found") - return &MagickCli{ - err: ErrNoDependency, - } - } - - version, err := exec.Command(path, "-version").Output() - if err != nil { - log.Error("Executable magick worker get version error", "error", err) - return &MagickCli{ - err: ErrNoDependency, - } - } - - log.Info("Found magick executable worker", "version", strings.Split(string(version), "\n")[0]) - - return &MagickCli{ - path: path, - } -} - -func (cli *MagickCli) IsInstalled() bool { - return cli.err == nil -} - -func (cli *MagickCli) EncodeJpeg(inputPath string, outputPath string, jpegQuality int) error { - if cli.err != nil { - return fmt.Errorf("encoding jpeg %q error: magick: %w", inputPath, cli.err) - } - - args := []string{ - inputPath, - "-auto-orient", - "-quality", fmt.Sprintf("%d", jpegQuality), - outputPath, - } - - cmd := exec.Command(cli.path, args...) - - if err := cmd.Run(); err != nil { - return fmt.Errorf("encoding image with \"%s %v\" error: %w", cli.path, args, err) - } - - return nil -} - -func (cli *MagickCli) GenerateThumbnail(inputPath string, outputPath string, width, height int) error { - if cli.err != nil { - return fmt.Errorf("generate thumbnail %q error: magick: %w", inputPath, cli.err) - } - - args := []string{ - inputPath + "[0]", // If there are multiple frames (like gif), only thumbnail the first frame. - "-thumbnail", - fmt.Sprintf("%dx%d", width, height), - outputPath, - } - - cmd := exec.Command(cli.path, args...) - - if err := cmd.Run(); err != nil { - return fmt.Errorf("generate thumbnail with \"%s %v\" error: %w", cli.path, args, err) - } - - return nil -} - -func (cli *MagickCli) IdentifyDimension(inputPath string) (width, height int, err error) { - if cli.err != nil { - err = fmt.Errorf("identify dimension %q error: magick: %w", inputPath, cli.err) - return - } - - args := []string{ - "identify", - "-format", - `{"height":%H, "width":%W}`, - inputPath, - } - - cmd := exec.Command(cli.path, args...) - - var output bytes.Buffer - cmd.Stdout = &output - - if e := cmd.Run(); e != nil { - err = fmt.Errorf("identify dimension with \"%s %v\" error: %w", cli.path, args, e) - return - } - - ret := struct { - Width *int - Height *int - }{ - Width: &width, - Height: &height, - } - - if e := json.NewDecoder(&output).Decode(&ret); e != nil { - err = fmt.Errorf("identify dimension with \"%s %v\" error: %w", cli.path, args, e) - return - } - - return -} diff --git a/api/scanner/media_encoding/executable_worker/magick_cli_test.go b/api/scanner/media_encoding/executable_worker/magick_cli_test.go deleted file mode 100644 index 7d6493da..00000000 --- a/api/scanner/media_encoding/executable_worker/magick_cli_test.go +++ /dev/null @@ -1,179 +0,0 @@ -package executable_worker - -import ( - "errors" - "regexp" - "testing" -) - -func TestMagickCliNotExist(t *testing.T) { - SetPathWithCurrent(t, "") - - Magick = newMagickCli() - - if got, want := Magick.err, ErrNoDependency; got != want { - t.Errorf("Magick.err = %v, want: %v", got, want) - } - - if Magick.IsInstalled() { - t.Error("MagickCli should not be installed, but is found:", Magick) - } - - if got, want := Magick.EncodeJpeg("input", "output", 70), ErrNoDependency; !errors.Is(got, want) { - t.Errorf("Magick.EncodeJpeg() = %v, want: %v", got, want) - } - - if got, want := Magick.GenerateThumbnail("input", "output", 100, 100), ErrNoDependency; !errors.Is(got, want) { - t.Errorf("Magick.GenerateThumbnail() = %v, want: %v", got, want) - } - - { - _, _, got := Magick.IdentifyDimension("input") - if want := ErrNoDependency; !errors.Is(got, want) { - t.Errorf("Magick.IdentifyDimension() = %v, want: %v", got, want) - } - } -} - -func TestMagickCliIgnore(t *testing.T) { - SetPathWithCurrent(t, testdataBinPath) - t.Setenv("PHOTOVIEW_DISABLE_RAW_PROCESSING", "true") - - Magick = newMagickCli() - - if got, want := Magick.err, ErrDisabledFunction; got != want { - t.Errorf("Magick.err = %v, want: %v", got, want) - } - - if Magick.IsInstalled() { - t.Error("MagickCli should not be installed, but is found:", Magick) - } - - if got, want := Magick.EncodeJpeg("input", "output", 70), ErrDisabledFunction; !errors.Is(got, want) { - t.Errorf("Magick.EncodeJpeg() = %v, want: %v", got, want) - } - - if got, want := Magick.GenerateThumbnail("input", "output", 100, 100), ErrDisabledFunction; !errors.Is(got, want) { - t.Errorf("Magick.GenerateThumbnail() = %v, want: %v", got, want) - } - - { - _, _, got := Magick.IdentifyDimension("input") - if want := ErrDisabledFunction; !errors.Is(got, want) { - t.Errorf("Magick.IdentifyDimension() = %v, want: %v", got, want) - } - } -} - -func TestMagickCliVersionFail(t *testing.T) { - SetPathWithCurrent(t, testdataBinPath) - t.Setenv("FAIL_WITH", "failure") - - Magick = newMagickCli() - - if got, want := Magick.err, ErrNoDependency; got != want { - t.Errorf("Magick.err = %v, want: %v", got, want) - } - - if Magick.IsInstalled() { - t.Error("MagickCli should not be installed, but is found:", Magick) - } - - if got, want := Magick.EncodeJpeg("input", "output", 70), ErrNoDependency; !errors.Is(got, want) { - t.Errorf("Magick.EncodeJpeg() = %v, want: %v", got, want) - } - - if got, want := Magick.GenerateThumbnail("input", "output", 100, 100), ErrNoDependency; !errors.Is(got, want) { - t.Errorf("Magick.GenerateThumbnail() = %v, want: %v", got, want) - } - - { - _, _, got := Magick.IdentifyDimension("input") - if want := ErrNoDependency; !errors.Is(got, want) { - t.Errorf("Magick.IdentifyDimension() = %v, want: %v", got, want) - } - } -} - -func TestMagickCliFail(t *testing.T) { - SetPathWithCurrent(t, testdataBinPath) - - Magick = newMagickCli() - - if !Magick.IsInstalled() { - t.Fatal("MagickCli should be installed") - } - - t.Setenv("FAIL_WITH", "failure") - - err := Magick.EncodeJpeg("input", "output", 70) - if err == nil { - t.Fatalf(`MagickCli.EncodeJpeg(...) = nil, should be an error.`) - } - - if got, want := err.Error(), `^encoding image with ".*/test_data/mock_bin/magick \[input -auto-orient -quality 70 output\]" error: .*$`; !regexp.MustCompile(want).MatchString(got) { - t.Errorf(`MagickCli.EncodeJpeg(...) = %q, should be matched with reg pattern %q`, got, want) - } - - err = Magick.GenerateThumbnail("input", "output", 100, 100) - if err == nil { - t.Fatalf(`MagickCli.GenerateThumbnail(...) = nil, should be an error.`) - } - if got, want := err.Error(), `^generate thumbnail with ".*/test_data/mock_bin/magick \[input\[0\] -thumbnail 100x100 output\]" error: .*$`; !regexp.MustCompile(want).MatchString(got) { - t.Errorf(`MagickCli.GenerateThumbnail(...) = %q, should be matched with reg pattern %q`, got, want) - } - - { - _, _, got := Magick.IdentifyDimension("input") - if want := `^identify dimension with ".*/test_data/mock_bin/magick \[identify -format {"height":\%H, "width":\%W} input\]" error: .*$`; !regexp.MustCompile(want).MatchString(got.Error()) { - t.Errorf("Magick.IdentifyDimension() = %v, should be matched with reg pattern %q", got, want) - } - } -} - -func TestMagickCliSucceed(t *testing.T) { - SetPathWithCurrent(t, testdataBinPath) - - Magick = newMagickCli() - - if !Magick.IsInstalled() { - t.Fatal("MagickCli should be installed") - } - - t.Run("EncodeJpeg", func(t *testing.T) { - err := Magick.EncodeJpeg("input", "output", 70) - if err != nil { - t.Fatalf("MagickCli.EncodeJpeg(...) = %v, should be nil.", err) - } - }) - - t.Run("GenerateThumbnail", func(t *testing.T) { - err := Magick.GenerateThumbnail("input", "output", 100, 100) - if err != nil { - t.Fatalf("MagickCli.GenerateThumbnail(...) = %v, should be nil.", err) - } - }) - - t.Run("IdentifyDimension", func(t *testing.T) { - w, h, err := Magick.IdentifyDimension("input") - if err != nil { - t.Fatalf("MagickCli.IdentifyDimension(...) = %v, should be nil.", err) - } - - if got, want := w, 1000; got != want { - t.Errorf("got = %d, want = %d", got, want) - } - if got, want := h, 800; got != want { - t.Errorf("got = %d, want = %d", got, want) - } - }) - - t.Run("IdentifyDimensionInvalidJSON", func(t *testing.T) { - t.Setenv("INVALID_OUTPUT", `{"width":1000,`) - - _, _, err := Magick.IdentifyDimension("input") - if want := `unexpected EOF$`; !regexp.MustCompile(want).MatchString(err.Error()) { - t.Errorf("MagickCli.IdentifyDimension() = error(%v), which should match with regexp %q", err, want) - } - }) -} diff --git a/api/scanner/media_encoding/executable_worker/magickwand.go b/api/scanner/media_encoding/executable_worker/magickwand.go new file mode 100644 index 00000000..8624c1a8 --- /dev/null +++ b/api/scanner/media_encoding/executable_worker/magickwand.go @@ -0,0 +1,111 @@ +package executable_worker + +import ( + "fmt" + + "github.com/photoview/photoview/api/log" + "gopkg.in/gographics/imagick.v3/imagick" +) + +type MagickWand struct { + initialized bool +} + +func newMagickWand() *MagickWand { + imagick.Initialize() + + verstr, vernum := imagick.GetVersion() + + log.Info("Found magickwand worker: "+verstr, "version", vernum) + + return &MagickWand{ + initialized: true, + } +} + +func (cli *MagickWand) Terminate() { + cli.initialized = false + imagick.Terminate() +} + +func (cli *MagickWand) IsInstalled() bool { + return cli != nil && cli.initialized +} + +func (cli *MagickWand) EncodeJpeg(inputPath string, outputPath string, jpegQuality uint) error { + if !cli.IsInstalled() { + return fmt.Errorf("ImagickWand is not initialized") + } + + wand := imagick.NewMagickWand() + defer wand.Destroy() + + if err := wand.ReadImage(inputPath); err != nil { + return fmt.Errorf("ImagickWand read %q error: %w", inputPath, err) + } + + if err := wand.SetFormat("JPEG"); err != nil { + return fmt.Errorf("ImagickWand set JPEG format for %q error: %w", inputPath, err) + } + + if err := wand.SetImageCompressionQuality(jpegQuality); err != nil { + return fmt.Errorf("ImagickWand set JPEG quality %d for %q error: %w", jpegQuality, inputPath, err) + } + + if err := wand.WriteImage(outputPath); err != nil { + return fmt.Errorf("ImagickWand write %q error: %w", outputPath, err) + } + + return nil +} + +func (cli *MagickWand) GenerateThumbnail(inputPath string, outputPath string, width, height uint) error { + if !cli.IsInstalled() { + return fmt.Errorf("ImagickWand is not initialized") + } + + wand := imagick.NewMagickWand() + defer wand.Destroy() + + if err := wand.ReadImage(inputPath); err != nil { + return fmt.Errorf("ImagickWand read %q error: %w", inputPath, err) + } + + if err := wand.ThumbnailImage(width, height); err != nil { + return fmt.Errorf("ImagickWand generate thumbnail for %q error: %w", inputPath, err) + } + + if err := wand.SetFormat("JPEG"); err != nil { + return fmt.Errorf("ImagickWand set JPEG format for %q error: %w", inputPath, err) + } + + if err := wand.SetImageCompressionQuality(70); err != nil { + return fmt.Errorf("ImagickWand set JPEG quality %d for %q error: %w", 70, inputPath, err) + } + + if err := wand.WriteImage(outputPath); err != nil { + return fmt.Errorf("ImagickWand write %q error: %w", outputPath, err) + } + + return nil +} + +func (cli *MagickWand) IdentifyDimension(inputPath string) (width, height uint, err error) { + if !cli.IsInstalled() { + err = fmt.Errorf("ImagickWand is not initialized") + return + } + + wand := imagick.NewMagickWand() + defer wand.Destroy() + + if errRI := wand.ReadImage(inputPath); errRI != nil { + err = fmt.Errorf("ImagickWand read %q error: %w", inputPath, errRI) + return + } + + width = wand.GetImageWidth() + height = wand.GetImageHeight() + + return +} diff --git a/api/scanner/perf_test.go b/api/scanner/perf_test.go index bef1f1c7..062f87c1 100644 --- a/api/scanner/perf_test.go +++ b/api/scanner/perf_test.go @@ -9,6 +9,7 @@ import ( "testing" "github.com/photoview/photoview/api/scanner/media_encoding/executable_worker" + "gopkg.in/gographics/imagick.v3/imagick" ) func BenchmarkStdlib(b *testing.B) { @@ -57,3 +58,36 @@ func BenchmarkMagickCLI(b *testing.B) { }() } } + +func BenchmarkMagickWand(b *testing.B) { + dir := b.TempDir() + + imagick.Initialize() + defer imagick.Terminate() + + for b.Loop() { + func() { + mw := imagick.NewMagickWand() + defer mw.Destroy() + + if err := mw.ReadImage("./test_media/real_media/png.png"); err != nil { + b.Fatal("read error:", err) + } + + output := filepath.Join(dir, "test.jpg") + defer os.Remove(output) + + if err := mw.SetFormat("JPEG"); err != nil { + b.Fatal("set format error:", err) + } + + if err := mw.SetImageCompressionQuality(70); err != nil { + b.Fatal("set quality error:", err) + } + + if err := mw.WriteImage(output); err != nil { + b.Fatal("write error:", err) + } + }() + } +} diff --git a/api/scanner/scanner_test.go b/api/scanner/scanner_test.go index f17c1c96..10d98ee0 100644 --- a/api/scanner/scanner_test.go +++ b/api/scanner/scanner_test.go @@ -122,7 +122,7 @@ func TestFullScan(t *testing.T) { slices.Sort(got) if diff := cmp.Diff(got, want); diff != "" { - t.Errorf("all media diff:\n%s", diff) + t.Errorf("all media diff (-got, +want):\n%s", diff) } }) @@ -168,7 +168,7 @@ func TestFullScan(t *testing.T) { slices.Sort(got) if diff := cmp.Diff(got, want, cmp.Comparer(equalNameWithoutSuffix)); diff != "" { - t.Errorf("all media diff:\n%s", diff) + t.Errorf("all media diff (-got, +want):\n%s", diff) } }) @@ -202,7 +202,7 @@ func TestFullScan(t *testing.T) { got := groupMediaWithFaces(allImageFaces) if diff := cmp.Diff(got, wantFaceGroups); diff != "" { - t.Errorf("all media diff:\n%s", diff) + t.Errorf("all media diff (-got, +want):\n%s", diff) } }) } diff --git a/api/server.go b/api/server.go index 591406b7..60974a27 100644 --- a/api/server.go +++ b/api/server.go @@ -17,6 +17,7 @@ import ( "github.com/photoview/photoview/api/routes" "github.com/photoview/photoview/api/scanner/exif" "github.com/photoview/photoview/api/scanner/face_detection" + "github.com/photoview/photoview/api/scanner/media_encoding/executable_worker" "github.com/photoview/photoview/api/scanner/periodic_scanner" "github.com/photoview/photoview/api/scanner/scanner_queue" "github.com/photoview/photoview/api/server" @@ -33,6 +34,9 @@ func main() { log.Println("No .env file found") } + terminateWorkers := executable_worker.Initialize() + defer terminateWorkers() + devMode := utils.DevelopmentMode() db, err := database.SetupDatabase() diff --git a/api/test_utils/integration_setup.go b/api/test_utils/integration_setup.go index eca5a16d..e6e2e5a6 100644 --- a/api/test_utils/integration_setup.go +++ b/api/test_utils/integration_setup.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/joho/godotenv" + "github.com/photoview/photoview/api/scanner/media_encoding/executable_worker" "github.com/photoview/photoview/api/utils" "gorm.io/gorm" ) @@ -49,6 +50,9 @@ func IntegrationTestRun(m *testing.M) int { faceModelsPath := path.Join(path.Dir(file), "..", "data", "models") utils.ConfigureTestFaceRecognitionModelsPath(faceModelsPath) + terminateWorkers := executable_worker.Initialize() + defer terminateWorkers() + result := m.Run() test_dbm.Close() diff --git a/scripts/install_build_dependencies.sh b/scripts/install_build_dependencies.sh index 0f8184e6..3a0a2054 100755 --- a/scripts/install_build_dependencies.sh +++ b/scripts/install_build_dependencies.sh @@ -3,13 +3,22 @@ set -eu : ${DEB_HOST_ARCH=`dpkg --print-architecture`} echo Arch: ${DEB_HOST_ARCH} +apt-get update + +# Install libheif dependencies +apt-get install -y --no-install-recommends libdav1d-dev:${DEB_HOST_ARCH} libde265-dev:${DEB_HOST_ARCH} libjpeg62-turbo-dev:${DEB_HOST_ARCH} libopenh264-dev:${DEB_HOST_ARCH} libpng-dev:${DEB_HOST_ARCH} libnuma-dev:${DEB_HOST_ARCH} zlib1g-dev:${DEB_HOST_ARCH} + +# Install libraw dependencies +apt-get install -y --no-install-recommends libjpeg62-turbo-dev:${DEB_HOST_ARCH} liblcms2-dev:${DEB_HOST_ARCH} zlib1g-dev:${DEB_HOST_ARCH} + +# Install ImageMagick dependencies +apt-get install -y --no-install-recommends libjxl-dev:${DEB_HOST_ARCH} liblcms2-dev:${DEB_HOST_ARCH} liblqr-1-0-dev:${DEB_HOST_ARCH} libdjvulibre-dev:${DEB_HOST_ARCH} libjpeg62-turbo-dev:${DEB_HOST_ARCH} libopenjp2-7-dev:${DEB_HOST_ARCH} libopenexr-dev:${DEB_HOST_ARCH} libpng-dev:${DEB_HOST_ARCH} libtiff-dev:${DEB_HOST_ARCH} libwebp-dev:${DEB_HOST_ARCH} libxml2-dev:${DEB_HOST_ARCH} libfftw3-dev:${DEB_HOST_ARCH} zlib1g-dev:${DEB_HOST_ARCH} liblzma-dev:${DEB_HOST_ARCH} libbz2-dev:${DEB_HOST_ARCH} # Install go-face dependencies -apt-get install -y \ - libdlib-dev:${DEB_HOST_ARCH} libblas-dev:${DEB_HOST_ARCH} libatlas-base-dev:${DEB_HOST_ARCH} liblapack-dev:${DEB_HOST_ARCH} libjpeg62-turbo-dev:${DEB_HOST_ARCH} +apt-get install -y --no-install-recommends libdlib-dev:${DEB_HOST_ARCH} libblas-dev:${DEB_HOST_ARCH} libatlas-base-dev:${DEB_HOST_ARCH} liblapack-dev:${DEB_HOST_ARCH} libjpeg62-turbo-dev:${DEB_HOST_ARCH} # Install gomagic dependencies -apt-get install -y libmagic-dev:${DEB_HOST_ARCH} +apt-get install -y --no-install-recommends libmagic-dev:${DEB_HOST_ARCH} # Install tools for development -apt-get install -y reflex sqlite3 +apt-get install -y --no-install-recommends reflex sqlite3 diff --git a/scripts/install_runtime_dependencies.sh b/scripts/install_runtime_dependencies.sh index 8b6cca93..db6dfa95 100755 --- a/scripts/install_runtime_dependencies.sh +++ b/scripts/install_runtime_dependencies.sh @@ -2,15 +2,19 @@ set -eu apt-get update -apt-get install -y curl exiftool +apt-get install -y --no-install-recommends curl exiftool # libheif dependencies -apt-get install -y libdav1d6 librav1e0 libde265-0 libx265-199 libjpeg62-turbo libopenh264-7 libpng16-16 libnuma1 zlib1g +apt-get install -y --no-install-recommends libdav1d6 librav1e0 libde265-0 libx265-199 libjpeg62-turbo libopenh264-7 libpng16-16 libnuma1 zlib1g + # libraw dependencies -apt-get install -y libjpeg62-turbo liblcms2-2 zlib1g libgomp1 +apt-get install -y --no-install-recommends libjpeg62-turbo liblcms2-2 zlib1g libgomp1 + # ImageMagick dependencies -apt-get install -y libjxl0.7 liblcms2-2 liblqr-1-0 libdjvulibre21 libjpeg62-turbo libopenjp2-7 libopenexr-3-1-30 libpng16-16 libtiff6 libwebpmux3 libwebpdemux2 libwebp7 libxml2 zlib1g liblzma5 libbz2-1.0 libgomp1 +apt-get install -y --no-install-recommends libjxl0.7 liblcms2-2 liblqr-1-0 libdjvulibre21 libjpeg62-turbo libopenjp2-7 libopenexr-3-1-30 libpng16-16 libtiff6 libwebpmux3 libwebpdemux2 libwebp7 libxml2 zlib1g liblzma5 libbz2-1.0 libgomp1 + # go-face dependencies -apt-get install -y libdlib19.1 libblas3 liblapack3 libjpeg62-turbo -# libmagic dependencies -apt-get install -y libmagic1 +apt-get install -y --no-install-recommends libdlib19.1 libblas3 liblapack3 libjpeg62-turbo + +# gomagic dependencies +apt-get install -y --no-install-recommends libmagic1