mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-07 20:30:36 -05:00
Some godoc adjustments and image struct renames
This commit is contained in:
parent
11047534e4
commit
fa80fe3c8a
23 changed files with 193 additions and 90 deletions
|
@ -27,7 +27,7 @@ var (
|
||||||
// here as it makes it easier to get an idea of "type coverage". These
|
// here as it makes it easier to get an idea of "type coverage". These
|
||||||
// implementations have no value on their own.
|
// implementations have no value on their own.
|
||||||
|
|
||||||
// Slice is not meant to be used externally. It's a bridge function
|
// Slice is for internal use.
|
||||||
func (p *pageState) Slice(items any) (any, error) {
|
func (p *pageState) Slice(items any) (any, error) {
|
||||||
return page.ToPages(items)
|
return page.ToPages(items)
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,21 +55,26 @@ type Language struct {
|
||||||
Title string
|
Title string
|
||||||
Weight int
|
Weight int
|
||||||
|
|
||||||
|
// For internal use.
|
||||||
Disabled bool
|
Disabled bool
|
||||||
|
|
||||||
// If set per language, this tells Hugo that all content files without any
|
// If set per language, this tells Hugo that all content files without any
|
||||||
// language indicator (e.g. my-page.en.md) is in this language.
|
// language indicator (e.g. my-page.en.md) is in this language.
|
||||||
// This is usually a path relative to the working dir, but it can be an
|
// This is usually a path relative to the working dir, but it can be an
|
||||||
// absolute directory reference. It is what we get.
|
// absolute directory reference. It is what we get.
|
||||||
|
// For internal use.
|
||||||
ContentDir string
|
ContentDir string
|
||||||
|
|
||||||
// Global config.
|
// Global config.
|
||||||
|
// For internal use.
|
||||||
Cfg config.Provider
|
Cfg config.Provider
|
||||||
|
|
||||||
// Language specific config.
|
// Language specific config.
|
||||||
|
// For internal use.
|
||||||
LocalCfg config.Provider
|
LocalCfg config.Provider
|
||||||
|
|
||||||
// Composite config.
|
// Composite config.
|
||||||
|
// For internal use.
|
||||||
config.Provider
|
config.Provider
|
||||||
|
|
||||||
// These are params declared in the [params] section of the language merged with the
|
// These are params declared in the [params] section of the language merged with the
|
||||||
|
@ -91,6 +96,7 @@ type Language struct {
|
||||||
initErr error
|
initErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For internal use.
|
||||||
func (l *Language) String() string {
|
func (l *Language) String() string {
|
||||||
return l.Lang
|
return l.Lang
|
||||||
}
|
}
|
||||||
|
@ -233,6 +239,7 @@ func (l Languages) IsMultihost() bool {
|
||||||
|
|
||||||
// SetParam sets a param with the given key and value.
|
// SetParam sets a param with the given key and value.
|
||||||
// SetParam is case-insensitive.
|
// SetParam is case-insensitive.
|
||||||
|
// For internal use.
|
||||||
func (l *Language) SetParam(k string, v any) {
|
func (l *Language) SetParam(k string, v any) {
|
||||||
l.paramsMu.Lock()
|
l.paramsMu.Lock()
|
||||||
defer l.paramsMu.Unlock()
|
defer l.paramsMu.Unlock()
|
||||||
|
@ -245,6 +252,7 @@ func (l *Language) SetParam(k string, v any) {
|
||||||
// GetLocal gets a configuration value set on language level. It will
|
// GetLocal gets a configuration value set on language level. It will
|
||||||
// not fall back to any global value.
|
// not fall back to any global value.
|
||||||
// It will return nil if a value with the given key cannot be found.
|
// It will return nil if a value with the given key cannot be found.
|
||||||
|
// For internal use.
|
||||||
func (l *Language) GetLocal(key string) any {
|
func (l *Language) GetLocal(key string) any {
|
||||||
if l == nil {
|
if l == nil {
|
||||||
panic("language not set")
|
panic("language not set")
|
||||||
|
@ -256,6 +264,7 @@ func (l *Language) GetLocal(key string) any {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For internal use.
|
||||||
func (l *Language) Set(k string, v any) {
|
func (l *Language) Set(k string, v any) {
|
||||||
k = strings.ToLower(k)
|
k = strings.ToLower(k)
|
||||||
if globalOnlySettings[k] {
|
if globalOnlySettings[k] {
|
||||||
|
@ -265,11 +274,13 @@ func (l *Language) Set(k string, v any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge is currently not supported for Language.
|
// Merge is currently not supported for Language.
|
||||||
|
// For internal use.
|
||||||
func (l *Language) Merge(key string, value any) {
|
func (l *Language) Merge(key string, value any) {
|
||||||
panic("Not supported")
|
panic("Not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSet checks whether the key is set in the language or the related config store.
|
// IsSet checks whether the key is set in the language or the related config store.
|
||||||
|
// For internal use.
|
||||||
func (l *Language) IsSet(key string) bool {
|
func (l *Language) IsSet(key string) bool {
|
||||||
key = strings.ToLower(key)
|
key = strings.ToLower(key)
|
||||||
if !globalOnlySettings[key] {
|
if !globalOnlySettings[key] {
|
||||||
|
|
|
@ -163,6 +163,7 @@ func (m Type) Type() string {
|
||||||
return m.MainType + "/" + m.SubType
|
return m.MainType + "/" + m.SubType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For internal use.
|
||||||
func (m Type) String() string {
|
func (m Type) String() string {
|
||||||
return m.Type()
|
return m.Type()
|
||||||
}
|
}
|
||||||
|
@ -510,11 +511,13 @@ func DecodeTypes(mms ...map[string]any) (Types, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsZero reports whether this Type represents a zero value.
|
// IsZero reports whether this Type represents a zero value.
|
||||||
|
// For internal use.
|
||||||
func (m Type) IsZero() bool {
|
func (m Type) IsZero() bool {
|
||||||
return m.SubType == ""
|
return m.SubType == ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON returns the JSON encoding of m.
|
// MarshalJSON returns the JSON encoding of m.
|
||||||
|
// For internal use.
|
||||||
func (m Type) MarshalJSON() ([]byte, error) {
|
func (m Type) MarshalJSON() ([]byte, error) {
|
||||||
type Alias Type
|
type Alias Type
|
||||||
return json.Marshal(&struct {
|
return json.Marshal(&struct {
|
||||||
|
|
|
@ -156,6 +156,7 @@ func (m *MenuEntry) isSamePage(p Page) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For internal use.
|
||||||
func (m *MenuEntry) MarshallMap(ime map[string]any) error {
|
func (m *MenuEntry) MarshallMap(ime map[string]any) error {
|
||||||
var err error
|
var err error
|
||||||
for k, v := range ime {
|
for k, v := range ime {
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"github.com/gohugoio/hugo/common/hugio"
|
"github.com/gohugoio/hugo/common/hugio"
|
||||||
"github.com/gohugoio/hugo/common/maps"
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
"github.com/gohugoio/hugo/media"
|
"github.com/gohugoio/hugo/media"
|
||||||
|
"github.com/gohugoio/hugo/resources/images"
|
||||||
"github.com/gohugoio/hugo/resources/images/exif"
|
"github.com/gohugoio/hugo/resources/images/exif"
|
||||||
"github.com/gohugoio/hugo/resources/resource"
|
"github.com/gohugoio/hugo/resources/resource"
|
||||||
)
|
)
|
||||||
|
@ -26,7 +27,7 @@ import (
|
||||||
var (
|
var (
|
||||||
_ error = (*errorResource)(nil)
|
_ error = (*errorResource)(nil)
|
||||||
// Imnage covers all current Resource implementations.
|
// Imnage covers all current Resource implementations.
|
||||||
_ resource.Image = (*errorResource)(nil)
|
_ images.ImageResource = (*errorResource)(nil)
|
||||||
// The list of user facing and exported interfaces in resource.go
|
// The list of user facing and exported interfaces in resource.go
|
||||||
// Note that if we're missing some interface here, the user will still
|
// Note that if we're missing some interface here, the user will still
|
||||||
// get an error, but not as pretty.
|
// get an error, but not as pretty.
|
||||||
|
@ -98,27 +99,27 @@ func (e *errorResource) Width() int {
|
||||||
panic(e.ResourceError)
|
panic(e.ResourceError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *errorResource) Crop(spec string) (resource.Image, error) {
|
func (e *errorResource) Crop(spec string) (images.ImageResource, error) {
|
||||||
panic(e.ResourceError)
|
panic(e.ResourceError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *errorResource) Fill(spec string) (resource.Image, error) {
|
func (e *errorResource) Fill(spec string) (images.ImageResource, error) {
|
||||||
panic(e.ResourceError)
|
panic(e.ResourceError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *errorResource) Fit(spec string) (resource.Image, error) {
|
func (e *errorResource) Fit(spec string) (images.ImageResource, error) {
|
||||||
panic(e.ResourceError)
|
panic(e.ResourceError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *errorResource) Resize(spec string) (resource.Image, error) {
|
func (e *errorResource) Resize(spec string) (images.ImageResource, error) {
|
||||||
panic(e.ResourceError)
|
panic(e.ResourceError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *errorResource) Filter(filters ...any) (resource.Image, error) {
|
func (e *errorResource) Filter(filters ...any) (images.ImageResource, error) {
|
||||||
panic(e.ResourceError)
|
panic(e.ResourceError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *errorResource) Exif() *exif.Exif {
|
func (e *errorResource) Exif() *exif.ExifInfo {
|
||||||
panic(e.ResourceError)
|
panic(e.ResourceError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,12 +49,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ resource.Image = (*imageResource)(nil)
|
_ images.ImageResource = (*imageResource)(nil)
|
||||||
_ resource.Source = (*imageResource)(nil)
|
_ resource.Source = (*imageResource)(nil)
|
||||||
_ resource.Cloner = (*imageResource)(nil)
|
_ resource.Cloner = (*imageResource)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// ImageResource represents an image resource.
|
// imageResource represents an image resource.
|
||||||
type imageResource struct {
|
type imageResource struct {
|
||||||
*images.Image
|
*images.Image
|
||||||
|
|
||||||
|
@ -70,14 +70,14 @@ type imageResource struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type imageMeta struct {
|
type imageMeta struct {
|
||||||
Exif *exif.Exif
|
Exif *exif.ExifInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *imageResource) Exif() *exif.Exif {
|
func (i *imageResource) Exif() *exif.ExifInfo {
|
||||||
return i.root.getExif()
|
return i.root.getExif()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *imageResource) getExif() *exif.Exif {
|
func (i *imageResource) getExif() *exif.ExifInfo {
|
||||||
i.metaInit.Do(func() {
|
i.metaInit.Do(func() {
|
||||||
supportsExif := i.Format == images.JPEG || i.Format == images.TIFF
|
supportsExif := i.Format == images.JPEG || i.Format == images.TIFF
|
||||||
if !supportsExif {
|
if !supportsExif {
|
||||||
|
@ -137,6 +137,7 @@ func (i *imageResource) getExif() *exif.Exif {
|
||||||
return i.meta.Exif
|
return i.meta.Exif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cloneis for internal use.
|
||||||
func (i *imageResource) Clone() resource.Resource {
|
func (i *imageResource) Clone() resource.Resource {
|
||||||
gr := i.baseResource.Clone().(baseResource)
|
gr := i.baseResource.Clone().(baseResource)
|
||||||
return &imageResource{
|
return &imageResource{
|
||||||
|
@ -170,7 +171,7 @@ func (i *imageResource) cloneWithUpdates(u *transformationUpdate) (baseResource,
|
||||||
// Resize resizes the image to the specified width and height using the specified resampling
|
// Resize resizes the image to the specified width and height using the specified resampling
|
||||||
// filter and returns the transformed image. If one of width or height is 0, the image aspect
|
// filter and returns the transformed image. If one of width or height is 0, the image aspect
|
||||||
// ratio is preserved.
|
// ratio is preserved.
|
||||||
func (i *imageResource) Resize(spec string) (resource.Image, error) {
|
func (i *imageResource) Resize(spec string) (images.ImageResource, error) {
|
||||||
conf, err := i.decodeImageConfig("resize", spec)
|
conf, err := i.decodeImageConfig("resize", spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -182,8 +183,8 @@ func (i *imageResource) Resize(spec string) (resource.Image, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crop the image to the specified dimensions without resizing using the given anchor point.
|
// Crop the image to the specified dimensions without resizing using the given anchor point.
|
||||||
// Space delimited config: 200x300 TopLeft
|
// Space delimited config, e.g. `200x300 TopLeft`.
|
||||||
func (i *imageResource) Crop(spec string) (resource.Image, error) {
|
func (i *imageResource) Crop(spec string) (images.ImageResource, error) {
|
||||||
conf, err := i.decodeImageConfig("crop", spec)
|
conf, err := i.decodeImageConfig("crop", spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -196,7 +197,7 @@ func (i *imageResource) Crop(spec string) (resource.Image, error) {
|
||||||
|
|
||||||
// Fit scales down the image using the specified resample filter to fit the specified
|
// Fit scales down the image using the specified resample filter to fit the specified
|
||||||
// maximum width and height.
|
// maximum width and height.
|
||||||
func (i *imageResource) Fit(spec string) (resource.Image, error) {
|
func (i *imageResource) Fit(spec string) (images.ImageResource, error) {
|
||||||
conf, err := i.decodeImageConfig("fit", spec)
|
conf, err := i.decodeImageConfig("fit", spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -209,8 +210,8 @@ func (i *imageResource) Fit(spec string) (resource.Image, error) {
|
||||||
|
|
||||||
// Fill scales the image to the smallest possible size that will cover the specified dimensions,
|
// Fill scales the image to the smallest possible size that will cover the specified dimensions,
|
||||||
// crops the resized image to the specified dimensions using the given anchor point.
|
// crops the resized image to the specified dimensions using the given anchor point.
|
||||||
// Space delimited config: 200x300 TopLeft
|
// Space delimited config, e.g. `200x300 TopLeft`.
|
||||||
func (i *imageResource) Fill(spec string) (resource.Image, error) {
|
func (i *imageResource) Fill(spec string) (images.ImageResource, error) {
|
||||||
conf, err := i.decodeImageConfig("fill", spec)
|
conf, err := i.decodeImageConfig("fill", spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -238,7 +239,7 @@ func (i *imageResource) Fill(spec string) (resource.Image, error) {
|
||||||
return img, err
|
return img, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *imageResource) Filter(filters ...any) (resource.Image, error) {
|
func (i *imageResource) Filter(filters ...any) (images.ImageResource, error) {
|
||||||
conf := images.GetDefaultImageConfig("filter", i.Proc.Cfg)
|
conf := images.GetDefaultImageConfig("filter", i.Proc.Cfg)
|
||||||
|
|
||||||
var gfilters []gift.Filter
|
var gfilters []gift.Filter
|
||||||
|
@ -264,7 +265,7 @@ const imageProcWorkers = 1
|
||||||
|
|
||||||
var imageProcSem = make(chan bool, imageProcWorkers)
|
var imageProcSem = make(chan bool, imageProcWorkers)
|
||||||
|
|
||||||
func (i *imageResource) doWithImageConfig(conf images.ImageConfig, f func(src image.Image) (image.Image, error)) (resource.Image, error) {
|
func (i *imageResource) doWithImageConfig(conf images.ImageConfig, f func(src image.Image) (image.Image, error)) (images.ImageResource, error) {
|
||||||
img, err := i.getSpec().imageCache.getOrCreate(i, conf, func() (*imageResource, image.Image, error) {
|
img, err := i.getSpec().imageCache.getOrCreate(i, conf, func() (*imageResource, image.Image, error) {
|
||||||
imageProcSem <- true
|
imageProcSem <- true
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|
|
@ -40,7 +40,6 @@ import (
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/media"
|
"github.com/gohugoio/hugo/media"
|
||||||
"github.com/gohugoio/hugo/resources/images"
|
"github.com/gohugoio/hugo/resources/images"
|
||||||
"github.com/gohugoio/hugo/resources/resource"
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/htesting/hqt"
|
"github.com/gohugoio/hugo/htesting/hqt"
|
||||||
|
@ -76,7 +75,7 @@ func TestImageTransformBasic(t *testing.T) {
|
||||||
|
|
||||||
fileCache := image.(specProvider).getSpec().FileCaches.ImageCache().Fs
|
fileCache := image.(specProvider).getSpec().FileCaches.ImageCache().Fs
|
||||||
|
|
||||||
assertWidthHeight := func(img resource.Image, w, h int) {
|
assertWidthHeight := func(img images.ImageResource, w, h int) {
|
||||||
c.Helper()
|
c.Helper()
|
||||||
c.Assert(img, qt.Not(qt.IsNil))
|
c.Assert(img, qt.Not(qt.IsNil))
|
||||||
c.Assert(img.Width(), qt.Equals, w)
|
c.Assert(img.Width(), qt.Equals, w)
|
||||||
|
@ -162,7 +161,7 @@ func TestImageTransformFormat(t *testing.T) {
|
||||||
|
|
||||||
fileCache := image.(specProvider).getSpec().FileCaches.ImageCache().Fs
|
fileCache := image.(specProvider).getSpec().FileCaches.ImageCache().Fs
|
||||||
|
|
||||||
assertExtWidthHeight := func(img resource.Image, ext string, w, h int) {
|
assertExtWidthHeight := func(img images.ImageResource, ext string, w, h int) {
|
||||||
c.Helper()
|
c.Helper()
|
||||||
c.Assert(img, qt.Not(qt.IsNil))
|
c.Assert(img, qt.Not(qt.IsNil))
|
||||||
c.Assert(paths.Ext(img.RelPermalink()), qt.Equals, ext)
|
c.Assert(paths.Ext(img.RelPermalink()), qt.Equals, ext)
|
||||||
|
@ -210,13 +209,13 @@ func TestImagePermalinkPublishOrder(t *testing.T) {
|
||||||
os.Remove(workDir)
|
os.Remove(workDir)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
check1 := func(img resource.Image) {
|
check1 := func(img images.ImageResource) {
|
||||||
resizedLink := "/a/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_100x50_resize_q75_box.jpg"
|
resizedLink := "/a/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_100x50_resize_q75_box.jpg"
|
||||||
c.Assert(img.RelPermalink(), qt.Equals, resizedLink)
|
c.Assert(img.RelPermalink(), qt.Equals, resizedLink)
|
||||||
assertImageFile(c, spec.PublishFs, resizedLink, 100, 50)
|
assertImageFile(c, spec.PublishFs, resizedLink, 100, 50)
|
||||||
}
|
}
|
||||||
|
|
||||||
check2 := func(img resource.Image) {
|
check2 := func(img images.ImageResource) {
|
||||||
c.Assert(img.RelPermalink(), qt.Equals, "/a/sunset.jpg")
|
c.Assert(img.RelPermalink(), qt.Equals, "/a/sunset.jpg")
|
||||||
assertImageFile(c, spec.PublishFs, "a/sunset.jpg", 900, 562)
|
assertImageFile(c, spec.PublishFs, "a/sunset.jpg", 900, 562)
|
||||||
}
|
}
|
||||||
|
@ -231,7 +230,7 @@ func TestImagePermalinkPublishOrder(t *testing.T) {
|
||||||
resized, err := orignal.Resize("100x50")
|
resized, err := orignal.Resize("100x50")
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
check1(resized.(resource.Image))
|
check1(resized.(images.ImageResource))
|
||||||
|
|
||||||
if !checkOriginalFirst {
|
if !checkOriginalFirst {
|
||||||
check2(orignal)
|
check2(orignal)
|
||||||
|
@ -441,9 +440,9 @@ func TestImageExif(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
fs := afero.NewMemMapFs()
|
fs := afero.NewMemMapFs()
|
||||||
spec := newTestResourceSpec(specDescriptor{fs: fs, c: c})
|
spec := newTestResourceSpec(specDescriptor{fs: fs, c: c})
|
||||||
image := fetchResourceForSpec(spec, c, "sunset.jpg").(resource.Image)
|
image := fetchResourceForSpec(spec, c, "sunset.jpg").(images.ImageResource)
|
||||||
|
|
||||||
getAndCheckExif := func(c *qt.C, image resource.Image) {
|
getAndCheckExif := func(c *qt.C, image images.ImageResource) {
|
||||||
x := image.Exif()
|
x := image.Exif()
|
||||||
c.Assert(x, qt.Not(qt.IsNil))
|
c.Assert(x, qt.Not(qt.IsNil))
|
||||||
|
|
||||||
|
@ -464,22 +463,22 @@ func TestImageExif(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
getAndCheckExif(c, image)
|
getAndCheckExif(c, image)
|
||||||
image = fetchResourceForSpec(spec, c, "sunset.jpg").(resource.Image)
|
image = fetchResourceForSpec(spec, c, "sunset.jpg").(images.ImageResource)
|
||||||
// This will read from file cache.
|
// This will read from file cache.
|
||||||
getAndCheckExif(c, image)
|
getAndCheckExif(c, image)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkImageExif(b *testing.B) {
|
func BenchmarkImageExif(b *testing.B) {
|
||||||
getImages := func(c *qt.C, b *testing.B, fs afero.Fs) []resource.Image {
|
getImages := func(c *qt.C, b *testing.B, fs afero.Fs) []images.ImageResource {
|
||||||
spec := newTestResourceSpec(specDescriptor{fs: fs, c: c})
|
spec := newTestResourceSpec(specDescriptor{fs: fs, c: c})
|
||||||
images := make([]resource.Image, b.N)
|
imgs := make([]images.ImageResource, b.N)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
images[i] = fetchResourceForSpec(spec, c, "sunset.jpg", strconv.Itoa(i)).(resource.Image)
|
imgs[i] = fetchResourceForSpec(spec, c, "sunset.jpg", strconv.Itoa(i)).(images.ImageResource)
|
||||||
}
|
}
|
||||||
return images
|
return imgs
|
||||||
}
|
}
|
||||||
|
|
||||||
getAndCheckExif := func(c *qt.C, image resource.Image) {
|
getAndCheckExif := func(c *qt.C, image images.ImageResource) {
|
||||||
x := image.Exif()
|
x := image.Exif()
|
||||||
c.Assert(x, qt.Not(qt.IsNil))
|
c.Assert(x, qt.Not(qt.IsNil))
|
||||||
c.Assert(x.Long, qt.Equals, float64(-4.50846))
|
c.Assert(x.Long, qt.Equals, float64(-4.50846))
|
||||||
|
|
|
@ -32,10 +32,18 @@ import (
|
||||||
|
|
||||||
const exifTimeLayout = "2006:01:02 15:04:05"
|
const exifTimeLayout = "2006:01:02 15:04:05"
|
||||||
|
|
||||||
type Exif struct {
|
// ExifInfo holds the decoded Exif data for an Image.
|
||||||
|
type ExifInfo struct {
|
||||||
|
// GPS latitude in degrees.
|
||||||
Lat float64
|
Lat float64
|
||||||
|
|
||||||
|
// GPS longitude in degrees.
|
||||||
Long float64
|
Long float64
|
||||||
|
|
||||||
|
// Image creation date/time.
|
||||||
Date time.Time
|
Date time.Time
|
||||||
|
|
||||||
|
// A collection of the available Exif tags for this Image.
|
||||||
Tags Tags
|
Tags Tags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +114,7 @@ func NewDecoder(options ...func(*Decoder) error) (*Decoder, error) {
|
||||||
return d, nil
|
return d, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Decoder) Decode(r io.Reader) (ex *Exif, err error) {
|
func (d *Decoder) Decode(r io.Reader) (ex *ExifInfo, err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
err = fmt.Errorf("Exif failed: %v", r)
|
err = fmt.Errorf("Exif failed: %v", r)
|
||||||
|
@ -139,7 +147,7 @@ func (d *Decoder) Decode(r io.Reader) (ex *Exif, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ex = &Exif{Lat: lat, Long: long, Date: tm, Tags: walker.vals}
|
ex = &ExifInfo{Lat: lat, Long: long, Date: tm, Tags: walker.vals}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ func TestExif(t *testing.T) {
|
||||||
// Verify that it survives a round-trip to JSON and back.
|
// Verify that it survives a round-trip to JSON and back.
|
||||||
data, err := json.Marshal(x)
|
data, err := json.Marshal(x)
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
x2 := &Exif{}
|
x2 := &ExifInfo{}
|
||||||
err = json.Unmarshal(data, x2)
|
err = json.Unmarshal(data, x2)
|
||||||
|
|
||||||
c.Assert(x2, eq, x)
|
c.Assert(x2, eq, x)
|
||||||
|
|
|
@ -192,7 +192,7 @@ type ImageProcessor struct {
|
||||||
exifDecoder *exif.Decoder
|
exifDecoder *exif.Decoder
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ImageProcessor) DecodeExif(r io.Reader) (*exif.Exif, error) {
|
func (p *ImageProcessor) DecodeExif(r io.Reader) (*exif.ExifInfo, error) {
|
||||||
return p.exifDecoder.Decode(r)
|
return p.exifDecoder.Decode(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
53
resources/images/image_resource.go
Normal file
53
resources/images/image_resource.go
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright 2022 The Hugo Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package images
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/resources/images/exif"
|
||||||
|
"github.com/gohugoio/hugo/resources/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImageResource represents an image resource.
|
||||||
|
type ImageResource interface {
|
||||||
|
resource.Resource
|
||||||
|
ImageResourceOps
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImageResourceOps interface {
|
||||||
|
// Height returns the height of the Image.
|
||||||
|
Height() int
|
||||||
|
// Width returns the width of the Image.
|
||||||
|
Width() int
|
||||||
|
|
||||||
|
// Crop an image to match the given dimensions without resizing.
|
||||||
|
// You must provide both width and height.
|
||||||
|
// Use the anchor option to change the crop box anchor point.
|
||||||
|
// {{ $image := $image.Crop "600x400" }}
|
||||||
|
Crop(spec string) (ImageResource, error)
|
||||||
|
Fill(spec string) (ImageResource, error)
|
||||||
|
Fit(spec string) (ImageResource, error)
|
||||||
|
Resize(spec string) (ImageResource, error)
|
||||||
|
|
||||||
|
// Filter applies one or more filters to an Image.
|
||||||
|
// {{ $image := $image.Filter (images.GaussianBlur 6) (images.Pixelate 8) }}
|
||||||
|
Filter(filters ...any) (ImageResource, error)
|
||||||
|
|
||||||
|
// Exif returns an ExifInfo object containing Image metadata.
|
||||||
|
Exif() *exif.ExifInfo
|
||||||
|
|
||||||
|
// Internal
|
||||||
|
DecodeImage() (image.Image, error)
|
||||||
|
}
|
|
@ -161,8 +161,7 @@ type PageMetaProvider interface {
|
||||||
// Aliases forms the base for redirects generation.
|
// Aliases forms the base for redirects generation.
|
||||||
Aliases() []string
|
Aliases() []string
|
||||||
|
|
||||||
// BundleType returns the bundle type: "leaf", "branch" or an empty string if it is none.
|
// BundleType returns the bundle type: `leaf`, `branch` or an empty string.
|
||||||
// See https://gohugo.io/content-management/page-bundles/
|
|
||||||
BundleType() files.ContentClass
|
BundleType() files.ContentClass
|
||||||
|
|
||||||
// A configured description.
|
// A configured description.
|
||||||
|
|
|
@ -40,7 +40,10 @@ var (
|
||||||
// PageGroup represents a group of pages, grouped by the key.
|
// PageGroup represents a group of pages, grouped by the key.
|
||||||
// The key is typically a year or similar.
|
// The key is typically a year or similar.
|
||||||
type PageGroup struct {
|
type PageGroup struct {
|
||||||
|
// The key, typically a year or similar.
|
||||||
Key any
|
Key any
|
||||||
|
|
||||||
|
// The Pages in this group.
|
||||||
Pages
|
Pages
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,6 +364,7 @@ func (p Pages) GroupByParamDate(key string, format string, order ...string) (Pag
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProbablyEq wraps compare.ProbablyEqer
|
// ProbablyEq wraps compare.ProbablyEqer
|
||||||
|
// For internal use.
|
||||||
func (p PageGroup) ProbablyEq(other any) bool {
|
func (p PageGroup) ProbablyEq(other any) bool {
|
||||||
otherP, ok := other.(PageGroup)
|
otherP, ok := other.(PageGroup)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -374,7 +378,7 @@ func (p PageGroup) ProbablyEq(other any) bool {
|
||||||
return p.Pages.ProbablyEq(otherP.Pages)
|
return p.Pages.ProbablyEq(otherP.Pages)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slice is not meant to be used externally. It's a bridge function
|
// Slice is for internal use.
|
||||||
// for the template functions. See collections.Slice.
|
// for the template functions. See collections.Slice.
|
||||||
func (p PageGroup) Slice(in any) (any, error) {
|
func (p PageGroup) Slice(in any) (any, error) {
|
||||||
switch items := in.(type) {
|
switch items := in.(type) {
|
||||||
|
|
|
@ -22,9 +22,11 @@ import (
|
||||||
"github.com/gohugoio/hugo/resources/resource"
|
"github.com/gohugoio/hugo/resources/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pages is a slice of pages. This is the most common list type in Hugo.
|
// Pages is a slice of Page objects. This is the most common list type in Hugo.
|
||||||
type Pages []Page
|
type Pages []Page
|
||||||
|
|
||||||
|
// String returns a string representation of the list.
|
||||||
|
// For internal use.
|
||||||
func (ps Pages) String() string {
|
func (ps Pages) String() string {
|
||||||
return fmt.Sprintf("Pages(%d)", len(ps))
|
return fmt.Sprintf("Pages(%d)", len(ps))
|
||||||
}
|
}
|
||||||
|
@ -37,7 +39,8 @@ func (ps Pages) shuffle() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToResources wraps resource.ResourcesConverter
|
// ToResources wraps resource.ResourcesConverter.
|
||||||
|
// For internal use.
|
||||||
func (pages Pages) ToResources() resource.Resources {
|
func (pages Pages) ToResources() resource.Resources {
|
||||||
r := make(resource.Resources, len(pages))
|
r := make(resource.Resources, len(pages))
|
||||||
for i, p := range pages {
|
for i, p := range pages {
|
||||||
|
@ -86,10 +89,12 @@ func ToPages(seq any) (Pages, error) {
|
||||||
return nil, fmt.Errorf("cannot convert type %T to Pages", seq)
|
return nil, fmt.Errorf("cannot convert type %T to Pages", seq)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Group groups the pages in in by key.
|
||||||
|
// This implements collections.Grouper.
|
||||||
func (p Pages) Group(key any, in any) (any, error) {
|
func (p Pages) Group(key any, in any) (any, error) {
|
||||||
pages, err := ToPages(in)
|
pages, err := ToPages(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return PageGroup{}, err
|
||||||
}
|
}
|
||||||
return PageGroup{Key: key, Pages: pages}, nil
|
return PageGroup{Key: key, Pages: pages}, nil
|
||||||
}
|
}
|
||||||
|
@ -100,6 +105,7 @@ func (p Pages) Len() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProbablyEq wraps compare.ProbablyEqer
|
// ProbablyEq wraps compare.ProbablyEqer
|
||||||
|
// For internal use.
|
||||||
func (pages Pages) ProbablyEq(other any) bool {
|
func (pages Pages) ProbablyEq(other any) bool {
|
||||||
otherPages, ok := other.(Pages)
|
otherPages, ok := other.(Pages)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
@ -29,21 +29,52 @@ import (
|
||||||
// Site represents a site in the build. This is currently a very narrow interface,
|
// Site represents a site in the build. This is currently a very narrow interface,
|
||||||
// but the actual implementation will be richer, see hugolib.SiteInfo.
|
// but the actual implementation will be richer, see hugolib.SiteInfo.
|
||||||
type Site interface {
|
type Site interface {
|
||||||
|
// Returns the Language configured for this Site.
|
||||||
Language() *langs.Language
|
Language() *langs.Language
|
||||||
|
|
||||||
|
// Returns all the regular Pages in this Site.
|
||||||
RegularPages() Pages
|
RegularPages() Pages
|
||||||
|
|
||||||
|
// Returns all Pages in this Site.
|
||||||
Pages() Pages
|
Pages() Pages
|
||||||
|
|
||||||
|
// A shortcut to the home page.
|
||||||
Home() Page
|
Home() Page
|
||||||
|
|
||||||
|
// Returns true if we're running in a server.
|
||||||
IsServer() bool
|
IsServer() bool
|
||||||
|
|
||||||
|
// Returns the server port.
|
||||||
ServerPort() int
|
ServerPort() int
|
||||||
|
|
||||||
|
// Returns the configured title for this Site.
|
||||||
Title() string
|
Title() string
|
||||||
|
|
||||||
|
// Returns all Sites for all languages.
|
||||||
Sites() Sites
|
Sites() Sites
|
||||||
|
|
||||||
|
// Returns Site currently rendering.
|
||||||
Current() Site
|
Current() Site
|
||||||
|
|
||||||
|
// Returns a struct with some information about the build.
|
||||||
Hugo() hugo.Info
|
Hugo() hugo.Info
|
||||||
|
|
||||||
|
// Returns the BaseURL for this Site.
|
||||||
BaseURL() template.URL
|
BaseURL() template.URL
|
||||||
|
|
||||||
|
// Retuns a taxonomy map.
|
||||||
Taxonomies() any
|
Taxonomies() any
|
||||||
|
|
||||||
|
// Returns the last modification date of the content.
|
||||||
LastChange() time.Time
|
LastChange() time.Time
|
||||||
|
|
||||||
|
// Returns the Menus for this site.
|
||||||
Menus() navigation.Menus
|
Menus() navigation.Menus
|
||||||
|
|
||||||
|
// Returns the Params configured for this site.
|
||||||
Params() maps.Params
|
Params() maps.Params
|
||||||
|
|
||||||
|
// Returns a map of all the data inside /data.
|
||||||
Data() map[string]any
|
Data() map[string]any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ func (w WeightedPage) String() string {
|
||||||
return fmt.Sprintf("WeightedPage(%d,%q)", w.Weight, w.Page.Title())
|
return fmt.Sprintf("WeightedPage(%d,%q)", w.Weight, w.Page.Title())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slice is not meant to be used externally. It's a bridge function
|
// Slice is for internal use.
|
||||||
// for the template functions. See collections.Slice.
|
// for the template functions. See collections.Slice.
|
||||||
func (p WeightedPage) Slice(in any) (any, error) {
|
func (p WeightedPage) Slice(in any) (any, error) {
|
||||||
switch items := in.(type) {
|
switch items := in.(type) {
|
||||||
|
|
|
@ -161,7 +161,7 @@ type baseResource interface {
|
||||||
type commonResource struct {
|
type commonResource struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slice is not meant to be used externally. It's a bridge function
|
// Slice is for internal use.
|
||||||
// for the template functions. See collections.Slice.
|
// for the template functions. See collections.Slice.
|
||||||
func (commonResource) Slice(in any) (any, error) {
|
func (commonResource) Slice(in any) (any, error) {
|
||||||
switch items := in.(type) {
|
switch items := in.(type) {
|
||||||
|
|
|
@ -20,9 +20,16 @@ var _ Dated = Dates{}
|
||||||
// Dated wraps a "dated resource". These are the 4 dates that makes
|
// Dated wraps a "dated resource". These are the 4 dates that makes
|
||||||
// the date logic in Hugo.
|
// the date logic in Hugo.
|
||||||
type Dated interface {
|
type Dated interface {
|
||||||
|
// Date returns the date of the resource.
|
||||||
Date() time.Time
|
Date() time.Time
|
||||||
|
|
||||||
|
// Lastmod returns the last modification date of the resource.
|
||||||
Lastmod() time.Time
|
Lastmod() time.Time
|
||||||
|
|
||||||
|
// PublishDate returns the publish date of the resource.
|
||||||
PublishDate() time.Time
|
PublishDate() time.Time
|
||||||
|
|
||||||
|
// ExpiryDate returns the expiration date of the resource.
|
||||||
ExpiryDate() time.Time
|
ExpiryDate() time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,9 @@
|
||||||
package resource
|
package resource
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"image"
|
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/maps"
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
"github.com/gohugoio/hugo/langs"
|
"github.com/gohugoio/hugo/langs"
|
||||||
"github.com/gohugoio/hugo/media"
|
"github.com/gohugoio/hugo/media"
|
||||||
"github.com/gohugoio/hugo/resources/images/exif"
|
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/hugio"
|
"github.com/gohugoio/hugo/common/hugio"
|
||||||
)
|
)
|
||||||
|
@ -82,26 +79,6 @@ type Resource interface {
|
||||||
ErrProvider
|
ErrProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image represents an image resource.
|
|
||||||
type Image interface {
|
|
||||||
Resource
|
|
||||||
ImageOps
|
|
||||||
}
|
|
||||||
|
|
||||||
type ImageOps interface {
|
|
||||||
Height() int
|
|
||||||
Width() int
|
|
||||||
Crop(spec string) (Image, error)
|
|
||||||
Fill(spec string) (Image, error)
|
|
||||||
Fit(spec string) (Image, error)
|
|
||||||
Resize(spec string) (Image, error)
|
|
||||||
Filter(filters ...any) (Image, error)
|
|
||||||
Exif() *exif.Exif
|
|
||||||
|
|
||||||
// Internal
|
|
||||||
DecodeImage() (image.Image, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResourceTypeProvider interface {
|
type ResourceTypeProvider interface {
|
||||||
// ResourceType is the resource type. For most file types, this is the main
|
// ResourceType is the resource type. For most file types, this is the main
|
||||||
// part of the MIME type, e.g. "image", "application", "text" etc.
|
// part of the MIME type, e.g. "image", "application", "text" etc.
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
"github.com/gohugoio/hugo/media"
|
"github.com/gohugoio/hugo/media"
|
||||||
"github.com/gohugoio/hugo/output"
|
"github.com/gohugoio/hugo/output"
|
||||||
|
"github.com/gohugoio/hugo/resources/images"
|
||||||
"github.com/gohugoio/hugo/resources/page"
|
"github.com/gohugoio/hugo/resources/page"
|
||||||
"github.com/gohugoio/hugo/resources/resource"
|
"github.com/gohugoio/hugo/resources/resource"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
@ -131,19 +132,19 @@ func newTestResourceOsFs(c *qt.C) (*Spec, string) {
|
||||||
return spec, workDir
|
return spec, workDir
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchSunset(c *qt.C) resource.Image {
|
func fetchSunset(c *qt.C) images.ImageResource {
|
||||||
return fetchImage(c, "sunset.jpg")
|
return fetchImage(c, "sunset.jpg")
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchImage(c *qt.C, name string) resource.Image {
|
func fetchImage(c *qt.C, name string) images.ImageResource {
|
||||||
spec := newTestResourceSpec(specDescriptor{c: c})
|
spec := newTestResourceSpec(specDescriptor{c: c})
|
||||||
return fetchImageForSpec(spec, c, name)
|
return fetchImageForSpec(spec, c, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchImageForSpec(spec *Spec, c *qt.C, name string) resource.Image {
|
func fetchImageForSpec(spec *Spec, c *qt.C, name string) images.ImageResource {
|
||||||
r := fetchResourceForSpec(spec, c, name)
|
r := fetchResourceForSpec(spec, c, name)
|
||||||
|
|
||||||
img := r.(resource.Image)
|
img := r.(images.ImageResource)
|
||||||
|
|
||||||
c.Assert(img, qt.Not(qt.IsNil))
|
c.Assert(img, qt.Not(qt.IsNil))
|
||||||
c.Assert(img.(specProvider).getSpec(), qt.Not(qt.IsNil))
|
c.Assert(img.(specProvider).getSpec(), qt.Not(qt.IsNil))
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/resources/images"
|
||||||
"github.com/gohugoio/hugo/resources/images/exif"
|
"github.com/gohugoio/hugo/resources/images/exif"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
|
||||||
|
@ -176,19 +177,19 @@ func (r *resourceAdapter) Data() any {
|
||||||
return r.target.Data()
|
return r.target.Data()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *resourceAdapter) Crop(spec string) (resource.Image, error) {
|
func (r *resourceAdapter) Crop(spec string) (images.ImageResource, error) {
|
||||||
return r.getImageOps().Crop(spec)
|
return r.getImageOps().Crop(spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *resourceAdapter) Fill(spec string) (resource.Image, error) {
|
func (r *resourceAdapter) Fill(spec string) (images.ImageResource, error) {
|
||||||
return r.getImageOps().Fill(spec)
|
return r.getImageOps().Fill(spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *resourceAdapter) Fit(spec string) (resource.Image, error) {
|
func (r *resourceAdapter) Fit(spec string) (images.ImageResource, error) {
|
||||||
return r.getImageOps().Fit(spec)
|
return r.getImageOps().Fit(spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *resourceAdapter) Filter(filters ...any) (resource.Image, error) {
|
func (r *resourceAdapter) Filter(filters ...any) (images.ImageResource, error) {
|
||||||
return r.getImageOps().Filter(filters...)
|
return r.getImageOps().Filter(filters...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +197,7 @@ func (r *resourceAdapter) Height() int {
|
||||||
return r.getImageOps().Height()
|
return r.getImageOps().Height()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *resourceAdapter) Exif() *exif.Exif {
|
func (r *resourceAdapter) Exif() *exif.ExifInfo {
|
||||||
return r.getImageOps().Exif()
|
return r.getImageOps().Exif()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,7 +242,7 @@ func (r *resourceAdapter) RelPermalink() string {
|
||||||
return r.target.RelPermalink()
|
return r.target.RelPermalink()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *resourceAdapter) Resize(spec string) (resource.Image, error) {
|
func (r *resourceAdapter) Resize(spec string) (images.ImageResource, error) {
|
||||||
return r.getImageOps().Resize(spec)
|
return r.getImageOps().Resize(spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,8 +282,8 @@ func (r *resourceAdapter) DecodeImage() (image.Image, error) {
|
||||||
return r.getImageOps().DecodeImage()
|
return r.getImageOps().DecodeImage()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *resourceAdapter) getImageOps() resource.ImageOps {
|
func (r *resourceAdapter) getImageOps() images.ImageResourceOps {
|
||||||
img, ok := r.target.(resource.ImageOps)
|
img, ok := r.target.(images.ImageResourceOps)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Sprintf("%T is not an image", r.target))
|
panic(fmt.Sprintf("%T is not an image", r.target))
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/media"
|
"github.com/gohugoio/hugo/media"
|
||||||
|
"github.com/gohugoio/hugo/resources/images"
|
||||||
"github.com/gohugoio/hugo/resources/internal"
|
"github.com/gohugoio/hugo/resources/internal"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
|
@ -361,7 +362,7 @@ func TestTransform(t *testing.T) {
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
c.Assert(tr.MediaType(), eq, media.PNGType)
|
c.Assert(tr.MediaType(), eq, media.PNGType)
|
||||||
|
|
||||||
img, ok := tr.(resource.Image)
|
img, ok := tr.(images.ImageResource)
|
||||||
c.Assert(ok, qt.Equals, true)
|
c.Assert(ok, qt.Equals, true)
|
||||||
|
|
||||||
c.Assert(img.Width(), qt.Equals, 75)
|
c.Assert(img.Width(), qt.Equals, 75)
|
||||||
|
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/resources/images"
|
"github.com/gohugoio/hugo/resources/images"
|
||||||
"github.com/gohugoio/hugo/resources/resource"
|
|
||||||
|
|
||||||
// Importing image codecs for image.DecodeConfig
|
// Importing image codecs for image.DecodeConfig
|
||||||
_ "image/gif"
|
_ "image/gif"
|
||||||
|
@ -92,12 +91,12 @@ func (ns *Namespace) Config(path any) (image.Config, error) {
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *Namespace) Filter(args ...any) (resource.Image, error) {
|
func (ns *Namespace) Filter(args ...any) (images.ImageResource, error) {
|
||||||
if len(args) < 2 {
|
if len(args) < 2 {
|
||||||
return nil, errors.New("must provide an image and one or more filters")
|
return nil, errors.New("must provide an image and one or more filters")
|
||||||
}
|
}
|
||||||
|
|
||||||
img := args[len(args)-1].(resource.Image)
|
img := args[len(args)-1].(images.ImageResource)
|
||||||
filtersv := args[:len(args)-1]
|
filtersv := args[:len(args)-1]
|
||||||
|
|
||||||
return img.Filter(filtersv...)
|
return img.Filter(filtersv...)
|
||||||
|
|
Loading…
Reference in a new issue