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
+13.1k Golang : Verify token from Google Authenticator App
+5.5k Golang : Fix opencv.LoadHaarClassifierCascade The node does not represent a user object error
+19.3k Golang : Close channel after ticker stopped example
+6k Golang : Test input string for unicode example
+5.5k Golang : ROT32768 (rotate by 0x80) UTF-8 strings example
+6.9k Golang : Gorrila mux.Vars() function example
+18.4k Unmarshal/Load CSV record into struct in Go
+13.6k Golang : Compress and decompress file with compress/flate example
+22.6k Golang : Calculate time different
+11.7k Golang : Convert a rune to unicode style string \u
+27k Golang : Convert CSV data to JSON format and save to file
+12.5k Golang : Convert int(year) to time.Time type