Compare commits
No commits in common. "d37e9e821a63f5e0dd8dfd878df782c5c745f0e8" and "4131bc5d3130e876d021e1cfa7fae4d3c3b86626" have entirely different histories.
d37e9e821a
...
4131bc5d31
@ -309,8 +309,8 @@ run(std::vector<Magick::Image> &images, const Config &config,
|
|||||||
if (config.sigmoid)
|
if (config.sigmoid)
|
||||||
value = 1 / (1 + std::exp(-value));
|
value = 1 / (1 + std::exp(-value));
|
||||||
if (value > g.threshold) {
|
if (value > g.threshold) {
|
||||||
printf("%s\t%s\t%.2f\n", images.at(i).fileName().c_str(),
|
printf("%s\t%.2f\t%s\n", images.at(i).fileName().c_str(),
|
||||||
config.tags.at(t).c_str(), value);
|
value, config.tags.at(t).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
66
main.go
66
main.go
@ -41,9 +41,6 @@ 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
|
||||||
@ -1418,11 +1415,7 @@ func syncPostProcess(c *syncContext, info syncFileInfo) error {
|
|||||||
case info.err != nil:
|
case info.err != nil:
|
||||||
// * → error
|
// * → error
|
||||||
if ee, ok := info.err.(*exec.ExitError); ok {
|
if ee, ok := info.err.(*exec.ExitError); ok {
|
||||||
message := string(ee.Stderr)
|
syncPrintf(c, "%s: %s", info.fsPath, ee.Stderr)
|
||||||
if message == "" {
|
|
||||||
message = ee.String()
|
|
||||||
}
|
|
||||||
syncPrintf(c, "%s: %s", info.fsPath, message)
|
|
||||||
} else {
|
} else {
|
||||||
return info.err
|
return info.err
|
||||||
}
|
}
|
||||||
@ -2179,13 +2172,8 @@ 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 of metadata,
|
||||||
// simply push it through ImageMagick.
|
// simply push it through ImageMagick.
|
||||||
//
|
//
|
||||||
// - http://www.ericbrasseur.org/gamma.html
|
// - http://www.ericbrasseur.org/gamma.html
|
||||||
@ -2197,17 +2185,8 @@ 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",
|
cmd := exec.Command("magick", "-limit", "thread", "1", pathImage,
|
||||||
|
"-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:")
|
||||||
|
|
||||||
@ -2258,10 +2237,7 @@ func cmdThumbnail(fs *flag.FlagSet, args []string) error {
|
|||||||
w, h, err := makeThumbnail(*load, pathImage, pathThumb)
|
w, h, err := makeThumbnail(*load, pathImage, pathThumb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if ee, ok := err.(*exec.ExitError); ok {
|
if ee, ok := err.(*exec.ExitError); ok {
|
||||||
if message = string(ee.Stderr); message != "" {
|
return string(ee.Stderr), nil
|
||||||
return message, nil
|
|
||||||
}
|
|
||||||
return ee.String(), nil
|
|
||||||
}
|
}
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -2414,29 +2390,14 @@ func cmdDhash(fs *flag.FlagSet, args []string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commits are very IO-expensive in both WAL and non-WAL SQLite,
|
stmt, err := db.Prepare(`UPDATE image SET dhash = ? WHERE sha1 = ?`)
|
||||||
// so write this in one go. For a middle ground, we could batch the updates.
|
|
||||||
tx, err := db.Begin()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer tx.Rollback()
|
|
||||||
|
|
||||||
// Mild hack: upgrade the transaction to a write one straight away,
|
|
||||||
// in order to rule out deadlocks (preventable failure).
|
|
||||||
if _, err := tx.Exec(`END TRANSACTION;
|
|
||||||
BEGIN IMMEDIATE TRANSACTION`); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
stmt, err := tx.Prepare(`UPDATE image SET dhash = ? WHERE sha1 = ?`)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer stmt.Close()
|
defer stmt.Close()
|
||||||
|
|
||||||
var mu sync.Mutex
|
var mu sync.Mutex
|
||||||
err = parallelize(hexSHA1, func(sha1 string) (message string, err error) {
|
return parallelize(hexSHA1, func(sha1 string) (message string, err error) {
|
||||||
hash, err := makeDhash(sha1)
|
hash, err := makeDhash(sha1)
|
||||||
if errors.Is(err, errIsAnimation) {
|
if errors.Is(err, errIsAnimation) {
|
||||||
// Ignoring this common condition.
|
// Ignoring this common condition.
|
||||||
@ -2450,10 +2411,6 @@ func cmdDhash(fs *flag.FlagSet, args []string) error {
|
|||||||
_, err = stmt.Exec(int64(hash), sha1)
|
_, err = stmt.Exec(int64(hash), sha1)
|
||||||
return "", err
|
return "", err
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return tx.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Main --------------------------------------------------------------------
|
// --- Main --------------------------------------------------------------------
|
||||||
@ -2495,8 +2452,6 @@ 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
|
||||||
@ -2522,12 +2477,7 @@ func main() {
|
|||||||
fs.PrintDefaults()
|
fs.PrintDefaults()
|
||||||
}
|
}
|
||||||
|
|
||||||
if *threads > 0 {
|
taskSemaphore = newSemaphore(runtime.NumCPU())
|
||||||
taskSemaphore = newSemaphore(*threads)
|
|
||||||
} else {
|
|
||||||
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…
x
Reference in New Issue
Block a user