DevGang
Авторизоваться

Работа с изображениями Go

Веб-приложениям часто требуется отображать аватар для пользователей, а пользователи не всегда стремятся загружать свои изображения. Популярный вариант - создавать аватары для ваших пользователей на основе инициалов их имен. В этом руководстве мы рассмотрим, как создавать такие аватары в Go и обслуживать их через HTTP с помощью маршрутизатора chi.

Настройка

Чтобы продолжить, вам потребуется достаточно свежая версия Go (версия 1.14 или выше).

Примечание. Команды оболочки, используемые ниже, предназначены для Linux / macOS, не стесняйтесь использовать эквивалент вашей операционной системы, если он отличается.

Сначала создайте папку для проекта и инициализируйте новый модуль Go:

$ mkdir go-avatars && cd go-avatars
$ go mod init gitlab.com/idoko/go-avatars

Затем добавьте необходимые зависимости, выполнив следующую команду в своем рабочем каталоге (т.е. go-avatars ):

$ go get golang.org/x/image github.com/golang/freetype github.com/go-chi/chi

Зависимости включают в себя image, который предоставляет методы для работы с изображениями в Go, freetype для работы со шрифтами (и записи на изображениях), а также маршрутизатор chi для обслуживания сгенерированных аватаров через HTTP.

Создайте холст изображения

Чтобы подготовить фон для наших аватарок, мы создаем файл main.go в рабочем каталоге и реализуем две функции - main и createAvatar. Откройте файл main.go и добавьте блок кода ниже:

package main
import (
    "fmt"
    "image"
    "image/color"
    "image/draw"
    "image/png"
    "log"
    "os"
    "time"
)
func main() {
    initials := "LR"
    size := 200
    avatar, err := createAvatar(size, initials)
    if err != nil {
        log.Fatal(err)
    }
    filename := fmt.Sprintf("out-%d.png", time.Now().Unix())
    file, err := os.Create(filename)
    if err != nil {
        log.Fatal(err)
    }
    png.Encode(file, avatar)
}
func createAvatar(size int, initials string) (*image.RGBA, error) {
    width, height := size, size
    bgColor, err := hexToRGBA("#764abc")
    if err != nil {
        log.Fatal(err)
    }
    background := image.NewRGBA(image.Rect(0, 0, width, height))
    draw.Draw(background, background.Bounds(), &image.Uniform{C: bgColor},
        image.Point{}, draw.Src)
    //drawText(background, initials)
    return background, err
}

Функция createAvatar создает квадратное полотно, ширину и высоту такие же, как параметр size, передаваемый в функцию. Он преобразует цветовой код HEX в его эквивалент RGBA, а затем RGBA равномерно окрашивается по холсту. Далее мы реализуем функцию преобразования hexToRGBA между цветами.

Преобразование HEX-кода в цвета RGBA

Добавьте реализацию функции hextorgb к файлу main.go:

func hexToRGBA(hex string) (color.RGBA, error) {
    var (
        rgba color.RGBA
        err  error
        errInvalidFormat = fmt.Errorf("invalid")
    )
    rgba.A = 0xff
    if hex[0] != '#' {
        return rgba, errInvalidFormat
    }
    hexToByte := func(b byte) byte {
        switch {
        case b >= '0' && b <= '9':
            return b - '0'
        case b >= 'a' && b <= 'f':
            return b - 'a' + 10
        case b >= 'A' && b <= 'F':
            return b - 'A' + 10
        }
        err = errInvalidFormat
        return 0
    }
    switch len(hex) {
    case 7:
        rgba.R = hexToByte(hex[1])<<4 + hexToByte(hex[2])
        rgba.G = hexToByte(hex[3])<<4 + hexToByte(hex[4])
        rgba.B = hexToByte(hex[5])<<4 + hexToByte(hex[6])
    case 4:
        rgba.R = hexToByte(hex[1]) * 17
        rgba.G = hexToByte(hex[2]) * 17
        rgba.B = hexToByte(hex[3]) * 17
    default:
        err = errInvalidFormat
    }
    return rgba, err
}

Реализация использует код из библиотеки gox и работает путем преобразования цветового кода HEX в байтовый ряд. Для шестнадцатеричных триплетов (т. е. шестизначных, трехбайтовых шестнадцатеричных чисел) первая цифра каждого байта умножается на 16 (сдвиг влево на 4 бита) и добавляется ко второй цифре того же байта, чтобы получить эквивалент RGB.

Если шестнадцатеричная строка состоит из трех цифр (скажем, #FFF), то нам нужно только умножить каждую из них на 17, чтобы получить эквивалент RGB.

Вы можете узнать больше о преобразованиях веб-цветов на этой странице в Википедии.

Запустите файл main.go с помощью go run ./main.go, чтобы сгенерировать однородно окрашенный файл, подобный приведенному ниже (названный out-xxxxxxxx.png) в каталоге проекта.

Нарисовать текст на фоне

Далее мы реализуем функцию drawText, отвечающую за запись инициалов на пустом холсте. Откройте файл main.go в своем редакторе и добавьте в него приведенный ниже код:

func drawText(canvas *image.RGBA, text string) error {
    var (
        fgColor  image.Image
        fontFace *truetype.Font
        err      error
        fontSize = 128.0
    )
    fgColor = image.White
    fontFace, err = freetype.ParseFont(goregular.TTF)
    fontDrawer := &font.Drawer{
        Dst: canvas,
        Src: fgColor,
        Face: truetype.NewFace(fontFace, &truetype.Options{
            Size:    fontSize,
            Hinting: font.HintingFull,
        }),
    }
    textBounds, _ := fontDrawer.BoundString(text)
    xPosition := (fixed.I(canvas.Rect.Max.X) - fontDrawer.MeasureString(text)) / 2
    textHeight := textBounds.Max.Y - textBounds.Min.Y
    yPosition := fixed.I((canvas.Rect.Max.Y)-textHeight.Ceil())/2 + fixed.I(textHeight.Ceil())
    fontDrawer.Dot = fixed.Point26_6{
        X: xPosition,
        Y: yPosition,
    }
    fontDrawer.DrawString(text)
    return err
}

Функция принимает указатель image.RGBA в качестве параметра, что гарантирует, что она изменяет то же изображение, переданное ей. Для рендеринга он использует шрифт goregular из стандартной библиотеки Go.

Рисование самого текста использует структуру font.Drawer, основная задача которой - писать на изображениях. Мы передаем холст аватара в качестве пункта назначения ящика (Dst) и полностью белое изображение в качестве исходного изображения (Src), которое отображает текст белым цветом.

Мы также вычисляем горизонтальную начальную точку (xPosition) для нашего текста, сначала измеряя длину текста, вычитая длину из общей ширины холста и деля результат на 2 (чтобы учесть левое и правое поля).

Аналогично, вертикальное положение (yPosition) вычисляется, сначала уменьшая вдвое разницу между высотой холста и высотой текста и снова добавляя высоту текста, чтобы текст встал на место.

Не забудьте раскомментировать строку drawText(background, initials)в функции createAvatar.

Кроме того, вам может потребоваться импортировать зависимости вручную, если ваш редактор не сделал этого за вас.

Запустите файл main.go с помощью go run ./main.go, и вы должны увидеть сгенерированное изображение в своем рабочем каталоге.

Рендеринг сгенерированных изображений с помощью маршрутизатора chi&nbsp;

Чтобы наши аватары были доступны в браузере, мы изменим нашу функцию main и заставим ее отображать сгенерированные изображения через HTTP. Замените существующую функцию main приведенным ниже кодом:

router := chi.NewRouter()
        router.Use(middleware.Logger)
        router.Get("/avatar", func(w http.ResponseWriter, r *http.Request) {
                initials := r.FormValue("initials")
                size, err := strconv.Atoi(r.FormValue("size"))
                if err != nil {
                        size = 200
                }
                avatar, err := createAvatar(size, initials)
                if err != nil {
                        log.Fatal(err)
                }
                w.Header().Set("Content-Type", "image/png")
                png.Encode(w, avatar)
        })
        http.ListenAndServe(":3000", router)

Приведенный выше фрагмент кода сначала настраивает маршрут /avatar с помощью chi для обработки HTTP-запросов. Затем функция извлекает инициалы и размер из параметров запроса и использует их для создания аватаров.

Поскольку png.Encode() принимает интерфейс io.Writer (который реализован http.ResponseWriter), наша новая функция main может напрямую обслуживать сгенерированное изображение для отображения браузером.

Запустите HTTP-сервер, запустив go run ./main.go в своем терминале, и посетите http: // localhost: 3000 / avatar? Initials = JD & size = 300 в своем терминале, чтобы увидеть результат.

Вывод

Я считаю, что динамические аватары более эстетичны, чем статические аватары по умолчанию, и в этой статье мы увидели способ реализовать их на Golang. Вы можете сделать еще один шаг, используя цвет фона, определяемый инициалами. Один из способов сделать это - создать фрагмент или массив шестнадцатеричных цветовых строк и выбрать цвет из фрагмента на основе хэша инициалов.

Источник:

#Golang
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

Поделитесь своим опытом, расскажите о новом инструменте, библиотеке или фреймворке. Для этого не обязательно становится постоянным автором.

Попробовать

Оплатив хостинг 25$ в подарок вы получите 100$ на счет

Получить