hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

text.go (2521B)

    1 // Copyright 2021 The Hugo Authors. All rights reserved.
    2 //
    3 // Licensed under the Apache License, Version 2.0 (the "License");
    4 // you may not use this file except in compliance with the License.
    5 // You may obtain a copy of the License at
    6 // http://www.apache.org/licenses/LICENSE-2.0
    7 //
    8 // Unless required by applicable law or agreed to in writing, software
    9 // distributed under the License is distributed on an "AS IS" BASIS,
   10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   11 // See the License for the specific language governing permissions and
   12 // limitations under the License.
   13 
   14 package images
   15 
   16 import (
   17 	"image"
   18 	"image/draw"
   19 	"io"
   20 	"strings"
   21 
   22 	"github.com/disintegration/gift"
   23 	"github.com/gohugoio/hugo/common/hugio"
   24 
   25 	"golang.org/x/image/font"
   26 	"golang.org/x/image/font/gofont/goregular"
   27 	"golang.org/x/image/font/opentype"
   28 	"golang.org/x/image/math/fixed"
   29 )
   30 
   31 var _ gift.Filter = (*textFilter)(nil)
   32 
   33 type textFilter struct {
   34 	text, color string
   35 	x, y        int
   36 	size        float64
   37 	linespacing int
   38 	fontSource  hugio.ReadSeekCloserProvider
   39 }
   40 
   41 func (f textFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) {
   42 	color, err := hexStringToColor(f.color)
   43 	if err != nil {
   44 		panic(err)
   45 	}
   46 
   47 	// Load and parse font
   48 	ttf := goregular.TTF
   49 	if f.fontSource != nil {
   50 		rs, err := f.fontSource.ReadSeekCloser()
   51 		if err != nil {
   52 			panic(err)
   53 		}
   54 		defer rs.Close()
   55 		ttf, err = io.ReadAll(rs)
   56 		if err != nil {
   57 			panic(err)
   58 		}
   59 	}
   60 	otf, err := opentype.Parse(ttf)
   61 	if err != nil {
   62 		panic(err)
   63 	}
   64 
   65 	// Set font options
   66 	face, err := opentype.NewFace(otf, &opentype.FaceOptions{
   67 		Size:    f.size,
   68 		DPI:     72,
   69 		Hinting: font.HintingNone,
   70 	})
   71 	if err != nil {
   72 		panic(err)
   73 	}
   74 
   75 	d := font.Drawer{
   76 		Dst:  dst,
   77 		Src:  image.NewUniform(color),
   78 		Face: face,
   79 	}
   80 
   81 	gift.New().Draw(dst, src)
   82 
   83 	// Draw text, consider and include linebreaks
   84 	maxWidth := dst.Bounds().Dx() - 20
   85 	fontHeight := face.Metrics().Ascent.Ceil()
   86 
   87 	// Correct y position based on font and size
   88 	f.y = f.y + fontHeight
   89 
   90 	// Start position
   91 	y := f.y
   92 	d.Dot = fixed.P(f.x, f.y)
   93 
   94 	// Draw text and break line at max width
   95 	parts := strings.Fields(f.text)
   96 	for _, str := range parts {
   97 		strWith := font.MeasureString(face, str)
   98 		if (d.Dot.X.Ceil() + strWith.Ceil()) >= maxWidth {
   99 			y = y + fontHeight + f.linespacing
  100 			d.Dot = fixed.P(f.x, y)
  101 		}
  102 		d.DrawString(str + " ")
  103 	}
  104 }
  105 
  106 func (f textFilter) Bounds(srcBounds image.Rectangle) image.Rectangle {
  107 	return image.Rect(0, 0, srcBounds.Dx(), srcBounds.Dy())
  108 }