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:

  1. Download chi package by go get -u github.com/go-chi/chi

  2. Create a directory named cropped

  3. 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