How to crop and upload image in ASPNET core using Jcrop?
Jcrop Plugin is an efficient way of adding image cropping functionality to our web application.
I was searching for an efficient way to Crop the image in my web application until I came along with Jcrop. In this article, I will show you how I implemented the Cropping functionality in my ASPNET core web application.
I hope it will be a great help for anyone who has the same problem.
Let’s get started by creating a new .net core web Application. I assume you know how to do it. If not Follow this link.
You can find this project on GitHub.
So, Create the input button in on the required view. After the image file is Selected and Cropped it appears in the image tag.
<div class="container">
<input type="file" class="img" id="imgInp" name="files" accept="image/*">
<div class="col-lg-6">
<img src="" class="img img-responsive img-rounded" />
</div>
</div>
Download the JCrop plugin. Click here.
Provide the link to Jcrop in View.
<link href="~/css/jquery.Jcrop.min.css" rel="stylesheet" />
<script src="~/js/jcrop/jquery.Jcrop.min.js"></script>
Create the popup model in view So that user can Crop the image.
My home View Code looks like this.
@section css{
<link href="~/css/jquery.Jcrop.min.css" rel="stylesheet" />
}
<div class="container">
<input type="file" class="img" id="imgInp" name="files" accept="image/*">
<div class="col-lg-6">
<img src="" class="img img-responsive img-rounded" />
</div>
</div>
<div class="modal" id="myprofilecrop" tabindex="-1" role="dialog" aria-labelledby="cropmodel">
<div class="modal-dialog" role="document">
<div id="loadingDiv" class="hide">
<div>
<h7>Please wait...</h7>
</div>
</div>
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" arial-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title text-center" id="cropmodel">Update Profile Picture</h4>
</div>
<form id="formimg">
<div id="loader" class="text-center">Loading...</div>
<div class="modal-body text-center">
<div id="views" class="m-t-15"></div>
</div>
<div class="modal-footer">
<button id="cropbutton" class="btn btn-primary" type="submit">Save</button>
<button id="rotatebutton" class="btn btn-default" type="button">Rotate</button>
</div>
</form>
</div>
</div>
</div>
@section Scripts{
<script src="~/js/jcrop/jquery.Jcrop.min.js"></script>
<script src="~/js/ImageCrop.js"></script>
}
Or Just Copy From GitHub.
I am not using the “jquery.Jcrop.js” of Jcrop but I created my own custom js(ImageCrop.js) by taking some of the from JCrop as the reference in order to meet my requirement. Here is the full imagecrop.js code
$(document).ready(function () {
function b64toBlob (b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, { type: contentType }, { fileName: "ppp.JPG" });
return blob;
}
function FileUploader (fileUpload) {
$("#submit").attr('disabled', true);
var fileformat;
var imageonly = fileUpload.split(';');
var contenttype = imageonly[0].split(':')[1];
fileformat = contenttype.split('/')[1];
var realdata = imageonly[1].split(',')[1];
var blob = b64toBlob(realdata, contenttype);
var filename = "pic." + fileformat;
var data = new FormData();
data.append("UploadLocation", "\\Images\\UserPhoto\\"); ///location
data.append("FileInitials", "userprofile"); ///create files name with start
data.append(filename, blob, filename);
$.ajax({
type: "POST",
url: `${location.protocol}//${window.location.host}/home/UploadFilesWihtLocation`,
contentType: false,
processData: false,
data: data,
success: function (path) {
$("#myprofilecrop").modal('hide');
path = path.toString();
$(".img").attr('src', path);
alert(path);
}
});
}
var crop_max_width = 400;
var crop_max_height = 400;
var jcrop_api;
var canvas;
var context;
var image;
var prefsize;
function loadImage(input) {
var isImage = input.value;
isImage = isImage.split('.');
isImage = isImage[isImage.length - 1];
if (isImage === 'png' || isImage === 'jpg' || isImage === 'jpeg') {
if (input.files && input.files[0]) {
var reader = new FileReader();
canvas = null;
reader.onload = function (e) {
image = new Image();
image.onload = validateImage;
image.src = e.target.result;
};
reader.readAsDataURL(input.files[0]);
$("#loader").addClass("hide");
}
}
else {
alert("something wrong.");
}
}
function validateImage() {
if (canvas != null) {
image = new Image();
image.onload = restartJcrop;
image.src = canvas.toDataURL('image/png');
} else restartJcrop();
}
function restartJcrop() {
if (jcrop_api != null) {
jcrop_api.destroy();
}
$("#views").empty();
$("#views").append("<canvas id=\"canvas\">");
canvas = $("#canvas")[0];
context = canvas.getContext("2d");
canvas.width = image.width;
canvas.height = image.height;
context.drawImage(image, 0, 0);
$("#canvas").Jcrop({
onSelect: selectcanvas,
onRelease: clearcanvas,
boxWidth: crop_max_width,
boxHeight: crop_max_height
}, function () {
jcrop_api = this;
});
clearcanvas();
}
function clearcanvas() {
prefsize = {
x: 0,
y: 0,
w: canvas.width,
h: canvas.height
};
selectcanvas(null);
}
function selectcanvas(coords) {
if (coords != null) {
prefsize = {
x: Math.round(coords.x),
y: Math.round(coords.y),
w: Math.round(coords.w),
h: Math.round(coords.h)
};
}
else {
jcrop_api.focus();
jcrop_api.animateTo([50, 50, 100, 100]);
jcrop_api.setOptions({
minSize: [150, 150],
aspectRatio: 4 / 4
});
jcrop_api.focus();
$('#canvas').Jcrop({
}, function () {
jcrop_api = this;
jcrop_api.animateTo([50, 50, 100, 100]);
// Setup and dipslay the interface for "enabled"
$('#can_click,#can_move,#can_size').attr('checked', 'checked');
$('#ar_lock,#size_lock,#bg_swap').attr('checked', false);
$('.requiresjcrop').show();
});
}
}
function applyCrop() {
canvas.width = prefsize.w;
canvas.height = prefsize.h;
context.drawImage(image, prefsize.x, prefsize.y, prefsize.w, prefsize.h, 0, 0, canvas.width, canvas.height);
validateImage();
}
function applyScale(scale) {
if (scale == 1) return;
canvas.width = canvas.width * scale;
canvas.height = canvas.height * scale;
context.drawImage(image, 0, 0, canvas.width, canvas.height);
validateImage();
}
function applyRotate() {
canvas.width = image.height;
canvas.height = image.width;
context.clearRect(0, 0, canvas.width, canvas.height);
context.translate(image.height / 2, image.width / 2);
context.rotate(Math.PI / 2);
context.drawImage(image, -image.width / 2, -image.height / 2);
validateImage();
}
function applyHflip() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.translate(image.width, 0);
context.scale(-1, 1);
context.drawImage(image, 0, 0);
validateImage();
}
function applyVflip() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.translate(0, image.height);
context.scale(1, -1);
context.drawImage(image, 0, 0);
validateImage();
}
$(".img").change(function () {
$("#myprofilecrop").modal('show');
loadImage(this);
});
$("#cropbutton").click(function (e) {
applyCrop();
$("#submit").attr('disabled', false);
});
$("#scalebutton").click(function (e) {
var scale = prompt("Scale Factor:", "1");
applyScale(scale);
});
$("#rotatebutton").click(function (e) {
applyRotate();
});
$("#hflipbutton").click(function (e) {
applyHflip();
});
$("#vflipbutton").click(function (e) {
applyVflip();
});
$("#formimg").submit(function (e) {
e.preventDefault();
FileUploader(canvas.toDataURL('image/png'));
});
});
I am going to explain the overall process of Cropping and uploading the Image.
Below I have to Provide the function which executes when the user clicks on the input button. And shows the image in the pop-up model.
$(".img").change(function () {
$("#myprofilecrop").modal('show');
loadImage(this);
});
function loadImage(input) {
var isImage = input.value;
isImage = isImage.split('.');
isImage = isImage[isImage.length - 1];
if (isImage === 'png' || isImage === 'jpg' || isImage === 'jpeg') {
if (input.files && input.files[0]) {
var reader = new FileReader();
canvas = null;
reader.onload = function (e) {
image = new Image();
image.onload = validateImage;
image.src = e.target.result;
};
reader.readAsDataURL(input.files[0]);
$("#loader").addClass("hide");
}
}
else {
alert("something wrong.");
}
}
After image loaded into the popup model where you can crop the image and click on save where all the magic is done by Jcrop.
Now Cropped Image needs to be uploaded to the server. For this, I have provided the js code below. Where we have two functions:
b64toBlob: This function Coverts the base64 string to Blob type.
function b64toBlob (b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, { type: contentType }, { fileName: "ppp.JPG" });
return blob;
}
FileUploader: we Get the base64 string of cropped image as a parameter which converted to Blob Data type and Sends to server Using FormData()
function FileUploader (fileUpload) {
$("#submit").attr('disabled', true);
var fileformat;
var imageonly = fileUpload.split(';');
var contenttype = imageonly[0].split(':')[1];
fileformat = contenttype.split('/')[1];
var realdata = imageonly[1].split(',')[1];
var blob = b64toBlob(realdata, contenttype); //
var filename = "pic." + fileformat;
var data = new FormData(); //create object of FormData
data.append("UploadLocation", "\\Images\\UserPhoto\\"); ///location
data.append("FileInitials", "userprofile"); ///create files name with start
data.append(filename, blob, filename);
$.ajax({
type: "POST",
url: `${location.protocol}//${window.location.host}/home/UploadFilesWihtLocation`,
contentType: false,
processData: false,
data: data,
success: function (path) {
$("#myprofilecrop").modal('hide');
path = path.toString();
$(".img").attr('src', path);
alert(path);
}
});
}
Now Create Controller in Server which accepts the image coming from FormData.
using System;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Hosting;
using System.IO;
using Microsoft.AspNetCore.Http;
namespace ImageCrop.Controllers
{
public class HomeController : Controller
{
private readonly IHostingEnvironment _hostingEnv;
public HomeController(IHostingEnvironment hostingEnv)
{
_hostingEnv = hostingEnv;
}
public IActionResult ImageCrop()
{
return View();
}
private bool IsValidExtension(IFormFile filename)
{
bool isValid = false;
Char delimiter = '.';
string fileExtension;
string[] imgTypes = new string[] { "png", "jpg", "gif", "jpeg" };
string[] documentsTypes = new string[] { "doc", "docx", "xls", "xlsx", "pdf", "ppt", "pptx" };
string[] collTypes = new string[] { "zip", "rar", "tar" };
string[] VideoTypes = new string[] { "mp4", "flv", "mkv", "3gp" };
fileExtension = filename.FileName.Split(delimiter).Last();
// fileExtension = substrings[substrings.Length - 1].ToString();
int fileType = 0;
if (imgTypes.Contains(fileExtension.ToLower()))
{
fileType = 1;
}
else if (documentsTypes.Contains(fileExtension.ToLower()))
{
fileType = 2;
}
else if (collTypes.Contains(fileExtension.ToLower()))
{
fileType = 3;
}
else if (VideoTypes.Contains(fileExtension.ToLower()))
{
fileType = 4;
}
switch (fileType)
{
case 1:
if (imgTypes.Contains(fileExtension.ToLower()))
{
isValid = true;
}
break;
case 2:
if (documentsTypes.Contains(fileExtension.ToLower()))
{
isValid = false;
}
break;
case 3:
if (collTypes.Contains(fileExtension.ToLower()))
{
isValid = false;
}
break;
case 4:
if (VideoTypes.Contains(fileExtension.ToLower()))
{
isValid = true;
}
break;
default:
isValid = false;
break;
}
return isValid;
}
private string GetNewFileName(string filenamestart, IFormFile filename)
{
Char delimiter = '.';
string fileExtension;
string strFileName = string.Empty;
strFileName = DateTime.Now.ToString().
Replace(" ", string.Empty).
Replace("/", "-").Replace(":", "-");
fileExtension = filename.FileName.Split(delimiter).Last();
Random ran = new Random();
strFileName = $"{ filenamestart}_{ran.Next(0, 100)}_{strFileName}.{fileExtension}";
return strFileName;
}
public IActionResult UploadFilesWihtLocation()
{
string hoststr = _hostingEnv.WebRootPath;
string[] strFileNames;
///string url = "";
try
{
long size = 0;
var files = Request.Form.Files;
strFileNames = new string[files.Count];
string fileLocation = Request.Form["UploadLocation"].ToString();
//string[] path = fileLocation.Split("/");
string fileInitals = Request.Form["FileInitials"].ToString();
int i = 0;
string[] path = fileLocation.Split("\\");
if (!Directory.Exists(hoststr + "\\" + path[1]))
{
Directory.CreateDirectory(hoststr + "\\" + path[1]);
Directory.CreateDirectory(hoststr + "\\" + path[1] + "\\" + path[2]);
}
else if (!Directory.Exists(hoststr + fileLocation))
{
Directory.CreateDirectory(hoststr + "\\" + path[1] + "\\" + path[2]);
}
foreach (var file in files)
{
if (IsValidExtension(file))
{
var filename = GetNewFileName(fileInitals + i, file);
strFileNames[i] = fileLocation + filename;
string fullpath = hoststr + fileLocation + $@"\{filename}";
size += file.Length;
using (FileStream fs = System.IO.File.Create(fullpath))
{
file.CopyTo(fs);
fs.Flush();
fs.Close();
}
}
else
{
strFileNames = new string[1];
strFileNames[0] = "Invalid File";
}
i = i + 1;
}
}
catch (Exception ex)
{
strFileNames = new string[1];
strFileNames[0] = ex.Message;
}
return Json(strFileNames);
}
}
}
Here is the Screen Shot of Image Crop Process.
Also read
HOW TO EXTRACT TEXT FROM IMAGE USING JAVASCRIPT (OCR with Tesseract.js)?
How to read appSettings JSON from Class Library in ASP.NET Core