func eval(t *testing.T, path string, f storage.Image, size image.Point, colors []int) string { var b []byte w := bytes.NewBuffer(b) p := processor.New() f.ValidatedWidth *= u f.ValidatedHeight *= u pixels, err := p.Preprocess(path) if err != nil { t.Fatalf("cannot preprocess image: error=%v", err) } f, err = f.Normalize(pixels.Bounds().Size()) if err != nil { t.Fatalf("fail to normalize: error=%v", err) } if _, err := p.Process(pixels, w, f); err != nil { t.Fatalf("cannot process image: %v", err) return "" } r := bytes.NewReader(w.Bytes()) img, format, err := image.Decode(r) if err != nil { t.Fatalf("cannot decode image: %v", err) return "" } expectedSize := size.Mul(u) rect := img.Bounds() actualSize := rect.Size() if !actualSize.Eq(expectedSize) { t.Fatalf("wrong size expected %v, but actual %v", expectedSize, actualSize) return "" } evalPixels(t, img, size, colors) return format }
func BenchmarkProcess(b *testing.B) { if err := fetcher.Init(); err != nil { b.Fatal(err) } o, err := option.New(os.Args[1:]) if err != nil { b.Fatal(err) } for i := 0; i < b.N; i++ { o, err := storage.NewImage(map[string][]string{ "url": []string{""}, "width": []string{"800"}, "height": []string{"0"}, }, o.Hosts) if err != nil { b.Fatalf("%s", err) } path, err := fetcher.Fetch(o.ValidatedURL) if err != nil { b.Fatalf("%s", err.Error()) } var bs []byte w := bytes.NewBuffer(bs) p := processor.New() image, err := p.Preprocess(path) if err != nil { b.Fatalf("%s", err.Error()) } if _, err := p.Process(image, w, o); err != nil { b.Fatalf("%s", err.Error()) } } }
// operate は手続き的に一連のリサイズ処理を行う。 // エラーを画一的に扱うためにメソッドとして切り分けを行っている func (h *Handler) operate(resp http.ResponseWriter, req *http.Request) error { t := log.Start() defer log.End(t) // 1. URLクエリからリクエストされているオプションを抽出する i, err := storage.NewImage(req.URL.Query(), h.Hosts) if err != nil { return err } // 3. バリデート済みオプションでリサイズをしたキャッシュがあるか調べる // 4. キャッシュがあればリサイズ画像のURLにリダイレクトする cache := storage.Image{} h.Storage.Where(&storage.Image{ ValidatedHash: i.ValidatedHash, ValidatedWidth: i.ValidatedWidth, ValidatedHeight: i.ValidatedHeight, ValidatedMethod: i.ValidatedMethod, ValidatedFormat: i.ValidatedFormat, ValidatedQuality: i.ValidatedQuality, }).First(&cache) log.Debugln(cache.ID) if cache.ID != 0 { log.Infof("validated cache %+v exists, requested with %+v", cache, i) url := h.Uploader.CreateURL(cache.Filename) http.Redirect(resp, req, url, http.StatusSeeOther) return nil } log.Infof("validated cache doesn't exist, requested with %+v", i) // 5. 元画像を取得する // 6. リサイズの前処理をする filename, err := fetcher.Fetch(i.ValidatedURL) defer func() { if err := fetcher.Clean(filename); err != nil { log.Errorf("fail to clean fetched file: %s", filename) } }() if err != nil { return err } var b []byte buf := bytes.NewBuffer(b) p := processor.New() pixels, err := p.Preprocess(filename) if err != nil { return err } // 7. 正規化する // 8. 正規化済みのオプションでリサイズをしたことがあるか調べる // 9. あればリサイズ画像のURLにリダイレクトする i, err = i.Normalize(pixels.Bounds().Size()) if err != nil { return err } cache = storage.Image{} h.Storage.Where(&storage.Image{ NormalizedHash: i.NormalizedHash, DestWidth: i.DestWidth, DestHeight: i.DestHeight, ValidatedMethod: i.ValidatedMethod, ValidatedFormat: i.ValidatedFormat, ValidatedQuality: i.ValidatedQuality, }).First(&cache) if cache.ID != 0 { log.Infof("normalized cache %+v exists, requested with %+v", cache, i) url := h.Uploader.CreateURL(cache.Filename) http.Redirect(resp, req, url, http.StatusSeeOther) return nil } log.Infof("normalized cache doesn't exist, requested with %+v", i) // 10. リサイズする // 11. ファイルオブジェクトの処理結果フィールドを埋める // 12. レスポンスする size, err := p.Process(pixels, buf, i) if err != nil { return err } b = buf.Bytes() i.ETag = fmt.Sprintf("%x", md5.Sum(b)) i.Filename = i.CreateFilename() i.ContentType = contentTypes[i.ValidatedFormat] i.CanvasWidth = size.X i.CanvasHeight = size.Y resp.Header().Add("Content-Type", i.ContentType) io.Copy(resp, bufio.NewReader(buf)) // レスポンスを完了させるために非同期に処理する go h.save(b, i) return nil }