Implemented thumbnails command

This commit is contained in:
Michael Mayer 2018-06-17 12:56:02 +02:00
parent 187449226a
commit 3c80d4a842
5 changed files with 216 additions and 14 deletions

View file

@ -43,6 +43,8 @@ func main() {
conf.SetValuesFromCliContext(context)
conf.CreateDirectories()
fmt.Printf("Importing photos from %s...\n", conf.ImportPath)
importer := photoprism.NewImporter(conf.OriginalsPath)
@ -62,6 +64,8 @@ func main() {
conf.SetValuesFromCliContext(context)
conf.CreateDirectories()
fmt.Printf("Converting RAW images in %s to JPEG...\n", conf.OriginalsPath)
converter := photoprism.NewConverter(conf.DarktableCli)
@ -76,14 +80,43 @@ func main() {
{
Name: "thumbnails",
Usage: "Create thumbnails",
Flags: []cli.Flag{
cli.IntSliceFlag{
Name: "size, s",
Usage: "Thumbnail size in pixels",
},
cli.BoolFlag{
Name: "default, d",
Usage: "Render default sizes: 320, 500, 640, 1280, 1920 and 2560px",
},
cli.BoolFlag{
Name: "square, q",
Usage: "Square aspect ratio",
},
},
Action: func(context *cli.Context) error {
conf.SetValuesFromFile(photoprism.GetExpandedFilename(context.GlobalString("config-file")))
conf.SetValuesFromCliContext(context)
conf.CreateDirectories()
fmt.Printf("Creating thumbnails in %s...\n", conf.ThumbnailsPath)
fmt.Println("[TODO]")
sizes := context.IntSlice("size")
if context.Bool("default") {
sizes = []int{320, 500, 640, 1280, 1920, 2560}
}
if len(sizes) == 0 {
fmt.Println("No sizes selected. Nothing to do.")
return nil
}
for _, size := range sizes {
photoprism.CreateThumbnailsFromOriginals(conf.OriginalsPath, conf.ThumbnailsPath, size, context.Bool("square"))
}
fmt.Println("Done.")
@ -115,6 +148,8 @@ func main() {
conf.SetValuesFromCliContext(context)
conf.CreateDirectories()
fmt.Printf("Exporting photos to %s...\n", conf.ExportPath)
fmt.Println("[TODO]")

View file

@ -3,6 +3,8 @@ package photoprism
import (
"github.com/kylelemons/go-gypsy/yaml"
"github.com/urfave/cli"
"os"
"path"
)
type Config struct {
@ -73,3 +75,10 @@ func (c *Config) SetValuesFromCliContext(context *cli.Context) error {
return nil
}
func (c *Config) CreateDirectories() {
os.MkdirAll(path.Dir(c.OriginalsPath), os.ModePerm)
os.MkdirAll(path.Dir(c.ThumbnailsPath), os.ModePerm)
os.MkdirAll(path.Dir(c.ImportPath), os.ModePerm)
os.MkdirAll(path.Dir(c.ExportPath), os.ModePerm)
}

View file

@ -103,14 +103,9 @@ func (m *MediaFile) GetCameraModel() string {
func (m *MediaFile) GetCanonicalName() string {
dateCreated := m.GetDateCreated().UTC()
//cameraModel := strings.Replace(m.GetCameraModel(), " ", "_", -1)
result := dateCreated.Format("20060102_150405_") + strings.ToUpper(m.GetHash()[:12])
/* if cameraModel != "" {
result = result + "_" + cameraModel
} */
return result
}
@ -264,6 +259,11 @@ func (m *MediaFile) GetExtension() string {
}
func (m *MediaFile) IsJpeg() bool {
// Don't import/use existing thumbnail files (we create our own)
if m.GetExtension() == ".thm" {
return false
}
return m.GetMimeType() == MimeTypeJpeg
}

View file

@ -3,18 +3,122 @@ package photoprism
import (
"github.com/disintegration/imaging"
"log"
"os"
"fmt"
"path/filepath"
"strings"
)
func CreateThumbnail() {
src, err := imaging.Open("testdata/lena_512.png")
func CreateThumbnailsFromOriginals(originalsPath string, thumbnailsPath string, size int, square bool) {
err := filepath.Walk(originalsPath, func(filename string, fileInfo os.FileInfo, err error) error {
if err != nil || fileInfo.IsDir() || strings.HasPrefix(filepath.Base(filename), ".") {
return nil
}
mediaFile := NewMediaFile(filename)
if !mediaFile.Exists() || !mediaFile.IsJpeg() {
return nil
}
if square {
log.Printf("Creating square %dpx thumbnail for %s", size, filename)
if _, err := mediaFile.GetSquareThumbnail(thumbnailsPath, size); err != nil {
log.Print(err.Error())
}
} else {
log.Printf("Creating %dpx thumbnail for %s", size, filename)
if _, err := mediaFile.GetThumbnail(thumbnailsPath, size); err != nil {
log.Print(err.Error())
}
}
return nil
})
if err != nil {
log.Printf("Open failed: %s", err.Error())
log.Print(err.Error())
}
}
func (m *MediaFile) GetThumbnail(path string, size int) (result *MediaFile, err error) {
canonicalName := m.GetCanonicalName()
dateCreated := m.GetDateCreated()
thumbnailPath := fmt.Sprintf("%s/%dpx/%s", path, size, dateCreated.UTC().Format("2006/01"))
os.MkdirAll(thumbnailPath, os.ModePerm)
thumbnailFilename := fmt.Sprintf("%s/%s_%dpx.jpg", thumbnailPath, canonicalName, size)
if fileExists(thumbnailFilename) {
return NewMediaFile(thumbnailFilename), nil
}
// Crop the original image to 350x350px size using the center anchor.
src = imaging.CropAnchor(src, 350, 350, imaging.Center)
// Resize the cropped image to width = 256px preserving the aspect ratio.
src = imaging.Resize(src, 256, 0, imaging.Lanczos)
return m.CreateThumbnail(thumbnailFilename, size)
}
// Resize preserving the aspect ratio
func (m *MediaFile) CreateThumbnail(filename string, size int) (result *MediaFile, err error) {
image, err := imaging.Open(m.filename)
if err != nil {
log.Printf("open failed: %s", err.Error())
return nil, err
}
image = imaging.Fit(image, size, size, imaging.Lanczos)
err = imaging.Save(image, filename)
if err != nil {
log.Fatalf("failed to save image: %v", err)
return nil, err
}
result = NewMediaFile(filename)
return result, nil
}
func (m *MediaFile) GetSquareThumbnail(path string, size int) (result *MediaFile, err error) {
canonicalName := m.GetCanonicalName()
dateCreated := m.GetDateCreated()
thumbnailPath := fmt.Sprintf("%s/square/%dpx/%s", path, size, dateCreated.UTC().Format("2006/01"))
os.MkdirAll(thumbnailPath, os.ModePerm)
thumbnailFilename := fmt.Sprintf("%s/%s_square_%dpx.jpg", thumbnailPath, canonicalName, size)
if fileExists(thumbnailFilename) {
return NewMediaFile(thumbnailFilename), nil
}
return m.CreateSquareThumbnail(thumbnailFilename, size)
}
// Resize and crop to square format
func (m *MediaFile) CreateSquareThumbnail(filename string, size int) (result *MediaFile, err error) {
image, err := imaging.Open(m.filename)
if err != nil {
log.Printf("open failed: %s", err.Error())
return nil, err
}
image = imaging.Fill(image, size, size, imaging.Center, imaging.Lanczos)
err = imaging.Save(image, filename)
if err != nil {
log.Fatalf("failed to save image: %v", err)
return nil, err
}
result = NewMediaFile(filename)
return result, nil
}

54
thumbnails_test.go Normal file
View file

@ -0,0 +1,54 @@
package photoprism
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestMediaFile_GetThumbnail(t *testing.T) {
conf := NewTestConfig()
conf.CreateDirectories()
conf.InitializeTestData(t)
image1 := NewMediaFile(conf.ImportPath + "/iphone/IMG_6788.JPG")
thumbnail1, err := image1.GetThumbnail(conf.ThumbnailsPath, 350)
assert.Empty(t, err)
assert.IsType(t, &MediaFile{}, thumbnail1)
}
func TestMediaFile_GetSquareThumbnail(t *testing.T) {
conf := NewTestConfig()
conf.CreateDirectories()
conf.InitializeTestData(t)
image1 := NewMediaFile(conf.ImportPath + "/iphone/IMG_6788.JPG")
thumbnail1, err := image1.GetSquareThumbnail(conf.ThumbnailsPath, 350)
assert.Empty(t, err)
assert.IsType(t, &MediaFile{}, thumbnail1)
}
func TestCreateThumbnailsFromOriginals(t *testing.T) {
conf := NewTestConfig()
conf.CreateDirectories()
conf.InitializeTestData(t)
importer := NewImporter(conf.OriginalsPath)
importer.ImportPhotosFromDirectory(conf.ImportPath)
CreateThumbnailsFromOriginals(conf.OriginalsPath, conf.ThumbnailsPath, 600, false)
CreateThumbnailsFromOriginals(conf.OriginalsPath, conf.ThumbnailsPath, 300, true)
}