|
| 1 | +--- |
| 2 | +title: Rezise Image Before Upload |
| 3 | +description: How to resize an image chosen by the user before it is uploaded to the server |
| 4 | +type: how-to |
| 5 | +page_title: Rezise image before upload |
| 6 | +slug: upload-resize-image-before-upload |
| 7 | +position: |
| 8 | +tags: upload,resize,image,client,before upload |
| 9 | +ticketid: 1381676 |
| 10 | +res_type: kb |
| 11 | +--- |
| 12 | + |
| 13 | +## Environment |
| 14 | +<table> |
| 15 | + <tr> |
| 16 | + <td>Product</td> |
| 17 | + <td>Upload for ASP.NET Core</td> |
| 18 | + </tr> |
| 19 | +</table> |
| 20 | + |
| 21 | + |
| 22 | +## Description |
| 23 | +I am using the upload widget to upload photos taken from a phone and really need to resize them before the upload to reduce the amount of time it take to upload the photo. Is there a way to resize the photo with JavaScript with the Telerik Upload wdiget? |
| 24 | + |
| 25 | +## Solution |
| 26 | + |
| 27 | +Client-side resizing of images can be achieved through `<canvas>` and `Image` elements that can be used to fetch a `blob` that will be part of the POST data to the server. To use this approach with the Kendo Upload widget, you need to: |
| 28 | + |
| 29 | +1. use its [async mode](https://demos.telerik.com/kendo-ui/upload/async) |
| 30 | +1. disable the [automatic upload](https://docs.telerik.com/kendo-ui/api/javascript/ui/upload/configuration/async.autoupload) |
| 31 | +1. hook to the [select](https://docs.telerik.com/kendo-ui/api/javascript/ui/upload/events/select) event |
| 32 | +1. use a timetout to start the resizing logic to prevent errors with the built-in upload logic |
| 33 | +1. when you have the resized blob, create a `File` from it and replace the data in the Kendo Upload widget with the new data (file and its size) |
| 34 | +1. once resizing is done, initiate an upload through the [upload method](https://docs.telerik.com/kendo-ui/api/javascript/ui/upload/methods/upload) so the files reach the controller |
| 35 | + |
| 36 | +Here is an example: |
| 37 | + |
| 38 | +```CSHTML |
| 39 | +@(Html.Kendo().Upload() |
| 40 | + .Name("files") |
| 41 | + .Events(ev => ev.Select("fileSelectHandler")) |
| 42 | + .Async(a => a |
| 43 | + .Save("SaveAsync", "ResizeFile") |
| 44 | + .AutoUpload(false) |
| 45 | + ) |
| 46 | +) |
| 47 | +
|
| 48 | +<script> |
| 49 | + function fileSelectHandler(e) { |
| 50 | + //timeout so we don't break the built-in features and throw errors |
| 51 | + //note: the file size shown by the upload widget will, therefore, be wrong |
| 52 | + //consider using a template to hide it: https://demos.telerik.com/aspnet-mvc/upload/templates |
| 53 | + setTimeout(function () { |
| 54 | + triggerResizing(); |
| 55 | + }); |
| 56 | + } |
| 57 | +
|
| 58 | + function triggerResizing() { |
| 59 | + var files = $("#files").data("kendoUpload").getFiles(); |
| 60 | + for (var i = 0; i < files.length; i++) { |
| 61 | + files[i] = resizeFile(files[i]); |
| 62 | + } |
| 63 | +
|
| 64 | + //consider devising a better way to monitor the progress of the resizing operations |
| 65 | + //so you can trigger upload when you are sure they are done |
| 66 | + //for example, keep a hash table with results per file and loop it in an interval |
| 67 | + setTimeout(function () { |
| 68 | + $("#files").data("kendoUpload").upload(); |
| 69 | + }, 300); |
| 70 | + } |
| 71 | +
|
| 72 | + function resizeFile(data) { |
| 73 | + //resizing logic. Note that it is not extensively tested and may have quirks |
| 74 | + var uploadFile = data.rawFile; |
| 75 | + var img = new Image(); |
| 76 | + var canvas = document.createElement("canvas"); |
| 77 | + var reader = new FileReader(); |
| 78 | + reader.onload = function (e) { |
| 79 | + img.onload = function () { |
| 80 | + var ctx = canvas.getContext("2d"); |
| 81 | + ctx.drawImage(img, 0, 0); |
| 82 | +
|
| 83 | + //image constraints |
| 84 | + var MAX_WIDTH = 400; |
| 85 | + var MAX_HEIGHT = 300; |
| 86 | + var width = img.width; |
| 87 | + var height = img.height; |
| 88 | +
|
| 89 | + if (width > height) { |
| 90 | + if (width > MAX_WIDTH) { |
| 91 | + height *= MAX_WIDTH / width; |
| 92 | + width = MAX_WIDTH; |
| 93 | + } |
| 94 | + } else { |
| 95 | + if (height > MAX_HEIGHT) { |
| 96 | + width *= MAX_HEIGHT / height; |
| 97 | + height = MAX_HEIGHT; |
| 98 | + } |
| 99 | + } |
| 100 | + canvas.width = width; |
| 101 | + canvas.height = height; |
| 102 | + //end of image constraints |
| 103 | +
|
| 104 | + var ctx = canvas.getContext("2d"); |
| 105 | + ctx.drawImage(img, 0, 0, width, height); |
| 106 | +
|
| 107 | + canvas.toBlob(function (blob) { |
| 108 | + blob.lastModifiedDate = new Date(); |
| 109 | + blob.name = data.name; |
| 110 | + //replace original files with the new files |
| 111 | + data.size = blob.size; |
| 112 | + data.rawFile = new File([blob], data.name); |
| 113 | +
|
| 114 | + return data; |
| 115 | + }, 'image/png', 1); |
| 116 | + } |
| 117 | + img.src = e.target.result; |
| 118 | + } |
| 119 | + reader.readAsDataURL(uploadFile); |
| 120 | + } |
| 121 | +</script> |
| 122 | +``` |
| 123 | + |
| 124 | +There is nothing special in the controller, it simply has to save the file. Of course, you may want to add server resizing logic to ensure the file matches the project requirements. |
| 125 | + |
| 126 | +```C# |
| 127 | +public class ResizeFileController : Controller |
| 128 | +{ |
| 129 | + //needed to get the application root path |
| 130 | + private IHostingEnvironment _env; |
| 131 | + public ResizeFileController(IHostingEnvironment env) |
| 132 | + { |
| 133 | + _env = env; |
| 134 | + } |
| 135 | + |
| 136 | + public IActionResult Index() |
| 137 | + { |
| 138 | + return View(); |
| 139 | + } |
| 140 | + |
| 141 | + public async Task<ActionResult> SaveAsync(IEnumerable<IFormFile> files) |
| 142 | + { |
| 143 | + if (files != null) |
| 144 | + { |
| 145 | + foreach (var file in files) |
| 146 | + { |
| 147 | + var fileContent = ContentDispositionHeaderValue.Parse(file.ContentDisposition); |
| 148 | + |
| 149 | + // Some browsers send file names with full path. |
| 150 | + // We are only interested in the file name. |
| 151 | + var fileName = Path.GetFileName(fileContent.FileName.ToString().Trim('"')); |
| 152 | + |
| 153 | + //for portability, this will be in the application folder. |
| 154 | + //In a common case, you may want to use the wwwroot folder through WebRootPath |
| 155 | + //or some other location on your hard drive |
| 156 | + var appRoot = _env.ContentRootPath; |
| 157 | + var physicalPath = Path.Combine(appRoot, "SavedFiles", fileName); |
| 158 | + |
| 159 | + using (var fileStream = new FileStream(physicalPath, FileMode.Create)) |
| 160 | + { |
| 161 | + //implement server validatoin before saving, this is a rudimentary example |
| 162 | + await file.CopyToAsync(fileStream); |
| 163 | + } |
| 164 | + } |
| 165 | + } |
| 166 | + |
| 167 | + // Return an empty string to signify success |
| 168 | + return Content(""); |
| 169 | + } |
| 170 | +} |
| 171 | +``` |
| 172 | + |
| 173 | +## Notes |
| 174 | + |
| 175 | +* The upload widget does not offer such a feature out of the box, and Telerik cannot guarantee it will not have side effects or issues (especially with a wider variety of images users can upload). |
| 176 | +* It is important that the automatic upload is disabled because resizing images on the client is asynchronous. |
| 177 | +* You may want to refactor the code to fit your coding standards. A few comments are available that denote likely areas that can get improved. |
| 178 | + |
0 commit comments