Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

crop create new record #841

Merged
merged 1 commit into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading