// decoder reads an image from r and modifies the image as defined by opts. // swapDimensions indicates the decoded image will be rotated after being // returned, and when interpreting opts, the post-rotation dimensions should // be considered. // The decoded image is returned in im. The registered name of the decoder // used is returned in format. If the image was not successfully decoded, err // will be non-nil. If the decoded image was made smaller, needRescale will // be true. func decode(r io.Reader, opts *DecodeOpts, swapDimensions bool) (im image.Image, format string, err error, needRescale bool) { if opts == nil { // Fall-back to normal decode. im, format, err = image.Decode(r) return im, format, err, false } var buf bytes.Buffer tr := io.TeeReader(r, &buf) ic, format, err := image.DecodeConfig(tr) if err != nil { return nil, "", err, false } mr := io.MultiReader(&buf, r) b := image.Rect(0, 0, ic.Width, ic.Height) sw, sh, needRescale := opts.rescaleDimensions(b, swapDimensions) if !needRescale { im, format, err = image.Decode(mr) return im, format, err, false } imageDebug(fmt.Sprintf("Resizing from %dx%d -> %dx%d", ic.Width, ic.Height, sw, sh)) if format == "cr2" { // Replace mr with an io.Reader to the JPEG thumbnail embedded in a // CR2 image. if mr, err = cr2.NewReader(mr); err != nil { return nil, "", err, false } format = "jpeg" } if format == "jpeg" && fastjpeg.Available() { factor := fastjpeg.Factor(ic.Width, ic.Height, sw, sh) if factor > 1 { var buf bytes.Buffer tr := io.TeeReader(mr, &buf) im, err = fastjpeg.DecodeDownsample(tr, factor) switch err.(type) { case fastjpeg.DjpegFailedError: log.Printf("Retrying with jpeg.Decode, because djpeg failed with: %v", err) im, err = jpeg.Decode(io.MultiReader(&buf, mr)) case nil: // fallthrough to rescale() below. default: return nil, format, err, false } return rescale(im, sw, sh), format, err, true } } // Fall-back to normal decode. im, format, err = image.Decode(mr) if err != nil { return nil, "", err, false } return rescale(im, sw, sh), format, err, needRescale }
func testRun(b testing.TB, decode decodeFunc) { if !fastjpeg.Available() { b.Skip("Skipping benchmark, djpeg unavailable.") } im, _, err := decode(bytes.NewReader(jpegBytes)) if err != nil { b.Fatal(err) } rect := im.Bounds() w, h := 128, 128 im = resize.Resize(im, rect, w, h) err = jpeg.Encode(ioutil.Discard, im, nil) if err != nil { b.Fatal(err) } }
func BenchmarkDjpeg8(b *testing.B) { if !fastjpeg.Available() { b.Skip("Skipping benchmark, djpeg unavailable.") } common(b, decodeDownsample(8)) }