Beispiel #1
0
func main() {
	flag.IntVar(&params.Width, "w", 128, "target width")
	flag.IntVar(&params.Height, "h", 128, "target width")
	flag.BoolVar(&params.ForceAspect, "a", false, "force aspect")
	flag.BoolVar(&params.Upscale, "u", false, "also upscale if needed")
	flag.IntVar(&params.Quality, "q", 95, "JPEG quality")
	flag.BoolVar(&params.Optimize, "o", false, "optimize JPEG")
	flag.Float64Var(&params.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)
	}
}
Beispiel #2
0
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)
}