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
+9.2k Golang : Extract or copy items from map based on value
+6.8k Golang : Levenshtein distance example
+31.4k Golang : Convert an image file to []byte
+18.9k Golang : Calculate entire request body length during run time
+8.7k Golang : Build and compile multiple source files
+20.8k Golang : Clean up null characters from input data
+11.1k Golang : Byte format example
+13.3k Golang : Set image canvas or background to transparent
+9.9k Golang : How to get quoted string into another string?
+10.9k Google Maps URL parameters configuration
+14k Golang : Recombine chunked files example
+7k Golang : Fixing Gorilla mux http.FileServer() 404 problem