Remplissage du dépôt

This commit is contained in:
sys4-fr
2018-12-13 21:25:14 +01:00
commit 3ba9c542bb
10 changed files with 706 additions and 0 deletions

View File

@ -0,0 +1,87 @@
// Copyright 2015 by Sascha L. Teichmann
// Use of this source code is governed by the MIT license
// that can be found in the LICENSE file.
package main
import (
"bufio"
"fmt"
"image"
"image/color"
"image/draw"
"os"
_ "image/jpeg"
_ "image/png"
)
func loadRGBA(filename string) (*image.RGBA, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
var img image.Image
if img, _, err = image.Decode(bufio.NewReader(file)); err != nil {
return nil, fmt.Errorf("Decoding '%s' failed: %s", filename, err)
}
if rgba, ok := img.(*image.RGBA); ok {
return rgba, nil
}
bounds := img.Bounds()
rgba := image.NewRGBA(bounds)
draw.Draw(rgba, bounds, img, image.ZP, draw.Src)
return rgba, nil
}
func averageColor(filename string) (color.Color, error) {
img, err := loadRGBA(filename)
if err != nil {
return nil, err
}
bounds := img.Bounds()
if bounds.Empty() {
return color.Black, nil
}
y := img.PixOffset(bounds.Min.X, bounds.Min.Y)
yEnd := img.PixOffset(bounds.Min.X, bounds.Max.Y)
w := bounds.Dx() * 4
pix := img.Pix
var r, g, b, a uint64
for ; y < yEnd; y += img.Stride {
for pos, end := y, y+w; pos < end; pos += 4 {
pa := uint64(pix[pos+3])
r += pa * uint64(pix[pos])
g += pa * uint64(pix[pos+1])
b += pa * uint64(pix[pos+2])
a += pa
}
}
r /= 255
g /= 255
b /= 255
if s := a / 255; s > 0 {
r /= s
g /= s
b /= s
}
col := color.RGBA{
R: uint8(r),
G: uint8(g),
B: uint8(b),
A: uint8(a / uint64(bounds.Dx()*bounds.Dy()))}
return &col, nil
}

237
cmd/mtautocolors/main.go Normal file
View File

@ -0,0 +1,237 @@
// Copyright 2015 by Sascha L. Teichmann
// Use of this source code is governed by the MIT license
// that can be found in the LICENSE file.
package main
import (
"bufio"
"flag"
"fmt"
"image/color"
"io"
"log"
"os"
"path/filepath"
"regexp"
"runtime"
"sort"
"strings"
"sync"
)
var nodesSplit = regexp.MustCompile(" +")
func usage() {
fmt.Fprintf(os.Stderr,
"Usage: %s [<options>] <nodes.txt> [<data source directory> ...]\n",
os.Args[0])
fmt.Fprintln(os.Stderr, "Options:")
flag.PrintDefaults()
}
func main() {
var predef string
var transparent string
var workers int
flag.Usage = usage
flag.StringVar(&predef, "predefined", "", "predefined colors")
flag.StringVar(&predef, "p", "", "predefined colors (shorthand)")
flag.StringVar(&transparent, "transparent", "glasslike,liquid", "transparent nodes")
flag.StringVar(&transparent, "t", "glasslike,liquid", "transparent nodes (shorthand)")
flag.IntVar(&workers, "workers", 0, "number of image processing workers")
flag.IntVar(&workers, "w", 0, "number of image processing workers (shorthand)")
flag.Parse()
nargs := flag.NArg()
if nargs < 1 {
usage()
os.Exit(1)
}
var err error
var predefs PredefCols
if predef != "" {
if predefs, err = LoadPredefCols(predef); err != nil {
log.Fatalf("Cannot load predefined colors: %s\n", err)
}
}
var roots []string
if nargs > 1 {
roots = flag.Args()[1:]
} else {
roots = []string{"."}
}
files, err := buildFileIndex(roots)
if err != nil {
log.Fatalf("error while building file index: %s\n", err)
}
drawTypes := strings.Split(transparent, ",")
if err = process(flag.Arg(0), drawTypes, files, predefs, workers); err != nil {
log.Fatalf("error while generating colors: %s\n", err)
}
}
func contains(haystack []string, needle string) bool {
for _, straw := range haystack {
if strings.Contains(needle, straw) {
return true
}
}
return false
}
type outLine struct {
name string
col color.Color
alpha bool
}
func asByte(x uint32) byte {
return byte(x >> 8)
}
func (ol *outLine) print(out io.Writer) {
r, g, b, a := ol.col.RGBA()
ba := asByte(a)
if ol.alpha && ba < 255 {
fmt.Fprintf(out, "%s %d %d %d %d\n",
ol.name, asByte(r), asByte(g), asByte(b), ba)
} else {
fmt.Fprintf(out, "%s %d %d %d\n",
ol.name, asByte(r), asByte(g), asByte(b))
}
}
func process(
nodesFile string,
drawTypes []string,
files map[string]string,
predefs PredefCols,
workers int) error {
file, err := os.Open(nodesFile)
if err != nil {
return err
}
defer file.Close()
lineCh := make(chan []string)
if workers < 1 {
workers = runtime.NumCPU()
}
var outLineMu sync.Mutex
var outLines []outLine
var wg sync.WaitGroup
for i := 0; i < workers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
lines:
for line := range lineCh {
name, drawType, texture := line[0], line[1], line[2]
var c color.Color
switch col := predefs.findCol(name); {
case col != nil && col.Complete():
c = col
case col == nil || !col.Complete():
tfile := files[texture]
if tfile == "" {
log.Printf("WARN: node '%s' missing texture '%s'\n", name, texture)
continue lines
}
avg, err := averageColor(tfile)
if err != nil {
log.Printf("WARN: node '%s' defect image: %s\n", name, err)
continue lines
}
if col != nil {
c = col.Apply(avg)
} else {
c = avg
}
}
alpha := contains(drawTypes, drawType)
outLineMu.Lock()
outLines = append(outLines, outLine{
name: name,
col: c,
alpha: alpha,
})
outLineMu.Unlock()
}
}()
}
scanner := bufio.NewScanner(file)
for lineNo := 1; scanner.Scan(); lineNo++ {
parts := nodesSplit.Split(scanner.Text(), 3)
if len(parts) < 3 {
log.Printf("WARN: line %d too short.\n", lineNo)
} else {
lineCh <- parts
}
}
close(lineCh)
wg.Wait()
if err := scanner.Err(); err != nil {
return err
}
// To make it more deterministic.
sort.Slice(outLines, func(i, j int) bool {
return outLines[i].name < outLines[j].name
})
out := bufio.NewWriter(os.Stdout)
for i := range outLines {
outLines[i].print(out)
}
return out.Flush()
}
func buildFileIndex(roots []string) (map[string]string, error) {
index := make(map[string]string)
acceptedExts := map[string]bool{
".png": true,
".jpg": true,
".jpeg": true}
walkFn := func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.Mode().IsRegular() {
return nil
}
name := info.Name()
if !acceptedExts[strings.ToLower(filepath.Ext(name))] {
return nil
}
if _, found := index[name]; !found {
index[name] = path
} else {
log.Printf("WARN: more than one file for '%s'\n", name)
}
return nil
}
for _, root := range roots {
if err := filepath.Walk(root, walkFn); err != nil {
return nil, err
}
}
return index, nil
}

View File

@ -0,0 +1,116 @@
// Copyright 2015 by Sascha L. Teichmann
// Use of this source code is governed by the MIT license
// that can be found in the LICENSE file.
package main
import (
"bufio"
"encoding/json"
"image/color"
"os"
"regexp"
"strconv"
)
type Component struct {
Value uint8
Used bool
}
type Expr struct{ *regexp.Regexp }
type Col struct {
E Expr `json:"expr"`
R Component `json:"r"`
G Component `json:"g"`
B Component `json:"b"`
A Component `json:"a"`
}
type PredefCols []Col
func (e *Expr) UnmarshalJSON(data []byte) error {
unquoted := string(data[1 : len(data)-1])
expr, err := regexp.Compile(unquoted)
if err != nil {
return err
}
*e = Expr{expr}
return nil
}
func (c *Component) UnmarshalJSON(data []byte) error {
v, err := strconv.ParseUint(string(data), 10, 8)
if err != nil {
return err
}
c.Value = uint8(v)
c.Used = true
return nil
}
func LoadPredefCols(filename string) (PredefCols, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
decoder := json.NewDecoder(bufio.NewReader(file))
var predef PredefCols
if err = decoder.Decode(&predef); err != nil {
return nil, err
}
return predef, nil
}
func (pd *PredefCols) findCol(name string) *Col {
for i, n := 0, len(*pd); i < n; i++ {
if (*pd)[i].E.MatchString(name) {
return &(*pd)[i]
}
}
return nil
}
func (c *Col) Complete() bool {
return c.R.Used && c.G.Used && c.B.Used && c.A.Used
}
func (c *Col) RGBA() (r, g, b, a uint32) {
r = uint32(c.R.Value)
r |= r << 8
g = uint32(c.G.Value)
g |= g << 8
b = uint32(c.B.Value)
b |= b << 8
a = uint32(c.A.Value)
a |= a << 8
return
}
func (c *Col) Apply(other color.Color) color.Color {
r, g, b, a := other.RGBA()
x := color.RGBA{
R: uint8(r >> 8),
G: uint8(g >> 8),
B: uint8(b >> 8),
A: uint8(a >> 8)}
if c.R.Used {
x.R = c.R.Value
}
if c.G.Used {
x.G = c.G.Value
}
if c.B.Used {
x.B = c.B.Value
}
if c.A.Used {
x.A = c.A.Value
}
return &x
}