github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/app/imaging/encode.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package imaging
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"image"
    10  	"io"
    11  
    12  	"image/jpeg"
    13  	"image/png"
    14  )
    15  
    16  // EncoderOptions holds configuration options for an image encoder.
    17  type EncoderOptions struct {
    18  	// The level of concurrency for the encoder. This defines a limit on the
    19  	// number of concurrently running encoding goroutines.
    20  	ConcurrencyLevel int
    21  }
    22  
    23  func (o *EncoderOptions) validate() error {
    24  	if o.ConcurrencyLevel < 0 {
    25  		return errors.New("ConcurrencyLevel must be non-negative")
    26  	}
    27  	return nil
    28  }
    29  
    30  // Decoder holds the necessary state to encode images.
    31  // This is safe to be used from multiple goroutines.
    32  type Encoder struct {
    33  	sem        chan struct{}
    34  	opts       EncoderOptions
    35  	pngEncoder *png.Encoder
    36  }
    37  
    38  // NewEncoder creates and returns a new image encoder with the given options.
    39  func NewEncoder(opts EncoderOptions) (*Encoder, error) {
    40  	var e Encoder
    41  	if err := opts.validate(); err != nil {
    42  		return nil, fmt.Errorf("imaging: error validating encoder options: %w", err)
    43  	}
    44  	if opts.ConcurrencyLevel > 0 {
    45  		e.sem = make(chan struct{}, opts.ConcurrencyLevel)
    46  	}
    47  	e.opts = opts
    48  	e.pngEncoder = &png.Encoder{}
    49  	return &e, nil
    50  }
    51  
    52  // EncodeJPEG encodes the given image in JPEG format and writes the data to
    53  // the passed writer.
    54  func (e *Encoder) EncodeJPEG(wr io.Writer, img image.Image, quality int) error {
    55  	if e.opts.ConcurrencyLevel > 0 {
    56  		e.sem <- struct{}{}
    57  		defer func() {
    58  			<-e.sem
    59  		}()
    60  	}
    61  
    62  	var encOpts jpeg.Options
    63  	encOpts.Quality = quality
    64  	if err := jpeg.Encode(wr, img, &encOpts); err != nil {
    65  		return fmt.Errorf("imaging: failed to encode jpeg: %w", err)
    66  	}
    67  
    68  	return nil
    69  }
    70  
    71  // EncodePNG encodes the given image in PNG format and writes the data to
    72  // the passed writer.
    73  func (e *Encoder) EncodePNG(wr io.Writer, img image.Image) error {
    74  	if e.opts.ConcurrencyLevel > 0 {
    75  		e.sem <- struct{}{}
    76  		defer func() {
    77  			<-e.sem
    78  		}()
    79  	}
    80  
    81  	if err := e.pngEncoder.Encode(wr, img); err != nil {
    82  		return fmt.Errorf("imaging: failed to encode png: %w", err)
    83  	}
    84  
    85  	return nil
    86  }