github.com/anakojm/hugo-katex@v0.0.0-20231023141351-42d6f5de9c0b/tpl/images/images.go (about) 1 // Copyright 2019 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 provides template functions for manipulating images. 15 package images 16 17 import ( 18 "image" 19 "sync" 20 21 "errors" 22 23 "github.com/bep/overlayfs" 24 "github.com/gohugoio/hugo/resources/images" 25 26 // Importing image codecs for image.DecodeConfig 27 _ "image/gif" 28 _ "image/jpeg" 29 _ "image/png" 30 31 // Import webp codec 32 _ "golang.org/x/image/webp" 33 34 "github.com/gohugoio/hugo/deps" 35 "github.com/spf13/afero" 36 "github.com/spf13/cast" 37 ) 38 39 // New returns a new instance of the images-namespaced template functions. 40 func New(d *deps.Deps) *Namespace { 41 var readFileFs afero.Fs 42 43 // The docshelper script does not have or need all the dependencies set up. 44 if d.PathSpec != nil { 45 readFileFs = overlayfs.New(overlayfs.Options{ 46 Fss: []afero.Fs{ 47 d.PathSpec.BaseFs.Work, 48 d.PathSpec.BaseFs.Content.Fs, 49 }, 50 }) 51 } 52 53 return &Namespace{ 54 readFileFs: readFileFs, 55 Filters: &images.Filters{}, 56 cache: map[string]image.Config{}, 57 deps: d, 58 } 59 } 60 61 // Namespace provides template functions for the "images" namespace. 62 type Namespace struct { 63 *images.Filters 64 readFileFs afero.Fs 65 cacheMu sync.RWMutex 66 cache map[string]image.Config 67 68 deps *deps.Deps 69 } 70 71 // Config returns the image.Config for the specified path relative to the 72 // working directory. 73 func (ns *Namespace) Config(path any) (image.Config, error) { 74 filename, err := cast.ToStringE(path) 75 if err != nil { 76 return image.Config{}, err 77 } 78 79 if filename == "" { 80 return image.Config{}, errors.New("config needs a filename") 81 } 82 83 // Check cache for image config. 84 ns.cacheMu.RLock() 85 config, ok := ns.cache[filename] 86 ns.cacheMu.RUnlock() 87 88 if ok { 89 return config, nil 90 } 91 92 f, err := ns.readFileFs.Open(filename) 93 if err != nil { 94 return image.Config{}, err 95 } 96 defer f.Close() 97 98 config, _, err = image.DecodeConfig(f) 99 if err != nil { 100 return config, err 101 } 102 103 ns.cacheMu.Lock() 104 ns.cache[filename] = config 105 ns.cacheMu.Unlock() 106 107 return config, nil 108 } 109 110 // Filter applies the given filters to the image given as the last element in args. 111 func (ns *Namespace) Filter(args ...any) (images.ImageResource, error) { 112 if len(args) < 2 { 113 return nil, errors.New("must provide an image and one or more filters") 114 } 115 116 img := args[len(args)-1].(images.ImageResource) 117 filtersv := args[:len(args)-1] 118 119 return img.Filter(filtersv...) 120 }