This past week, I needed to be able to upload an image in my application to the server as a file so that I could crop it and upload it.
Now, uploading an image that you pulled up using the file upload control is relatively straight forward. But, in our case, the image we want to be able to upload didn’t always come from the user’s file system. This causes two problems.
First, you can’t crop an image you retrieved from a different URL using the HTML Canvas because of Cross Origin restrictions and second, you can’t upload the file using the standard file upload mechanism because you didn’t get it from the file system.
Image to Data without Canvas
Now, the standard way of converting an Image to a data URL is to
- create a new Image,
- set the onload event handler to a function
- set the Image src attribute to the file
- in the onload function,
- draw the image onto the canvas
- call canvas.toDataUrl(mimeType) to get the data url.
It is pretty trivial code:
But, the trouble starts when you use a URL that doesn’t originate from the file system, or the same domain as the application your are running.
The trick is to read the image using an XMLHttpRequest for foriegn URLs and then use a FileReader object and call readAsDataURL passing the result of the XMLHttpRequest.read.
Now we can put the image using the data URL on the canvas and the canvas doesn’t know we got it from a foreign URL any more so we no longer get a cross origin URL.
The entry point for this code is on line 27. You see that if we are working with a File, we just use the FileReader directly. But if we are using http, we go through the XMLHttpRequest.
Fake File Upload
The only problem with this is that now we no longer have the file point, so if we want to upload the file, as a file, to the server we have come up with some way of creating a fake file object. And believe it or not, that is a lot easier than you might think.
You see, a File object is just a kind of Blob object. So, all we really need to do is to create a Blob. But, we have one additional issue. Our image is in base 64 and we need to convert it to a binary byte array.
You can use the resulting “File” anywhere you would use a File you had retrieved from the file system.
Upload via Http
The last bit of this is that we need to upload this via the Http service. This is going to be harder to show with code because it depends on what you need to do.
In my case, I needed to just upload the file, so the post was pretty straight forward. I used an Http.post() and passed the returned “file” as the data parameter.
But, you may need to upload it by wrapping the file in a Form object and specifying varying headers.
Other post in Angular 2
- Angular 2 – First Impressions [Compared to Angular 1] - February 25th, 2016
- Angular 2 Thoughts - October 4th, 2016
- Getting Started with Angular 2 - October 25th, 2016
- Unit Testing an Angular 2 CLI Project - November 22nd, 2016
- Adding Client Side Routing to Angular 2 - November 29th, 2016
- Angular 2 Lazy Loading - December 6th, 2016
- Reasons to use RxJS Today - December 13th, 2016
- Dissecting Angular 2 Modules - December 20th, 2016
- Awesome Angular2 Architecture Options and Opinions - December 27th, 2016
- What if Everything Was Immutable? - January 10th, 2017
- Amazing Angular2 DOM Tips, Tricks, and Warnings - January 17th, 2017
- Secrets to Styling Angular2 - January 31st, 2017
- Jedi Angular 2 Tips and Tricks - March 28th, 2017
- Unit Testing Angular(2+) with JSDOM - April 4th, 2017
- More Control with Angular Flex Layout - April 11th, 2017
- Angular(2+) Model Driven Forms Are Superior - April 18th, 2017
- Dynamically Add Components in Angular - April 25th, 2017
- Using Real World NgRX - May 9th, 2017
- Functional Reactive Angular Revealed - May 30th, 2017
- NgRX/Store Coding Sanity Epiphany - June 6th, 2017
- Real World RxJS Marble Testing Revealed - June 13th, 2017
- How to Organize an Angular Application - June 20th, 2017
- Upload an Image as a File in Angular - July 4th, 2017
- How to Implement Angular 2+ Routing - July 18th, 2017
- TypeScript Basics for Angular Developers - August 1st, 2017
- Angular Observable Secrets Revealed - August 8th, 2017
- How to Upgrade NgRX to 4.x - August 15th, 2017
- Model View Presenter, Angular, and Testing - August 29th, 2017
- This One Tweak Improved my Angular Code - September 12th, 2017
- Upgrade to Angular from... - September 26th, 2017
- Using NgRX to Cleanly Aggregate Data - October 3rd, 2017
- NgRX 4 Actions - Class vs Object Literal - October 10th, 2017
- Implementing NgRX 4 - October 24th, 2017
- What I Learned Using Angular Material - October 31st, 2017
- Angular Ionic and Angular CLI - November 14th, 2017
- How to Really Screw Up an Angular Project - December 12th, 2017
- Angular Cross Field Validation - December 19th, 2017
- Attaching an Angular Child Component's Form to a Parent - January 2nd, 2018
- Why more Angular Modules are Better than One - January 16th, 2018
- Property Based Testing in Angular with jsVerify - February 6th, 2018