func main() { flag.IntVar(¶ms.Width, "w", 128, "target width") flag.IntVar(¶ms.Height, "h", 128, "target width") flag.BoolVar(¶ms.ForceAspect, "a", false, "force aspect") flag.BoolVar(¶ms.Upscale, "u", false, "also upscale if needed") flag.IntVar(¶ms.Quality, "q", 95, "JPEG quality") flag.BoolVar(¶ms.Optimize, "o", false, "optimize JPEG") flag.Float64Var(¶ms.PrescaleFactor, "p", 1.0, "prescale factor") flag.Parse() if flag.NArg() != 2 { fmt.Printf("USAGE: mkthumb [options] input_file output_file\n") flag.PrintDefaults() os.Exit(1) } inputFilename := flag.Arg(0) outputFilename := flag.Arg(1) fmt.Printf("Thumbnailing %s\n", inputFilename) ifd, err := os.Open(inputFilename) if err != nil { panic(err) } ofd, err := os.Create(outputFilename) if err != nil { panic(err) } err = thumbnail.MakeThumbnail(ifd, ofd, params) if err != nil { panic(err) } }
func thumbServer(w http.ResponseWriter, r *http.Request) { startTime := time.Now() defer func() { elapsed := int64(time.Now().Sub(startTime) / 1000) atomic.AddInt64(&http_stats.total_time_us, elapsed) }() atomic.AddInt64(&http_stats.received, 1) atomic.AddInt64(&http_stats.inflight, 1) defer atomic.AddInt64(&http_stats.inflight, -1) path := r.URL.RequestURI() // Defaults var params = thumbnail.ThumbnailParameters{ Upscale: true, ForceAspect: true, Quality: 90, Optimize: false, PrescaleFactor: 2.0, } if path[0] != '/' { http.Error(w, "Path should start with /", http.StatusBadRequest) atomic.AddInt64(&http_stats.arg_error, 1) return } parts := strings.SplitN(path[1:], "/", 2) if len(parts) < 2 { http.Error(w, "Path needs to have at least two components", http.StatusBadRequest) atomic.AddInt64(&http_stats.arg_error, 1) return } for _, arg := range strings.Split(parts[0], ",") { tup := strings.SplitN(arg, "=", 2) if len(tup) != 2 { http.Error(w, "Arguments must have the form name=value", http.StatusBadRequest) atomic.AddInt64(&http_stats.arg_error, 1) return } switch tup[0] { case "w", "h", "q", "u", "a", "o": val, err := strconv.Atoi(tup[1]) if err != nil { http.Error(w, "Invalid integer value for "+tup[0], http.StatusBadRequest) atomic.AddInt64(&http_stats.arg_error, 1) return } switch tup[0] { case "w": params.Width = val case "h": params.Height = val case "q": params.Quality = val case "u": params.Upscale = val != 0 case "a": params.ForceAspect = val != 0 case "o": params.Optimize = val != 0 } case "p": val, err := strconv.ParseFloat(tup[1], 64) if err != nil { http.Error(w, "Invalid float value for "+tup[0], http.StatusBadRequest) atomic.AddInt64(&http_stats.arg_error, 1) return } params.PrescaleFactor = val } } if params.Width <= 0 || params.Width > maxDimension { http.Error(w, "Width (w) not specified or invalid", http.StatusBadRequest) atomic.AddInt64(&http_stats.arg_error, 1) return } if params.Height <= 0 || params.Height > maxDimension { http.Error(w, "Height (h) not specified or invalid", http.StatusBadRequest) atomic.AddInt64(&http_stats.arg_error, 1) return } if params.Width*params.Height > maxPixels { http.Error(w, "Image dimensions are insane", http.StatusBadRequest) atomic.AddInt64(&http_stats.arg_error, 1) return } if params.Quality > 100 || params.Quality < 0 { http.Error(w, "Quality must be between 0 and 100", http.StatusBadRequest) atomic.AddInt64(&http_stats.arg_error, 1) return } srcReader, err := client.Get("http://" + parts[1]) if err != nil { http.Error(w, "Upstream failed: "+err.Error(), http.StatusBadGateway) atomic.AddInt64(&http_stats.upstream_error, 1) return } if srcReader.StatusCode != http.StatusOK { http.Error(w, "Upstream failed: "+srcReader.Status, srcReader.StatusCode) atomic.AddInt64(&http_stats.upstream_error, 1) return } w.Header().Set("Content-Type", "image/jpeg") w.Header().Set("Last-Modified", time.Now().UTC().Format(http.TimeFormat)) err = thumbnail.MakeThumbnail(srcReader.Body, w, params) if err != nil { switch err := err.(type) { case *url.Error: http.Error(w, "Upstream failed: "+err.Error(), http.StatusBadGateway) atomic.AddInt64(&http_stats.upstream_error, 1) return default: http.Error(w, "Thumbnailing failed: "+err.Error(), http.StatusInternalServerError) atomic.AddInt64(&http_stats.thumb_error, 1) return } } srcReader.Body.Close() atomic.AddInt64(&http_stats.ok, 1) }