Golang & Javascript : How to save cropped image to file on server
While building my web application to manage my tenants and rental properties, I need a solution to capture the cropped image and save the bytes produced by https://github.com/fengyuanchen/cropperjs into my server(or upload directly to S3). Cropping image helps to reduce the image size and provides a clearer representation on which part of the original image to focus on.
The example code below demonstrates how to crop an image and store the image bytes into a file. Before compiling and executing the code, make sure that you have:
Download chi package by
go get -u github.com/go-chi/chi
Create a directory named
cropped
An image file to crop
package main
import (
"bytes"
"encoding/base64"
"fmt"
"image"
"image/png"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/go-chi/chi"
)
func SaveFile(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
imgBase64 := r.FormValue("data")
// remove "data:image/png;base64,"
imgBase64cleaned := imgBase64[len("data:image/png;base64,"):len(imgBase64)]
// decode base64 to buffer bytes
imgBytes, _ := base64.StdEncoding.DecodeString(imgBase64cleaned)
// convert []byte to image for saving to file
img, _, _ := image.Decode(bytes.NewReader(imgBytes))
currentDir, _ := os.Getwd()
imgFile, err := os.Create(currentDir + "/cropped/croppedimage.png")
if err != nil {
panic(err)
}
// save to file on your webserver
png.Encode(imgFile, img)
fmt.Println("croppedimage.png file saved")
}
}
func CropImage(w http.ResponseWriter, r *http.Request) {
html := `<!DOCTYPE html>
<html lang="en">
<head>
<title>Golang and Cropper JS demo</title>
<!-- cropper js -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.6/cropper.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.6/cropper.min.js"></script>
<!-- jquery -->
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
</head><body>
<input type="file" name="img[]" class="file-upload-default" id="cropperImageUpload">
<div>
<input type="text" class="form-control file-upload-info" disabled="" placeholder="Upload Image">
<button class="file-upload-browse" type="button">Upload</button>
</div>
<div>
<label>Width (px) :</label>
<input type="number" value="300" class="img-w" placeholder="Image width">
<button class="btn btn-primary crop mb-2 mb-md-0">Crop</button>
<a href="javascript:;" class="save">Save</a>
</div>
<style>
w-100 {
max-width: 100%; /* This rule is very important, please do not ignore this! */
}
</style>
<div>
<img src="" class="w-100" id="croppingImage" alt="cropper">
</div>
<div class="col-md-4 ml-auto">
<h6>Cropped Image: </h6>
<img class="w-100 cropped-img" src="#" alt="">
</div>
<script type="text/javascript">
$(function() {
'use strict';
var croppingImage = document.querySelector('#croppingImage'),
img_w = document.querySelector('.img-w'),
cropBtn = document.querySelector('.crop'),
croppedImg = document.querySelector('.cropped-img'),
saveBtn = document.querySelector('.save'),
upload = document.querySelector('#cropperImageUpload'),
cropper = '';
$('.file-upload-browse').on('click', function(e) {
var file = $(this).parent().parent().parent().find('.file-upload-default');
file.trigger('click');
});
cropper = new Cropper(croppingImage);
// on change show image with crop options
upload.addEventListener('change', function (e) {
$(this).parent().find('.form-control').val($(this).val().replace(/C:\\fakepath\\/i, ''));
if (e.target.files.length) {
cropper.destroy();
// start file reader
const reader = new FileReader();
reader.onload = function (e) {
if(e.target.result){
croppingImage.src = e.target.result;
cropper = new Cropper(croppingImage);
}
};
reader.readAsDataURL(e.target.files[0]);
}
});
// crop on click
cropBtn.addEventListener('click',function(e) {
e.preventDefault();
// get result to data uri
let imgSrc = cropper.getCroppedCanvas({
width: img_w.value // input value
}).toDataURL();
croppedImg.src = imgSrc;
saveBtn.setAttribute('href', imgSrc);
});
// save on click
saveBtn.addEventListener('click',function(e) {
e.preventDefault();
// get result to data uri
let imgSrc = cropper.getCroppedCanvas({
//width: img_w.value // input value
width: 300 // input value
}).toDataURL();
//post base64 image data to saveCroppedPhoto function then redirect to the /cropped directory show the actual file
$.post("/saveCroppedPhoto", {data: imgSrc}, function () {window.location.href = "/cropped/"});
});
});
</script>`
w.Write([]byte(html))
}
func main() {
mux := chi.NewRouter()
mux.HandleFunc("/", CropImage)
mux.HandleFunc("/saveCroppedPhoto", SaveFile)
// expose our /cropped directory
workDir, _ := os.Getwd()
croppedDir := filepath.Join(workDir, "/cropped")
fileServer(mux, "/cropped", http.Dir(croppedDir))
http.ListenAndServe(":8080", mux)
}
func fileServer(r chi.Router, path string, root http.FileSystem) {
if strings.ContainsAny(path, "{}*") {
panic("FileServer does not permit URL parameters.")
}
fs := http.StripPrefix(path, http.FileServer(root))
if path != "/" && path[len(path)-1] != '/' {
r.Get(path, http.RedirectHandler(path+"/", 301).ServeHTTP)
path += "/"
}
path += "*"
r.Get(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fs.ServeHTTP(w, r)
}))
}
Start the program and point to localhost:8080
with your browser. Upload
an image file, crop
and save
the cropped image.
Happy coding!
References:
https://www.socketloop.com/tutorials/golang-upload-to-s3-with-official-aws-sdk-go-package
https://github.com/fengyuanchen/cropperjs/blob/master/README.md#features
https://www.socketloop.com/tutorials/golang-take-screen-shot-of-browser-with-jquery-example
See also : Golang : Upload to S3 with official aws-sdk-go package
By Adam Ng(黃武俊)
IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.
Advertisement
Tutorials
+6.9k Golang : Fix - does not implement sort.Interface (missing Len method)
+6k Golang : Gorilla web tool kit schema example
+8.6k Golang : Skip blank/empty lines in CSV file and trim whitespaces example
+5.8k Swift : Convert (cast) String to Float
+16.6k Golang : How to Set or Add Header http.ResponseWriter?
+3.1k HTTP common errors and their meaning explained
+5.7k Gogland : Where to put source code files in package directory for rookie
+29.4k Golang : Display float in 2 decimal points and rounding up or down
+8.8k Golang : Encrypt and decrypt data with x509 crypto
+5.3k Golang : Generate Datamatrix barcode
+6.3k Golang : GMail API create and send draft with simple upload attachment example
+12.9k Golang : Capture stdout of a child process and act according to the result