Download Image as File in Typescript

Download image as file in typescript

Considering you tagged this question as an Angular question, I suppose that for some reason, you dont want to expose an endpoint that serves the image in raw format, then create a link to it.

If you're looking for an Angular specific solution, there is none. However, there is a pure javascript solution described below. It can be used to preload your image so your user will be able to get the image instantly when needed.

let byteCharacters = atob('your base64 data');

let byteNumbers = new Array(byteCharacters.length);
for (var i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}

let byteArray = new Uint8Array(byteNumbers);

let blob = new Blob([byteArray], {"type": "image/jpeg"});

if(navigator.msSaveBlob){
let filename = 'picture';
navigator.msSaveBlob(blob, filename);
} else {
let link = document.createElement("a");

link.href = URL.createObjectURL(blob);

link.setAttribute('visibility','hidden');
link.download = 'picture';

document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}

You can test here : https://jsfiddle.net/pxm0eyzs/2/

Downloading images with node.js

I'd suggest using the request module. Downloading a file is as simple as the following code:

var fs = require('fs'),
request = require('request');

var download = function(uri, filename, callback){
request.head(uri, function(err, res, body){
console.log('content-type:', res.headers['content-type']);
console.log('content-length:', res.headers['content-length']);

request(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
});
};

download('https://www.google.com/images/srpr/logo3w.png', 'google.png', function(){
console.log('done');
});

How to convert image source into a JavaScript File object

Convert your image src https://cdn.shopify.com/s/files/1/0234/8017/2591/products/young-man-in-bright-fashion_925x_f7029e2b-80f0-4a40-a87b-834b9a283c39.jpg into Base64 ULR format and than convert Base64 URL into javaScript File Object.

***Here is the code for converting "image source" (url) to "Base64".***

let url = 'https://cdn.shopify.com/s/files/1/0234/8017/2591/products/young-man-in-bright-fashion_925x_f7029e2b-80f0-4a40-a87b-834b9a283c39.jpg'
const toDataURL = url => fetch(url)
.then(response => response.blob())
.then(blob => new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onloadend = () => resolve(reader.result)
reader.onerror = reject
reader.readAsDataURL(blob)
}))


***Here is code for converting "Base64" to javascript "File Object".***

function dataURLtoFile(dataurl, filename) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {type:mime});
}


*** Calling both function ***

toDataURL(url)
.then(dataUrl => {
console.log('Here is Base64 Url', dataUrl)
var fileData = dataURLtoFile(dataUrl, "imageName.jpg");
console.log("Here is JavaScript File Object",fileData)
fileArr.push(fileData)
})

Unable to download image as zip file using angular 6

I'm a little late, but this code will use your image array and create your GET requests. After that it will perform all requests and the responses will be added to your zip file and then downloaded.

I included two ways to download the file if you don't like to use the fileSaver. Pick whichever you prefer.

EDIT:

If you are using an old version of rxjs you'll have to import forkJoin in a different way, consult the rxjs documentation.
Also be sure that your backend allows the download of files, otherwise you'll have CORS errors.

forkJoin Documentation

app.component.ts

import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { forkJoin } from "rxjs";
import { saveAs } from "file-saver";
import * as JSZip from 'jszip';

@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {

data = [
'http://yoururl/file.png',
'http://yoururl/file2.png'
];

getRequests = [];

constructor(private _http: HttpClient) {}

download() {
this.createGetRequets(this.data);

forkJoin(...this.getRequests)
.subscribe((res) => {
const zip = new JSZip();

res.forEach((f, i) => {
zip.file(`image${i}.png`, f);
});

/* With file saver */
// zip
// .generateAsync({ type: 'blob' })
// .then(blob => saveAs(blob, 'image.zip'));

/* Without file saver */
zip
.generateAsync({ type: 'blob' })
.then(blob => {
const a: any = document.createElement('a');
document.body.appendChild(a);

a.style = 'display: none';
const url = window.URL.createObjectURL(blob);
a.href = url;
a.download = 'image.zip';
a.click();
window.URL.revokeObjectURL(url);
});
});
}

private createGetRequets(data: string[]) {
data.forEach(url => this.getRequests.push(this._http.get(url, { responseType: 'blob' })));
}
}

app.component.html

<div style="text-align:center">
<button (click)="download()">Download</button>
</div>

I also had to include the path to jszip in my tsconfig.json. Depending on your version of angular you don't have to do this. Inside "compilerOptions" add following:

tsconfig.json

"paths": {
"jszip": [
"node_modules/jszip/dist/jszip.min.js"
]
}

UPDATE:

Here is a solution with the old HttpModule, I tried it out and it works. I would suggest changing to the new HttpClientModule if possible.

UPDATE2:

Like I said in the comments, you can change the file extension when saving the file to handle different file types. This is an example and you can easily expand this solution.

app.component.ts

import { Component } from "@angular/core";
import { Http, ResponseContentType } from "@angular/http"; // Different Import
import { forkJoin } from "rxjs";
import { saveAs } from "file-saver";
import * as JSZip from "jszip";

@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {

/*
UPDATE 2
Create a Type map to handle differnet file types
*/
readonly MIME_TYPE_MAP = {
"image/png": "png",
"image/jpeg": "jpg",
"image/jpg": "jpg",
"image/gif": "gif"
};

data = [
"http://url/file.png",
"http://url/file.jpeg",
"http://url/file.gif"
];

getRequests = [];

constructor(private _http: Http) {} // Different Constructor

download() {
this.createGetRequets(this.data);

forkJoin(...this.getRequests).subscribe(res => {
const zip = new JSZip();
console.log(res);
/*
The return value is different when using the HttpModule.
Now you need do access the body of the response with ._body,
as you can see inside the forEach loop => f._body
*/
let fileExt: String; // UPDATE 2

res.forEach((f, i) => {
fileExt = this.MIME_TYPE_MAP[f._body.type]; // UPDATE 2, retrieve type from the response.
zip.file(`image${i}.${fileExt}`, f._body); // UPDATE 2, append the file extension when saving
});

zip
.generateAsync({ type: "blob" })
.then(blob => saveAs(blob, "image.zip"));
});
}

private createGetRequets(data: string[]) {
/*
Change your responseType to ResponseContentType.Blob
*/
data.forEach(url =>
this.getRequests.push(
this._http.get(url, { responseType: ResponseContentType.Blob })
)
);
}
}

UPDATE3:

Solution which extracts the file name from the URL, this way the file type is not needed:

import { Component } from "@angular/core";
import { Http, ResponseContentType } from "@angular/http";
import { forkJoin } from "rxjs";
import { saveAs } from "file-saver";
import * as JSZip from "jszip";

@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
data = ["http://url/file.png", "http://url/file.jpg", "http://url/file.gif"];

getRequests = [];

constructor(private _http: Http) {}

download() {
this.createGetRequets(this.data);

forkJoin(...this.getRequests).subscribe(res => {
const zip = new JSZip();
let fileName: String;

res.forEach((f, i) => {
fileName = f.url.substring(f.url.lastIndexOf("/") + 1); // extract filename from the response
zip.file(`${fileName}`, f._body); // use it as name, this way we don't need the file type anymore
});

zip
.generateAsync({ type: "blob" })
.then(blob => saveAs(blob, "image.zip"));
});
}

private createGetRequets(data: string[]) {
data.forEach(url =>
this.getRequests.push(
this._http.get(url, { responseType: ResponseContentType.Blob })
)
);
}
}


Related Topics



Leave a reply



Submit