// 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 decodeDownsample(factor int) decodeFunc { return func(r io.Reader) (image.Image, string, error) { im, err := fastjpeg.DecodeDownsample(r, factor) return im, "jpeg", err } }