github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/pkg/avatar/initials_convert.go (about)

     1  package avatar
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"os"
     7  	"os/exec"
     8  
     9  	"github.com/cozy/cozy-stack/pkg/logger"
    10  )
    11  
    12  // PNGInitials create PNG avatars with initials in it.
    13  //
    14  // This implementation is based on the `convert` binary.
    15  type PNGInitials struct {
    16  	cmd string
    17  }
    18  
    19  // NewPNGInitials instantiate a new [PNGInitials].
    20  func NewPNGInitials(cmd string) *PNGInitials {
    21  	if cmd == "" {
    22  		cmd = "convert"
    23  	}
    24  	return &PNGInitials{cmd}
    25  }
    26  
    27  // ContentType return the generated avatar content-type.
    28  func (a *PNGInitials) ContentType() string {
    29  	return "image/png"
    30  }
    31  
    32  // Generate will create a new avatar with the given initials and color.
    33  func (a *PNGInitials) Generate(initials, color string) ([]byte, error) {
    34  	tempDir, err := os.MkdirTemp("", "magick")
    35  	if err != nil {
    36  		return nil, fmt.Errorf("failed to create the tempdir: %w", err)
    37  	}
    38  	defer os.RemoveAll(tempDir)
    39  	envTempDir := fmt.Sprintf("MAGICK_TEMPORARY_PATH=%s", tempDir)
    40  	env := []string{envTempDir}
    41  
    42  	// convert -size 128x128 null: -fill blue -draw 'circle 64,64 0,64' -fill white -font Lato-Regular
    43  	// -pointsize 64 -gravity center -annotate "+0,+0" "AM" foo.png
    44  	args := []string{
    45  		"-limit", "Memory", "1GB",
    46  		"-limit", "Map", "1GB",
    47  		// Use a transparent background
    48  		"-size", "128x128",
    49  		"null:",
    50  		// Add a cicle of color
    51  		"-fill", color,
    52  		"-draw", "circle 64,64 0,64",
    53  		// Add the initials
    54  		"-fill", "white",
    55  		"-font", "Lato-Regular",
    56  		"-pointsize", "64",
    57  		"-gravity", "center",
    58  		"-annotate", "+0,+0",
    59  		initials,
    60  		// Use the colorspace recommended for web, sRGB
    61  		"-colorspace", "sRGB",
    62  		// Send the output on stdout, in PNG format
    63  		"png:-",
    64  	}
    65  
    66  	var stdout, stderr bytes.Buffer
    67  	cmd := exec.Command(a.cmd, args...)
    68  	cmd.Env = env
    69  	cmd.Stdout = &stdout
    70  	cmd.Stderr = &stderr
    71  	if err := cmd.Run(); err != nil {
    72  		logger.WithNamespace("initials").
    73  			WithField("stderr", stderr.String()).
    74  			WithField("initials", initials).
    75  			WithField("color", color).
    76  			Errorf("imagemagick failed: %s", err)
    77  		return nil, fmt.Errorf("failed to run the cmd %q: %w", a.cmd, err)
    78  	}
    79  	return stdout.Bytes(), nil
    80  }