Allow for marked up file thumbnails to be shown and uploaded.

This commit is contained in:
Justin Hawkins 2021-12-29 21:47:57 +10:30
parent bebc161256
commit 563de29fcf
6 changed files with 117 additions and 49 deletions

View File

@ -5,6 +5,7 @@ import (
"image" "image"
"image/png" "image/png"
"io" "io"
"log"
"os" "os"
"github.com/tardisx/discord-auto-upload/upload" "github.com/tardisx/discord-auto-upload/upload"
@ -16,8 +17,18 @@ const (
thumbnailMaxY = 128 thumbnailMaxY = 128
) )
func (ip *Processor) ThumbPNG(ul *upload.Upload, w io.Writer) error { func (ip *Processor) ThumbPNG(ul *upload.Upload, which string, w io.Writer) error {
file, err := os.Open(ul.OriginalFilename)
var filename string
if which == "orig" {
filename = ul.OriginalFilename
} else if which == "markedup" {
filename = ul.MarkedUpFilename
} else {
log.Fatal("was passed incorrect 'which' arg")
}
file, err := os.Open(filename)
if err != nil { if err != nil {
return fmt.Errorf("could not open file: %s", err) return fmt.Errorf("could not open file: %s", err)
} }

View File

@ -14,7 +14,6 @@ import (
"mime/multipart" "mime/multipart"
"net/http" "net/http"
"os" "os"
"path/filepath"
"sync/atomic" "sync/atomic"
"time" "time"
@ -49,9 +48,8 @@ type Upload struct {
Id int32 `json:"id"` Id int32 `json:"id"`
UploadedAt time.Time `json:"uploaded_at"` UploadedAt time.Time `json:"uploaded_at"`
OriginalFilename string `json:"original_file"` // path on the local disk OriginalFilename string `json:"original_file"` // path on the local disk
MarkedUpFilename string `json:"markedup_file"` // a temporary file, if the user did some markup MarkedUpFilename string `json:"markedup_file"` // a temporary file, if the user did some markup
TemporaryFileToUpload string // post-watermark, or just original if unwatermarked
webhookURL string webhookURL string
@ -121,13 +119,6 @@ func (u *Upload) processUpload() error {
return errors.New("webhook url not configured") return errors.New("webhook url not configured")
} }
if u.watermark {
daulog.SendLog("Watermarking image", daulog.LogTypeInfo)
u.applyWatermark()
} else {
u.TemporaryFileToUpload = u.OriginalFilename
}
extraParams := map[string]string{} extraParams := map[string]string{}
if u.usernameOverride != "" { if u.usernameOverride != "" {
@ -152,7 +143,42 @@ func (u *Upload) processUpload() error {
var retriesRemaining = 5 var retriesRemaining = 5
for retriesRemaining > 0 { for retriesRemaining > 0 {
request, err := newfileUploadRequest(u.webhookURL, extraParams, "file", u.TemporaryFileToUpload) // open an io.ReadCloser for the file we intend to upload
var filedata *os.File
var err error
if len(u.MarkedUpFilename) > 0 {
filedata, err = os.Open(u.MarkedUpFilename)
if err != nil {
log.Print("Error opening marked up file:", err)
retriesRemaining--
sleepForRetries(retriesRemaining)
continue
}
} else {
filedata, err = os.Open(u.OriginalFilename)
if err != nil {
log.Print("Error opening original file:", err)
retriesRemaining--
sleepForRetries(retriesRemaining)
continue
}
}
var imageData io.Reader
if u.watermark {
daulog.SendLog("Watermarking image", daulog.LogTypeInfo)
imageData, err = u.applyWatermark(filedata)
if err != nil {
log.Print("Error watermarking:", err)
retriesRemaining--
sleepForRetries(retriesRemaining)
continue
}
} else {
imageData = filedata
}
request, err := newfileUploadRequest(u.webhookURL, extraParams, "file", "pikachu.png", imageData)
if err != nil { if err != nil {
log.Printf("error creating upload request: %s", err) log.Printf("error creating upload request: %s", err)
return fmt.Errorf("could not create upload request: %s", err) return fmt.Errorf("could not create upload request: %s", err)
@ -237,9 +263,9 @@ func (u *Upload) processUpload() error {
} }
} }
if u.watermark { // remove any marked up file
daulog.SendLog(fmt.Sprintf("Removing temporary file: %s", u.TemporaryFileToUpload), daulog.LogTypeDebug) if len(u.MarkedUpFilename) > 0 {
os.Remove(u.TemporaryFileToUpload) os.Remove(u.MarkedUpFilename)
} }
if retriesRemaining == 0 { if retriesRemaining == 0 {
@ -247,23 +273,19 @@ func (u *Upload) processUpload() error {
u.State = StateFailed u.State = StateFailed
return errors.New("could not upload after all retries") return errors.New("could not upload after all retries")
} }
return nil return nil
} }
func newfileUploadRequest(uri string, params map[string]string, paramName, path string) (*http.Request, error) { func newfileUploadRequest(uri string, params map[string]string, paramName string, filename string, filedata io.Reader) (*http.Request, error) {
file, err := os.Open(path)
if err != nil {
return nil, fmt.Errorf("could not open file '%s': %s", path, err)
}
defer file.Close()
body := &bytes.Buffer{} body := &bytes.Buffer{}
writer := multipart.NewWriter(body) writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile(paramName, filepath.Base(path)) part, err := writer.CreateFormFile(paramName, filename)
if err != nil { if err != nil {
return nil, err return nil, err
} }
_, err = io.Copy(part, file) _, err = io.Copy(part, filedata)
if err != nil { if err != nil {
log.Fatal("Could not copy: ", err) log.Fatal("Could not copy: ", err)
} }
@ -281,20 +303,15 @@ func newfileUploadRequest(uri string, params map[string]string, paramName, path
return req, err return req, err
} }
func (u *Upload) applyWatermark() { // applyWatermark applies the watermark to the image
func (u *Upload) applyWatermark(in *os.File) (io.Reader, error) {
reader, err := os.Open(u.OriginalFilename) defer in.Close()
if err != nil {
log.Fatal(err)
}
defer reader.Close()
im, _, err := image.Decode(reader) im, _, err := image.Decode(in)
if err != nil { if err != nil {
daulog.SendLog(fmt.Sprintf("Cannot decode image: %v - skipping watermarking", err), daulog.LogTypeError) daulog.SendLog(fmt.Sprintf("Cannot decode image: %v - skipping watermarking", err), daulog.LogTypeError)
u.watermark = false return nil, errors.New("cannot decode image")
u.TemporaryFileToUpload = u.OriginalFilename
return
} }
bounds := im.Bounds() bounds := im.Bounds()
// var S float64 = float64(bounds.Max.X) // var S float64 = float64(bounds.Max.X)
@ -315,16 +332,9 @@ func (u *Upload) applyWatermark() {
dc.DrawString("github.com/tardisx/discord-auto-upload", 5.0, float64(bounds.Max.Y)-5.0) dc.DrawString("github.com/tardisx/discord-auto-upload", 5.0, float64(bounds.Max.Y)-5.0)
tempfile, err := ioutil.TempFile("", "dau") b := bytes.Buffer{}
if err != nil { dc.EncodePNG(&b)
log.Fatal(err) return &b, nil
}
tempfile.Close()
os.Remove(tempfile.Name())
actualName := tempfile.Name() + ".png"
dc.SavePNG(actualName)
u.TemporaryFileToUpload = actualName
} }
func sleepForRetries(retry int) { func sleepForRetries(retry int) {

5
web/data/alpine.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -23,7 +23,8 @@
<button @click="skip_upload(ul.id)" type="button" class="btn btn-primary">reject</button> <button @click="skip_upload(ul.id)" type="button" class="btn btn-primary">reject</button>
</td> </td>
<td> <td>
<td><a x-bind:href="'/editor.html?id='+ul.id"><img x-bind:src="'/rest/image/'+ul.id+'/thumb'"></a></td> <a x-bind:href="'/editor.html?id='+ul.id"><img x-bind:src="'/rest/image/'+ul.id+'/thumb'"></a>
<a x-show="ul.markedup_file" x-bind:href="'/editor.html?id='+ul.id"><img x-bind:src="'/rest/image/'+ul.id+'/markedup_thumb'"></a>
</td> </td>
</tr> </tr>
</template> </template>

View File

@ -7,7 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
<script src="//unpkg.com/alpinejs" defer></script> <script src="/alpine.js" defer></script>
<script src="https://cdn.jsdelivr.net/npm/fabric@4.6.0/dist/fabric.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/fabric@4.6.0/dist/fabric.min.js"></script>
<style> <style>

View File

@ -189,7 +189,31 @@ func (ws *WebService) imageThumb(w http.ResponseWriter, r *http.Request) {
returnJSONError(w, "bad id") returnJSONError(w, "bad id")
return return
} }
err = processor.ThumbPNG(ul, w) err = processor.ThumbPNG(ul, "orig", w)
if err != nil {
returnJSONError(w, "could not create thumb")
return
}
}
func (ws *WebService) imageMarkedupThumb(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "image/png")
processor := imageprocess.Processor{}
vars := mux.Vars(r)
id, err := strconv.ParseInt(vars["id"], 10, 32)
if err != nil {
returnJSONError(w, "bad id")
return
}
ul := ws.Uploader.UploadById(int32(id))
if ul == nil {
returnJSONError(w, "bad id")
return
}
err = processor.ThumbPNG(ul, "markedup", w)
if err != nil { if err != nil {
returnJSONError(w, "could not create thumb") returnJSONError(w, "could not create thumb")
return return
@ -268,7 +292,22 @@ func (ws *WebService) modifyUpload(w http.ResponseWriter, r *http.Request) {
returnJSONError(w, err.Error()) returnJSONError(w, err.Error())
return return
} }
fmt.Printf("YAY %v", b)
// write to a temporary file
tempfile, err := ioutil.TempFile("", "dau_markup")
if err != nil {
log.Fatal(err)
}
n, err := tempfile.Write(b)
if n != len(b) {
log.Fatalf("only wrote %d bytes??", n)
}
if err != nil {
log.Fatalf("Could not write temp file: %v", err)
}
tempfile.Close()
anUpload.MarkedUpFilename = tempfile.Name()
} else { } else {
returnJSONError(w, "bad change type") returnJSONError(w, "bad change type")
@ -294,6 +333,8 @@ func (ws *WebService) StartWebServer() {
r.HandleFunc("/rest/upload/{id:[0-9]+}/{change}", ws.modifyUpload) r.HandleFunc("/rest/upload/{id:[0-9]+}/{change}", ws.modifyUpload)
r.HandleFunc("/rest/image/{id:[0-9]+}/thumb", ws.imageThumb) r.HandleFunc("/rest/image/{id:[0-9]+}/thumb", ws.imageThumb)
r.HandleFunc("/rest/image/{id:[0-9]+}/markedup_thumb", ws.imageMarkedupThumb)
r.HandleFunc("/rest/image/{id:[0-9]+}", ws.image) r.HandleFunc("/rest/image/{id:[0-9]+}", ws.image)
r.HandleFunc("/rest/config", ws.handleConfig) r.HandleFunc("/rest/config", ws.handleConfig)