From 1fa11c162ad05870d309d92bd38a583d4228fade Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Tue, 20 Mar 2018 21:09:15 +0100 Subject: [PATCH] Calculate average color of images --- pages/anime/anime.pixy | 2 +- .../refresh-anime-average-color.go | 106 ++++++++++++++++++ scripts/AnimeNotifier.ts | 5 + 3 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 patches/refresh-anime-average-color/refresh-anime-average-color.go diff --git a/pages/anime/anime.pixy b/pages/anime/anime.pixy index 07dcfe6d..0058fc6c 100644 --- a/pages/anime/anime.pixy +++ b/pages/anime/anime.pixy @@ -8,7 +8,7 @@ component Anime(anime *arn.Anime, listItem *arn.AnimeListItem, tracks []*arn.Sou component AnimeMainColumn(anime *arn.Anime, listItem *arn.AnimeListItem, tracks []*arn.SoundTrack, episodes []*arn.AnimeEpisode, user *arn.User) .anime-header(data-id=anime.ID) a.anime-image-container.mountable(href=anime.ImageLink("original"), target="_blank") - img.anime-cover-image.lazy(data-src=anime.ImageLink("large"), data-webp="true", alt=anime.Title.ByUser(user)) + img.anime-cover-image.lazy(data-src=anime.ImageLink("large"), data-webp="true", data-color=anime.Image.AverageColor, alt=anime.Title.ByUser(user)) .space diff --git a/patches/refresh-anime-average-color/refresh-anime-average-color.go b/patches/refresh-anime-average-color/refresh-anime-average-color.go new file mode 100644 index 00000000..24b5c593 --- /dev/null +++ b/patches/refresh-anime-average-color/refresh-anime-average-color.go @@ -0,0 +1,106 @@ +package main + +import ( + "bytes" + "flag" + "fmt" + "image" + "io/ioutil" + "os" + "path" + + "github.com/animenotifier/arn" + "github.com/fatih/color" +) + +func main() { + color.Yellow("Updating anime image average colors") + + defer arn.Node.Close() + defer color.Green("Finished.") + + // Parse flags + var animeID string + flag.StringVar(&animeID, "id", "", "ID of the anime that you want to refresh") + flag.Parse() + + // Refresh 1 anime in case ID was specified + if animeID != "" { + anime, _ := arn.GetAnime(animeID) + + if anime != nil { + work(anime) + } + + return + } + + // Otherwise refresh all anime + for anime := range arn.StreamAnime() { + work(anime) + } +} + +// work refreshes the average color of the given anime. +func work(anime *arn.Anime) { + base := path.Join(arn.Root, "/images/anime/small/", anime.ID) + + if _, err := os.Stat(base + ".jpg"); err != nil { + color.Red(err.Error()) + return + } + + update(anime, base+".jpg") +} + +// update expects a file to load as image for the anime and update the average color. +func update(anime *arn.Anime, filePath string) { + fmt.Println(anime.ID, anime) + + // Load + data, err := ioutil.ReadFile(filePath) + + if err != nil { + color.Red(err.Error()) + return + } + + // Decode + img, _, err := image.Decode(bytes.NewReader(data)) + + if err != nil { + color.Red(err.Error()) + return + } + + width := img.Bounds().Dx() + height := img.Bounds().Dy() + + totalR := uint64(0) + totalG := uint64(0) + totalB := uint64(0) + + for x := 0; x < width; x++ { + for y := 0; y < height; y++ { + r, g, b, _ := img.At(x, y).RGBA() + totalR += uint64(r) + totalG += uint64(g) + totalB += uint64(b) + } + } + + pixels := uint64(width * height) + + const max = float64(65535) + averageR := float64(totalR/pixels) / max + averageG := float64(totalG/pixels) / max + averageB := float64(totalB/pixels) / max + + h, s, l := arn.RGBToHSL(averageR, averageG, averageB) + + anime.Image.AverageColor.Hue = h + anime.Image.AverageColor.Saturation = s + anime.Image.AverageColor.Lightness = l + + anime.Save() +} diff --git a/scripts/AnimeNotifier.ts b/scripts/AnimeNotifier.ts index f2e0be37..07e8b824 100644 --- a/scripts/AnimeNotifier.ts +++ b/scripts/AnimeNotifier.ts @@ -536,6 +536,11 @@ export class AnimeNotifier { } lazyLoadImage(element: HTMLImageElement) { + if(element.dataset.color) { + element.style.backgroundColor = element.dataset.color + this.elementFound.queue(element) + } + // Once the image becomes visible, load it element["became visible"] = () => { let dataSrc = element.dataset.src