Upload Image and Convert to Data URL in Angular

2 minute read

I have a little application that I wanted the user to be able to upload their own images, and be able to store them in a json format so that the configuration can be stored somewhere for example storing it in the browsers localstorage.  To do this, I wanted to be able to load the image into a data url which is in a string format, making it easier to store.  I’m using Angular, but the basic loading of an image is using the JavaScript FileReader class, and so with some minor tweaks you should be able to use with other JavaScript frameworks.

First I need a way to upload the image, this is done using the html input control.

    <input 
    	type="file"
    	accept="image/png, image/jpeg"
    />

Now I need to be able to do something when the user chooses a file, for this I’ll add an Angular function to handle the input control’s on change event.

    handleFileUpload(files: FileList){
    	// Just logging the selected files for now
    	console.log(files);
    }
	<input
		type="file"
		accept="image/png, image/jpeg"
		(change)="handleFileInput($event.target.files)"
	/>
Added the change event handler

To actually load the image into a data url which looks like this: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg== I will use the JavaScript FileReader class.  This needs to have an onload callback set to do something with the file once it has been loaded.

    handleFileUpload(files: FileList){
    	const fileReader = new FileReader();
    	// Set the onload callback to do something with the loaded file
    	fileReader.onload = (e) =>{
    		// just log the data url
    		console.log(fileReader.result.toString());
    	};
    	// Trigger the file load
    	fileReader.readAsDataURL(files.item(0));
    }

To display the image I will need to store the data url somewhere, as I want to be able to have several images uploaded. For this I will use an array of strings.

imageList: string[] = [];

handleFileUpload(files: FileList){
	// A list of images to be displayed
	const fileReader = new FileReader();
    // Set the onload callback to do something with the loaded file
    fileReader.onload = (e) =&gt;{
    	// Add the newly loaded image data url to the imageList
    	this.imageList.push(fileReader.result.toString());
    };
    // Trigger the file load
    fileReader.readAsDataURL(files.item(0));
}
Changed the onload callback to push the image to an imageList array

I just need to have an image tag for each image setting the source to the stored value in the array.  So I can just iterate over the array using an ngFor, creating an img html element for each.

<img *ngFor="let image of imageList" [src]="image" />
Simple angular for loop over each of the images in the imageList

Unsafe Url

There have been a few situations where I have run into an Angular error complaining about unsafe urls. This has been mostly when hard coding a data url in my code for testing purposes, but there is a way around it.  You just need to use the Angular DomSanitizer to mark the url safe. However, that then returns a SafeUrl instead of a string which typescript will complain about when trying to add it to your imageList.  I built this simple little method that takes a data url and marks it safe, and then converts back to a string which fixed the problem for me anytime it arose.

    markDataUrlSafe(dataUrl: string): string {
    	// Marks the url safe
        const safeUrl: SafeUrl = this.domSanitizer.bypassSecurityTrustUrl(dataUrl);
        // Sanitizes the passed in value, returning a url string
        const url: string = this.domSanitizer.sanitize(SecurityContext.URL, safeUrl);
        return url;
      }