diff --git a/assets/js/controllers/edit_upload.js b/assets/js/controllers/edit_upload.js
index f1d472a..f575bea 100644
--- a/assets/js/controllers/edit_upload.js
+++ b/assets/js/controllers/edit_upload.js
@@ -24,9 +24,17 @@ const processorUIs = {
"shadow": {
label: "Shadow",
template: Handlebars.compile(`
-
-
-
+
+
`),
},
@@ -67,10 +75,19 @@ export default class UploadEditController extends Controller {
async removeProcessor(ev) {
ev.preventDefault();
let id = ev.params.id;
- console.log(ev.params);
await this._removeProcessor(id);
}
+ async updateProcessor(ev) {
+ ev.preventDefault();
+ let id = ev.params.id;
+
+ let paramParentEl = ev.target.closest('[data-role="processor-params"]');
+ let params = Object.fromEntries(new FormData(paramParentEl).entries());
+
+ await this._updateProcessor(id, params);
+ }
+
_rebuildProcessList() {
let el = this.processListTarget;
@@ -135,6 +152,25 @@ export default class UploadEditController extends Controller {
}
}
+ async _updateProcessor(processorID, params) {
+ await this._doReturningState(async () => {
+ return (await fetch(`/sites/${this.siteIdValue}/imageedit/${this._state.session.guid}`, {
+ method: 'PATCH',
+ headers: {
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ processor: {
+ id: processorID,
+ props: params,
+ }
+ })
+ })).json();
+ })
+ }
+
+
async _removeProcessor(processorID) {
await this._doReturningState(async () => {
return (await fetch(`/sites/${this.siteIdValue}/imageedit/${this._state.session.guid}/processors/${processorID}`, {
diff --git a/cmds/server.go b/cmds/server.go
index 515f7a5..7a1445a 100644
--- a/cmds/server.go
+++ b/cmds/server.go
@@ -153,6 +153,7 @@ Starting weiro without any arguments will start the server.
siteGroup.Get("/uploads/:uploadID/edit", uh.Edit)
siteGroup.Post("/imageedit", ieh.Create)
+ siteGroup.Patch("/imageedit/:sessionID", ieh.PatchSession)
siteGroup.Post("/imageedit/:sessionID/processors", ieh.AddProcessor)
siteGroup.Delete("/imageedit/:sessionID/processors/:processorID", ieh.DeleteProcessor)
siteGroup.Get("/imageedit/:sessionID/preview/:versionID", ieh.Preview)
diff --git a/handlers/imageedit.go b/handlers/imageedit.go
index 8026c53..ced7f75 100644
--- a/handlers/imageedit.go
+++ b/handlers/imageedit.go
@@ -113,3 +113,32 @@ func (ieh ImageEditHandlers) DeleteProcessor(c fiber.Ctx) error {
PreviewURL: res.PreviewURL(),
})
}
+
+func (ieh ImageEditHandlers) PatchSession(c fiber.Ctx) error {
+ var req struct {
+ UpdateProc *imgedit.UpdateProcessorReq `json:"processor"`
+ }
+
+ sessionID := c.Params("sessionID")
+ if sessionID == "" {
+ return fiber.ErrBadRequest
+ }
+
+ if err := c.Bind().Body(&req); err != nil {
+ return err
+ }
+ log.Printf("Got request: %v", *req.UpdateProc)
+
+ if req.UpdateProc != nil {
+ res, err := ieh.ImageEditService.UpdateProcessor(c.Context(), sessionID, *req.UpdateProc)
+ if err != nil {
+ return err
+ }
+ return c.Status(http.StatusOK).JSON(sessionResponse{
+ Session: res,
+ PreviewURL: res.PreviewURL(),
+ })
+ }
+
+ return fiber.ErrBadRequest
+}
diff --git a/services/imgedit/processing.go b/services/imgedit/processing.go
index 378ead5..c1f99bf 100644
--- a/services/imgedit/processing.go
+++ b/services/imgedit/processing.go
@@ -21,7 +21,7 @@ type imageProcessor struct {
type shadowProcessorArgs struct {
Color string `json:"color"`
- OffsetY int `json:"offset_y"`
+ OffsetY int `json:"offset_y,string"`
}
var processors = map[string]imageProcessor{
@@ -35,7 +35,12 @@ var processors = map[string]imageProcessor{
processImage: func(ctx context.Context, srcImg image.Image, params any) (image.Image, error) {
p := params.(*shadowProcessorArgs)
- shadow := makeBoxShadow(srcImg, color.Black, 4, 10, p.OffsetY)
+ shadowColor, err := parseHexColor(p.Color)
+ if err != nil {
+ return nil, fmt.Errorf("invalid shadow color: %w", err)
+ }
+
+ shadow := makeBoxShadow(srcImg, shadowColor, 4, 10, p.OffsetY)
composit := imaging.OverlayCenter(shadow, srcImg, 1.0)
return composit, nil
},
@@ -135,3 +140,39 @@ type imageImageSource struct {
func (i imageImageSource) image() (image.Image, error) {
return i.img, nil
}
+
+func parseHexColor(s string) (color.Color, error) {
+ // Remove leading hash if present
+ if len(s) > 0 && s[0] == '#' {
+ s = s[1:]
+ }
+
+ // Parse based on length
+ var r, g, b, a uint8
+ switch len(s) {
+ case 6:
+ // RGB format
+ var rgb uint32
+ if _, err := fmt.Sscanf(s, "%06x", &rgb); err != nil {
+ return nil, fmt.Errorf("invalid hex color format: %w", err)
+ }
+ r = uint8((rgb >> 16) & 0xFF)
+ g = uint8((rgb >> 8) & 0xFF)
+ b = uint8(rgb & 0xFF)
+ a = 0xFF
+ case 8:
+ // RGBA format
+ var rgba uint32
+ if _, err := fmt.Sscanf(s, "%08x", &rgba); err != nil {
+ return nil, fmt.Errorf("invalid hex color format: %w", err)
+ }
+ r = uint8((rgba >> 24) & 0xFF)
+ g = uint8((rgba >> 16) & 0xFF)
+ b = uint8((rgba >> 8) & 0xFF)
+ a = uint8(rgba & 0xFF)
+ default:
+ return nil, fmt.Errorf("invalid hex color length: expected 6 or 8 characters, got %d", len(s))
+ }
+
+ return color.RGBA{R: r, G: g, B: b, A: a}, nil
+}
diff --git a/services/imgedit/service.go b/services/imgedit/service.go
index d9f3ba4..c53a37e 100644
--- a/services/imgedit/service.go
+++ b/services/imgedit/service.go
@@ -146,6 +146,35 @@ func (s *Service) DeleteProcessor(ctx context.Context, sessionID, processorID st
return session, nil
}
+type UpdateProcessorReq struct {
+ ID string `json:"id"`
+ Props json.RawMessage `json:"props"`
+}
+
+func (s *Service) UpdateProcessor(ctx context.Context, sessionID string, req UpdateProcessorReq) (*models.ImageEditSession, error) {
+ session, err := s.loadAndVerifySession(ctx, sessionID)
+ if err != nil {
+ return nil, err
+ }
+
+ for i, p := range session.Processors {
+ if p.ID == req.ID {
+ session.Processors[i].Props = req.Props
+ break
+ }
+ }
+
+ session.RecalcVersionIDs()
+ if err := s.sessionStore.save(session); err != nil {
+ return nil, err
+ }
+ if _, err := s.reprocess(ctx, session); err != nil {
+ return nil, err
+ }
+
+ return session, nil
+}
+
func (s *Service) loadAndVerifySession(ctx context.Context, sessionID string) (*models.ImageEditSession, error) {
site, user, err := s.fetchSiteAndUser(ctx)
if err != nil {
diff --git a/views/uploads/edit.html b/views/uploads/edit.html
index 5c8cc2d..21b41bb 100644
--- a/views/uploads/edit.html
+++ b/views/uploads/edit.html
@@ -1,12 +1,12 @@
-
+
-
+
-
+
- Actions go here
+
+
\ No newline at end of file