Implemented thumbnails command
This commit is contained in:
parent
187449226a
commit
3c80d4a842
|
@ -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]")
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
10
mediafile.go
10
mediafile.go
|
@ -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
|
||||
}
|
||||
|
||||
|
|
120
thumbnails.go
120
thumbnails.go
|
@ -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
54
thumbnails_test.go
Normal 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)
|
||||
}
|
Loading…
Reference in a new issue