| /* |
| * Copyright 2017 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| package main |
| |
| import ( |
| "encoding/json" |
| "errors" |
| "fmt" |
| "image" |
| "image/draw" |
| "image/png" |
| "log" |
| "net/http" |
| "os" |
| "path" |
| "sort" |
| "strings" |
| "sync" |
| |
| "go.skia.org/infra/golden/go/search" |
| ) |
| |
| const ( |
| min_png = "min.png" |
| max_png = "max.png" |
| ) |
| |
| type ExportTestRecordArray []search.ExportTestRecord |
| |
| func (a ExportTestRecordArray) Len() int { return len(a) } |
| func (a ExportTestRecordArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] } |
| func (a ExportTestRecordArray) Less(i, j int) bool { return a[i].TestName < a[j].TestName } |
| |
| func in(v string, a []string) bool { |
| for _, u := range a { |
| if u == v { |
| return true |
| } |
| } |
| return false |
| } |
| |
| func clampU8(v int) uint8 { |
| if v < 0 { |
| return 0 |
| } else if v > 255 { |
| return 255 |
| } |
| return uint8(v) |
| } |
| |
| func processTest(testName string, imgUrls []string, output string) error { |
| if strings.ContainsRune(testName, '/') { |
| return nil |
| } |
| output_directory := path.Join(output, testName) |
| var img_max image.NRGBA |
| var img_min image.NRGBA |
| for _, url := range imgUrls { |
| resp, err := http.Get(url) |
| if err != nil { |
| return err |
| } |
| img, err := png.Decode(resp.Body) |
| resp.Body.Close() |
| if err != nil { |
| return err |
| } |
| if img_max.Rect.Max.X == 0 { |
| // N.B. img_max.Pix may alias img.Pix (if they're already NRGBA). |
| img_max = toNrgba(img) |
| img_min = copyNrgba(img_max) |
| continue |
| } |
| w := img.Bounds().Max.X - img.Bounds().Min.X |
| h := img.Bounds().Max.Y - img.Bounds().Min.Y |
| if img_max.Rect.Max.X != w || img_max.Rect.Max.Y != h { |
| return errors.New("size mismatch") |
| } |
| img_nrgba := toNrgba(img) |
| for i, value := range img_nrgba.Pix { |
| if value > img_max.Pix[i] { |
| img_max.Pix[i] = value |
| } else if value < img_min.Pix[i] { |
| img_min.Pix[i] = value |
| } |
| } |
| } |
| if img_max.Rect.Max.X == 0 { |
| return nil |
| } |
| |
| if err := os.Mkdir(output_directory, os.ModePerm); err != nil && !os.IsExist(err) { |
| return err |
| } |
| if err := writePngToFile(path.Join(output_directory, min_png), &img_min); err != nil { |
| return err |
| } |
| if err := writePngToFile(path.Join(output_directory, max_png), &img_max); err != nil { |
| return err |
| } |
| return nil |
| |
| } |
| |
| func readMetaJsonFile(filename string) ([]search.ExportTestRecord, error) { |
| file, err := os.Open(filename) |
| if err != nil { |
| return nil, err |
| } |
| dec := json.NewDecoder(file) |
| var records []search.ExportTestRecord |
| err = dec.Decode(&records) |
| return records, err |
| } |
| |
| func writePngToFile(path string, img image.Image) error { |
| file, err := os.Create(path) |
| if err != nil { |
| return err |
| } |
| defer file.Close() |
| return png.Encode(file, img) |
| } |
| |
| // to_nrgb() may return a shallow copy of img if it's already NRGBA. |
| func toNrgba(img image.Image) image.NRGBA { |
| switch v := img.(type) { |
| case *image.NRGBA: |
| return *v |
| } |
| nimg := *image.NewNRGBA(img.Bounds()) |
| draw.Draw(&nimg, img.Bounds(), img, image.Point{0, 0}, draw.Src) |
| return nimg |
| } |
| |
| func copyNrgba(src image.NRGBA) image.NRGBA { |
| dst := image.NRGBA{make([]uint8, len(src.Pix)), src.Stride, src.Rect} |
| copy(dst.Pix, src.Pix) |
| return dst |
| } |
| |
| func main() { |
| if len(os.Args) != 3 { |
| log.Printf("Usage:\n %s INPUT.json OUTPUT_DIRECTORY\n\n", os.Args[0]) |
| os.Exit(1) |
| } |
| input := os.Args[1] |
| output := os.Args[2] |
| // output is removed and replaced with a clean directory. |
| if err := os.RemoveAll(output); err != nil && !os.IsNotExist(err) { |
| log.Fatal(err) |
| } |
| if err := os.MkdirAll(output, os.ModePerm); err != nil && !os.IsExist(err) { |
| log.Fatal(err) |
| } |
| |
| records, err := readMetaJsonFile(input) |
| if err != nil { |
| log.Fatal(err) |
| } |
| sort.Sort(ExportTestRecordArray(records)) |
| |
| var wg sync.WaitGroup |
| for _, record := range records { |
| var goodUrls []string |
| for _, digest := range record.Digests { |
| if (in("vk", digest.ParamSet["config"]) || |
| in("gles", digest.ParamSet["config"])) && |
| digest.Status == "positive" { |
| goodUrls = append(goodUrls, digest.URL) |
| } |
| } |
| wg.Add(1) |
| go func(testName string, imgUrls []string, output string) { |
| defer wg.Done() |
| if err := processTest(testName, imgUrls, output); err != nil { |
| log.Fatal(err) |
| } |
| fmt.Printf("\r%-60s", testName) |
| }(record.TestName, goodUrls, output) |
| } |
| wg.Wait() |
| fmt.Printf("\r%60s\n", "") |
| } |