为什么Bild中的jpeg.Decode(bytes.NewReader(imageBytes))和jpeg.Encode(buf,img,nil)占用大量CPU?

I am trying to build an application which manipulates images on the run using Bild. But the above-mentioned methods are eating up a lot CPU(90%) for images. What is the reason for these methods to use high CPU? Are there any other methods or packages which uses less CPU?

func imageDecode(imageBytes []byte) (image.Image, error) {
    contentType := http.DetectContentType(imageBytes)
    var err error
    var img image.Image
    if contentType == constants.PngContentType {
        img, err = png.Decode(bytes.NewReader(imageBytes))
    } else if contentType == constants.JpegContentType {
        img, err = jpeg.Decode(bytes.NewReader(imageBytes))
    } else if contentType == constants.GifContentType {
        img, err = gif.Decode(bytes.NewReader(imageBytes))
    } else {
        img, err = nil, fmt.Errorf("decode error invalid content-type for filename: ")
    }
    if err != nil {
        return img, err
    }
    return img, nil
}

func imageEncode(imageBytes []byte, img image.Image) ([]byte, error) {
    contentType := http.DetectContentType(imageBytes)
    if contentType == constants.PngContentType && isOpaque(img) {
        contentType = constants.JpegContentType
    }
    buf := new(bytes.Buffer)
    var err error
    var transformedImageBytes []byte
    if contentType == constants.PngContentType {
        pngEnc := png.Encoder{CompressionLevel: png.BestCompression}
        err = pngEnc.Encode(buf, img)
    } else if contentType == constants.JpegContentType {
        err = jpeg.Encode(buf, img, nil)
    } else if contentType == constants.GifContentType {
        err = gif.Encode(buf, img, nil)
    } else {
        err = fmt.Errorf("encode error invalid content-type")
    }
    if err != nil {
        return transformedImageBytes, err
    }
    transformedImageBytes = buf.Bytes()
    return transformedImageBytes, err
}

You don't need to manually detect the image type and use different decoding calls, the image package does that for you already, when using image.Decode(). Just make sure you have the image decoders registered prior, which you can achieve by using blank imports, e.g.:

import (
    _ "image/gif"
    _ "image/jpeg"
    _ "image/png"
)

func imageDecode(imageBytes []byte) (image.Image, error) {
    img, _, err := image.Decode(bytes.NewReader(imageBytes))
}

Although I'm not sure performance will improve significantly by this.

What you should do is use "smart" conversion. By this I mean in certain cases you can omit decoding and re-encoding the image, you can just send the input to the output as-is (e.g. using io.Copy()):

  • If input is a GIF image.
  • If input is a JPEG image.

You only have to truly decode the image if it is of PNG format. Note that detecting if a PNG image is opaque is slow as it has to examine all the pixels (unless a transparent pixel is found earlier).