Skip to content

Commit

Permalink
Merge pull request #841 from qor5/fix-crop
Browse files Browse the repository at this point in the history
crop create new record
  • Loading branch information
zhangshanwen authored Jan 3, 2025
2 parents fed8547 + e438e9f commit d070fd1
Show file tree
Hide file tree
Showing 12 changed files with 209 additions and 71 deletions.
2 changes: 1 addition & 1 deletion example/integration/pagebuilder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func TestPageBuilder(t *testing.T) {
return req
},
ExpectPageBodyContainsInOrder: []string{
`eventFunc("page_builder_EditContainerEvent").query("containerDataID", vars.containerDataID)`,
`eventFunc("page_builder_EditContainerEvent").mergeQuery(true).query("containerDataID", vars.containerDataID)`,
},
},
{
Expand Down
31 changes: 16 additions & 15 deletions media/base/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ func (fileWrapper *fileWrapper) Open() (multipart.File, error) {
type Base struct {
FileName string
Url string
ParentUrl string
CropOptions map[string]*CropOption `json:",omitempty"`
Delete bool `json:"-"`
Crop bool `json:"-"`
Crop bool `json:",omitempty"`
FileHeader FileHeader `json:"-"`
Reader io.Reader `json:"-"`
Options map[string]string `json:",omitempty"`
Expand Down Expand Up @@ -116,7 +117,7 @@ func (b *Base) Scan(data interface{}) (err error) {
}

// Value return struct's Value
func (b Base) Value() (driver.Value, error) {
func (b *Base) Value() (driver.Value, error) {
if b.Delete {
return nil, nil
}
Expand All @@ -125,20 +126,20 @@ func (b Base) Value() (driver.Value, error) {
return string(results), err
}

func (b Base) Ext() string {
func (b *Base) Ext() string {
return strings.ToLower(path.Ext(b.Url))
}

// URL return file's url with given style
func (b Base) URL(styles ...string) string {
func (b *Base) URL(styles ...string) string {
if b.Url != "" && len(styles) > 0 {
ext := path.Ext(b.Url)
return fmt.Sprintf("%v.%v%v", strings.TrimSuffix(b.Url, ext), styles[0], ext)
}
return b.Url
}

func (b Base) URLNoCached(styles ...string) string {
func (b *Base) URLNoCached(styles ...string) string {
i := b.URL(styles...)
if i != "" {
return i + "?" + fmt.Sprint(time.Now().Nanosecond())
Expand All @@ -147,12 +148,12 @@ func (b Base) URLNoCached(styles ...string) string {
}

// String return file's url
func (b Base) String() string {
func (b *Base) String() string {
return b.URL()
}

// GetFileName get file's name
func (b Base) GetFileName() string {
func (b *Base) GetFileName() string {
if b.FileName != "" {
return b.FileName
}
Expand All @@ -163,12 +164,12 @@ func (b Base) GetFileName() string {
}

// GetFileHeader get file's header, this value only exists when saving files
func (b Base) GetFileHeader() FileHeader {
func (b *Base) GetFileHeader() FileHeader {
return b.FileHeader
}

// GetURLTemplate get url template
func (b Base) GetURLTemplate(option *Option) (path string) {
func (b *Base) GetURLTemplate(option *Option) (path string) {
if path = option.Get("URL"); path == "" {
path = "/system/{{class}}/{{primary_key}}/{{column}}/{{filename_with_hash}}"
}
Expand Down Expand Up @@ -207,7 +208,7 @@ func getFuncMap(db *gorm.DB, field *schema.Field, filename string) template.Func
}

// GetURL get default URL for a model based on its options
func (b Base) GetURL(option *Option, db *gorm.DB, field *schema.Field, templater URLTemplater) string {
func (b *Base) GetURL(option *Option, db *gorm.DB, field *schema.Field, templater URLTemplater) string {
if path := templater.GetURLTemplate(option); path != "" {
tmpl := template.New("").Funcs(getFuncMap(db, field, b.GetFileName()))
if tmpl, err := tmpl.Parse(path); err == nil {
Expand Down Expand Up @@ -254,25 +255,25 @@ func (b *Base) GetFileSizes() map[string]int {
}

// Retrieve retrieve file content with url
func (b Base) Retrieve(url string) (*os.File, error) {
func (b *Base) Retrieve(url string) (*os.File, error) {
return nil, errors.New("not implemented")
}

// GetSizes get configured sizes, it will be used to crop images accordingly
func (b Base) GetSizes() map[string]*Size {
func (b *Base) GetSizes() map[string]*Size {
return map[string]*Size{}
}

// IsImage return if it is an image
func (b Base) IsImage() bool {
func (b *Base) IsImage() bool {
return IsImageFormat(b.URL())
}

func (b Base) IsVideo() bool {
func (b *Base) IsVideo() bool {
return IsVideoFormat(b.URL())
}

func (b Base) IsSVG() bool {
func (b *Base) IsSVG() bool {
return IsSVGFormat(b.URL())
}

Expand Down
58 changes: 40 additions & 18 deletions media/base/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ import (
)

var (
mediaHandlers = make(map[string]MediaHandler)
DefaultSizeKey = "default"
mediaHandlers = make(map[string]MediaHandler)
DefaultSizeKey = "default"
OriginalSizeKey = "original"
)

// MediaHandler media library handler interface, defined which files could be handled, and the handler
Expand All @@ -39,7 +40,7 @@ func (imageHandler) CouldHandle(media Media) bool {

func resizeImageTo(img image.Image, size *Size, format imaging.Format) image.Image {
imgSize := img.Bounds().Size()

SaleUpDown(imgSize.X, imgSize.Y, size)
switch {
case size.Padding:
var (
Expand Down Expand Up @@ -100,21 +101,26 @@ func resizeImageTo(img image.Image, size *Size, format imaging.Format) image.Ima
}

func (imageHandler) Handle(media Media, file FileInterface, option *Option) (err error) {
fileBytes, err := io.ReadAll(file)
var fileBytes []byte
fileBytes, err = io.ReadAll(file)
if err != nil {
return
}
fileSizes := media.GetFileSizes()
originalFileSize := len(fileBytes)
fileSizes["original"] = originalFileSize
file.Seek(0, 0)
err = media.Store(media.URL("original"), option, file)
fileSizes[OriginalSizeKey] = originalFileSize
if _, err = file.Seek(0, 0); err != nil {
return
}
err = media.Store(media.URL(OriginalSizeKey), option, file)
if err != nil {
return
}
file.Seek(0, 0)

format, err := GetImageFormat(media.URL())
if _, err = file.Seek(0, 0); err != nil {
return
}
var format *imaging.Format
format, err = GetImageFormat(media.URL())
if err != nil {
return
}
Expand All @@ -127,8 +133,8 @@ func (imageHandler) Handle(media Media, file FileInterface, option *Option) (err
SetFileSizes(media, fileSizes)
return
}

img, _, err := image.Decode(file)
var img image.Image
img, _, err = image.Decode(file)
if err != nil {
return
}
Expand All @@ -137,14 +143,22 @@ func (imageHandler) Handle(media Media, file FileInterface, option *Option) (err
// Save cropped default image
if cropOption := media.GetCropOption(DefaultSizeKey); cropOption != nil {
var buffer bytes.Buffer
imaging.Encode(&buffer, imaging.Crop(img, *cropOption), *format)
if err = imaging.Encode(&buffer, imaging.Crop(img, *cropOption), *format); err != nil {
return
}
fileSizes[DefaultSizeKey] = buffer.Len()
media.Store(media.URL(), option, &buffer)
if err = media.Store(media.URL(), option, &buffer); err != nil {
return
}
} else {
file.Seek(0, 0)
if _, err = file.Seek(0, 0); err != nil {
return
}
// Save default image
fileSizes[DefaultSizeKey] = originalFileSize
media.Store(media.URL(), option, file)
if err = media.Store(media.URL(), option, file); err != nil {
return
}
}

// save sizes image
Expand All @@ -156,11 +170,19 @@ func (imageHandler) Handle(media Media, file FileInterface, option *Option) (err
newImage := img
if cropOption := media.GetCropOption(key); cropOption != nil {
newImage = imaging.Crop(newImage, *cropOption)
} else {
if cropOption = media.GetCropOption(DefaultSizeKey); cropOption != nil {
newImage = imaging.Crop(newImage, *cropOption)
}
}
var buffer bytes.Buffer
imaging.Encode(&buffer, resizeImageTo(newImage, size, *format), *format)
if err = imaging.Encode(&buffer, resizeImageTo(newImage, size, *format), *format); err != nil {
return
}
fileSizes[key] = buffer.Len()
media.Store(media.URL(key), option, &buffer)
if err = media.Store(media.URL(key), option, &buffer); err != nil {
return
}
}
SetFileSizes(media, fileSizes)

Expand Down
2 changes: 1 addition & 1 deletion media/base/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func cropField(field *schema.Field, db *gorm.DB) (cropped bool, err error) {
if fileHeader := media.GetFileHeader(); fileHeader != nil {
mediaFile, err = media.GetFileHeader().Open()
} else {
mediaFile, err = media.Retrieve(media.URL("original"))
mediaFile, err = media.Retrieve(media.URL(OriginalSizeKey))
}
defer mediaFile.Close()

Expand Down
12 changes: 11 additions & 1 deletion media/base/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import (
"regexp"
"strings"

"github.com/qor5/admin/v3/utils"
"github.com/qor5/imaging"

"github.com/qor5/admin/v3/utils"
)

func GetImageFormat(url string) (*imaging.Format, error) {
Expand Down Expand Up @@ -86,3 +87,12 @@ func ByteCountSI(b int) string {
return fmt.Sprintf(format,
float64(b)/float64(div), suffix)
}

func SaleUpDown(width, height int, size *Size) {
if size.Height == 0 && size.Width > 0 {
size.Height = int(float64(size.Width) / float64(width) * float64(height))

} else if size.Height > 0 && size.Width == 0 {
size.Width = int(float64(size.Height) / float64(height) * float64(width))
}
}
25 changes: 22 additions & 3 deletions media/cropper.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"strconv"
"time"

"gorm.io/gorm"

Expand Down Expand Up @@ -55,14 +54,16 @@ func loadImageCropper(mb *Builder) web.EventFunc {
)
if size == nil && thumb != base.DefaultSizeKey {
return
} else if thumb != base.DefaultSizeKey {
base.SaleUpDown(m.File.Width, m.File.Height, size)
}

c := cropper.Cropper().
Src(m.File.URL("original")).
ViewMode(cropper.VIEW_MODE_FILL_FIT_CONTAINER).
AutoCropArea(1).
Attr("@update:model-value", "cropLocals.CropOption=JSON.stringify($event)")
if size != nil {
//scale up and down keep width/height ratio
c.AspectRatio(float64(size.Width), float64(size.Height))
}
// Attr("style", "max-width: 800px; max-height: 600px;")
Expand Down Expand Up @@ -153,6 +154,22 @@ func cropImage(b *Builder) web.EventFunc {
Width: int(cropValue.Width),
Height: int(cropValue.Height),
}
if thumb == base.DefaultSizeKey {
m.ID = 0
if m.File.ParentUrl == "" {
m.File.ParentUrl = m.File.Url
}
m.File.CropOptions = make(map[string]*base.CropOption)
m.File.Sizes = make(map[string]*base.Size)
m.File.FileSizes = make(map[string]int)
moption.CropOptions = map[string]*base.CropOption{
thumb: moption.CropOptions[thumb],
}
moption.Sizes = media_library.GetQorPreviewSize(int(cropValue.Width), int(cropValue.Height))
m.CreatedAt = db.NowFunc()
m.UpdatedAt = db.NowFunc()
}

moption.Crop = true
err = m.ScanMediaOptions(moption)
if err != nil {
Expand All @@ -166,12 +183,14 @@ func cropImage(b *Builder) web.EventFunc {
b.onEdit(ctx, old, m)

mb.Url = m.File.Url
mb.UpdatedAt = time.Now()
mb.ParentUrl = m.File.ParentUrl
mb.FileSizes = m.File.FileSizes
if thumb == base.DefaultSizeKey {
mb.Width = int(cropValue.Width)
mb.Height = int(cropValue.Height)
}
mb.ID = json.Number(fmt.Sprint(m.ID))

}

r.UpdatePortals = append(r.UpdatePortals, &web.PortalUpdate{
Expand Down
Loading

0 comments on commit d070fd1

Please sign in to comment.