Add luminance and monochrome return values to MediaFile.Colors()
This commit is contained in:
parent
7ddfb6d9dc
commit
5e1210c508
|
@ -18,6 +18,8 @@ type Photo struct {
|
|||
PhotoArtist string
|
||||
PhotoColors string
|
||||
PhotoColor string
|
||||
PhotoLuminance string
|
||||
PhotoMonochrome bool
|
||||
PhotoCanonicalName string
|
||||
PhotoFavorite bool
|
||||
PhotoLat float64
|
||||
|
|
|
@ -2,8 +2,10 @@ package photoprism
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"log"
|
||||
"math"
|
||||
|
||||
"github.com/disintegration/imaging"
|
||||
"github.com/lucasb-eyer/go-colorful"
|
||||
|
@ -12,6 +14,9 @@ import (
|
|||
type MaterialColor uint16
|
||||
type MaterialColors []MaterialColor
|
||||
|
||||
type Luminance uint8
|
||||
type LightMap []Luminance
|
||||
|
||||
const ColorSampleSize = 3
|
||||
|
||||
const (
|
||||
|
@ -87,6 +92,18 @@ func (c MaterialColors) Hex() (result string) {
|
|||
return result
|
||||
}
|
||||
|
||||
func (l Luminance) Hex() string {
|
||||
return fmt.Sprintf("%X", l)
|
||||
}
|
||||
|
||||
func (m LightMap) Hex() (result string) {
|
||||
for _, luminance := range m {
|
||||
result += luminance.Hex()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
var materialColorMap = map[color.RGBA]MaterialColor{
|
||||
{0x00, 0x00, 0x00, 0xff}: Black,
|
||||
{0x79, 0x55, 0x48, 0xff}: Brown,
|
||||
|
@ -122,28 +139,35 @@ func colorfulToMaterialColor(actualColor colorful.Color) (result MaterialColor)
|
|||
return result
|
||||
}
|
||||
|
||||
// Colors returns color information for a media file.
|
||||
func (m *MediaFile) Colors() (colors MaterialColors, mainColor MaterialColor, err error) {
|
||||
func (m *MediaFile) Resize(width, height int) (result *image.NRGBA, err error) {
|
||||
jpeg, err := m.GetJpeg()
|
||||
|
||||
if err != nil {
|
||||
log.Printf("can't find jpeg: %s", err.Error())
|
||||
|
||||
return colors, mainColor, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
img, err := imaging.Open(jpeg.GetFilename(), imaging.AutoOrientation(true))
|
||||
img, err:= imaging.Open(jpeg.GetFilename(), imaging.AutoOrientation(true))
|
||||
|
||||
if err != nil {
|
||||
log.Printf("can't open jpeg: %s", err.Error())
|
||||
|
||||
return colors, mainColor, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
img = imaging.Resize(img, ColorSampleSize, ColorSampleSize, imaging.Box)
|
||||
return imaging.Resize(img, width, height, imaging.Box), nil
|
||||
}
|
||||
|
||||
// Colors returns color information for a media file.
|
||||
func (m *MediaFile) Colors() (colors MaterialColors, mainColor MaterialColor, luminance LightMap, monochrome bool, err error) {
|
||||
img, err := m.Resize(ColorSampleSize, ColorSampleSize)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("can't open image: %s", err.Error())
|
||||
|
||||
return colors, mainColor, luminance, monochrome, err
|
||||
}
|
||||
|
||||
bounds := img.Bounds()
|
||||
width, height := bounds.Max.X, bounds.Max.Y
|
||||
monochrome = true
|
||||
|
||||
colorCount := make(map[MaterialColor]uint16)
|
||||
var mainColorCount uint16
|
||||
|
@ -166,8 +190,15 @@ func (m *MediaFile) Colors() (colors MaterialColors, mainColor MaterialColor, er
|
|||
mainColor = materialColor
|
||||
}
|
||||
|
||||
_, s, l := rgbColor.Hsl()
|
||||
|
||||
if s != 0 {
|
||||
monochrome = false
|
||||
}
|
||||
|
||||
luminance = append(luminance, Luminance(math.Round(l * 16)))
|
||||
}
|
||||
}
|
||||
|
||||
return colors, mainColor, nil
|
||||
return colors, mainColor, luminance, monochrome, nil
|
||||
}
|
||||
|
|
|
@ -15,11 +15,12 @@ func TestMediaFile_GetColors_Slow(t *testing.T) {
|
|||
conf.InitializeTestData(t)
|
||||
|
||||
if mediaFile2, err := NewMediaFile(conf.ImportPath() + "/iphone/IMG_6788.JPG"); err == nil {
|
||||
colors, main, err := mediaFile2.Colors()
|
||||
colors, main, l, m, err := mediaFile2.Colors()
|
||||
|
||||
t.Log(colors, main, err)
|
||||
t.Log(colors, main, l, m, err)
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, m)
|
||||
assert.IsType(t, MaterialColors{}, colors)
|
||||
assert.Equal(t, "grey", main.Name())
|
||||
assert.Equal(t, MaterialColors{0x2, 0x1, 0x2, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2}, colors)
|
||||
|
@ -28,11 +29,12 @@ func TestMediaFile_GetColors_Slow(t *testing.T) {
|
|||
}
|
||||
|
||||
if mediaFile3, err := NewMediaFile(conf.ImportPath() + "/raw/20140717_154212_1EC48F8489.jpg"); err == nil {
|
||||
colors, main, err := mediaFile3.Colors()
|
||||
colors, main, l, m, err := mediaFile3.Colors()
|
||||
|
||||
t.Log(colors, main, err)
|
||||
t.Log(colors, main, l, m, err)
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, m)
|
||||
assert.IsType(t, MaterialColors{}, colors)
|
||||
assert.Equal(t, "grey", main.Name())
|
||||
|
||||
|
|
|
@ -13,27 +13,31 @@ func TestMediaFile_GetColors(t *testing.T) {
|
|||
conf.InitializeTestData(t)
|
||||
|
||||
if mediaFile1, err := NewMediaFile(conf.ImportPath() + "/dog.jpg"); err == nil {
|
||||
colors, main, err := mediaFile1.Colors()
|
||||
colors, main, l, m, err := mediaFile1.Colors()
|
||||
|
||||
t.Log(colors, main, err)
|
||||
t.Log(colors, main, l, m, err)
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, m)
|
||||
assert.IsType(t, MaterialColors{}, colors)
|
||||
assert.Equal(t, "grey", main.Name())
|
||||
assert.Equal(t, MaterialColors{0x1, 0x2, 0x1, 0x2, 0x2, 0x1, 0x1, 0x1, 0x0}, colors)
|
||||
assert.Equal(t, LightMap{5, 9, 7, 10, 9, 5, 5, 6, 2}, l)
|
||||
} else {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if mediaFile2, err := NewMediaFile(conf.ImportPath() + "/ape.jpeg"); err == nil {
|
||||
colors, main, err := mediaFile2.Colors()
|
||||
colors, main, l, m, err := mediaFile2.Colors()
|
||||
|
||||
t.Log(colors, main, err)
|
||||
t.Log(colors, main, l, m, err)
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, m)
|
||||
assert.IsType(t, MaterialColors{}, colors)
|
||||
assert.Equal(t, "teal", main.Name())
|
||||
assert.Equal(t, MaterialColors{0x8, 0x8, 0x2, 0x8, 0x2, 0x1, 0x8, 0x1, 0x2}, colors)
|
||||
assert.Equal(t, LightMap{8, 8, 7, 7, 7, 5, 8, 6, 8}, l)
|
||||
} else {
|
||||
t.Error(err)
|
||||
}
|
||||
|
|
|
@ -94,10 +94,12 @@ func (i *Indexer) indexMediaFile(mediaFile *MediaFile) string {
|
|||
}
|
||||
|
||||
// PhotoColors
|
||||
photoColors, photoColor, _ := jpeg.Colors()
|
||||
photoColors, photoColor, luminance, monochrome, _ := jpeg.Colors()
|
||||
|
||||
photo.PhotoColor = photoColor.Name()
|
||||
photo.PhotoColors = photoColors.Hex()
|
||||
photo.PhotoLuminance = luminance.Hex()
|
||||
photo.PhotoMonochrome = monochrome
|
||||
|
||||
// Tags (TensorFlow)
|
||||
tags = i.getImageTags(jpeg)
|
||||
|
@ -163,10 +165,12 @@ func (i *Indexer) indexMediaFile(mediaFile *MediaFile) string {
|
|||
} else if time.Now().Sub(photo.UpdatedAt).Minutes() > 10 { // If updated more than 10 minutes ago
|
||||
if jpeg, err := mediaFile.GetJpeg(); err == nil {
|
||||
// PhotoColors
|
||||
photoColors, photoColor, _ := jpeg.Colors()
|
||||
photoColors, photoColor, luminance, monochrome, _ := jpeg.Colors()
|
||||
|
||||
photo.PhotoColor = photoColor.Name()
|
||||
photo.PhotoColors = photoColors.Hex()
|
||||
photo.PhotoLuminance = luminance.Hex()
|
||||
photo.PhotoMonochrome = monochrome
|
||||
|
||||
photo.Camera = models.NewCamera(mediaFile.GetCameraModel(), mediaFile.GetCameraMake()).FirstOrCreate(i.db)
|
||||
photo.Lens = models.NewLens(mediaFile.GetLensModel(), mediaFile.GetLensMake()).FirstOrCreate(i.db)
|
||||
|
|
Loading…
Reference in New Issue
Block a user