gallery: try to avoid OOM while thumbnailing
This commit is contained in:
parent
de0dc58b99
commit
d37e9e821a
28
main.go
28
main.go
|
@ -41,6 +41,9 @@ import (
|
||||||
"golang.org/x/image/webp"
|
"golang.org/x/image/webp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// #include <unistd.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
db *sql.DB // sqlite database
|
db *sql.DB // sqlite database
|
||||||
galleryDirectory string // gallery directory
|
galleryDirectory string // gallery directory
|
||||||
|
@ -2176,6 +2179,11 @@ func makeThumbnail(load bool, pathImage, pathThumb string) (
|
||||||
return 0, 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is still too much, but it will be effective enough.
|
||||||
|
memoryLimit := strconv.FormatInt(
|
||||||
|
int64(C.sysconf(C._SC_PHYS_PAGES)*C.sysconf(C._SC_PAGE_SIZE))/
|
||||||
|
int64(len(taskSemaphore)), 10)
|
||||||
|
|
||||||
// Create a normalized thumbnail. Since we don't particularly need
|
// Create a normalized thumbnail. Since we don't particularly need
|
||||||
// any complex processing, such as surrounding metadata,
|
// any complex processing, such as surrounding metadata,
|
||||||
// simply push it through ImageMagick.
|
// simply push it through ImageMagick.
|
||||||
|
@ -2189,8 +2197,17 @@ func makeThumbnail(load bool, pathImage, pathThumb string) (
|
||||||
//
|
//
|
||||||
// TODO: See if we can optimize resulting WebP animations.
|
// TODO: See if we can optimize resulting WebP animations.
|
||||||
// (Do -layers optimize* apply to this format at all?)
|
// (Do -layers optimize* apply to this format at all?)
|
||||||
cmd := exec.Command("magick", "-limit", "thread", "1", pathImage,
|
cmd := exec.Command("magick", "-limit", "thread", "1",
|
||||||
"-coalesce", "-colorspace", "RGB", "-auto-orient", "-strip",
|
|
||||||
|
// Do not invite the OOM killer, a particularly unpleasant guest.
|
||||||
|
"-limit", "memory", memoryLimit,
|
||||||
|
|
||||||
|
// ImageMagick creates files in /tmp, but that tends to be a tmpfs,
|
||||||
|
// which is backed by memory. The path could also be moved elsewhere:
|
||||||
|
// -define registry:temporary-path=/var/tmp
|
||||||
|
"-limit", "map", "0", "-limit", "disk", "0",
|
||||||
|
|
||||||
|
pathImage, "-coalesce", "-colorspace", "RGB", "-auto-orient", "-strip",
|
||||||
"-resize", "256x128>", "-colorspace", "sRGB",
|
"-resize", "256x128>", "-colorspace", "sRGB",
|
||||||
"-format", "%w %h", "+write", pathThumb, "-delete", "1--1", "info:")
|
"-format", "%w %h", "+write", pathThumb, "-delete", "1--1", "info:")
|
||||||
|
|
||||||
|
@ -2478,6 +2495,8 @@ func usage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
threads := flag.Int("threads", -1, "level of parallelization")
|
||||||
|
|
||||||
// This implements the -h switch for us by default.
|
// This implements the -h switch for us by default.
|
||||||
// The rest of the handling here closely follows what flag does internally.
|
// The rest of the handling here closely follows what flag does internally.
|
||||||
flag.Usage = usage
|
flag.Usage = usage
|
||||||
|
@ -2503,7 +2522,12 @@ func main() {
|
||||||
fs.PrintDefaults()
|
fs.PrintDefaults()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *threads > 0 {
|
||||||
|
taskSemaphore = newSemaphore(*threads)
|
||||||
|
} else {
|
||||||
taskSemaphore = newSemaphore(runtime.NumCPU())
|
taskSemaphore = newSemaphore(runtime.NumCPU())
|
||||||
|
}
|
||||||
|
|
||||||
err := cmd.handler(fs, flag.Args()[1:])
|
err := cmd.handler(fs, flag.Args()[1:])
|
||||||
|
|
||||||
// Note that the database object has a closing finalizer,
|
// Note that the database object has a closing finalizer,
|
||||||
|
|
Loading…
Reference in New Issue