最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Unable to download image as zip file using angular 6 - Stack Overflow

programmeradmin0浏览0评论

here i am having below dynamic data like this

data =  [
  ".jpg&text=test", 
  ".jpg&text=testOne",
  ".png&text=testTwo"
]

on button click i want to get the all the images from those url's and save it as zip

Issue : when ever i am able download the file as zip and try to extract it i am getting error as could not open image.zip as archieve and if i save as single image also the image is not opening up and is there any way to store the

below is my code

downloadImageData(){


  var blob = new Blob([this.data], { type:  'application/zip'' });

  FileSaver.saveAs(blob,'image.zip');

}

here i am having both png & jpg and various type of data so what ever data the links will get has to downloaded as zip file is there any approach for angular 5+. i am using filesave angular package also

JS ZIP _body resp

By using the http module im getting the below data [

  {
    "_body": {

    },
    "status": 200,
    "ok": true,
    "statusText": "OK",
    "headers": {
      "date": [
        "Sun",
        " 25 Nov 2018 12:18:47 GMT"
      ],
      "cache-control": [
        "public",
        " max-age=43200"
      ],
      "expires": [
        "Mon",
        " 26 Nov 2018 00:18:47 GMT"
      ],
      "content-disposition": [
        "attachment; filename=2B.JPG"
      ],
      "content-length": [
        "40649"
      ],
      "server": [
        "Werkzeug/0.14.1 Python/2.7.13"
      ],
      "content-type": [
        "image/jpg"
      ]
    },
    "type": 2,
    "url": "http://some url"
  }
]

here i am having below dynamic data like this

data =  [
  "https://dummyimage./200x200/000/fff.jpg&text=test", 
  "https://dummyimage./200x200/000/fff.jpg&text=testOne",
  "https://dummyimage./200x200/000/fff.png&text=testTwo"
]

on button click i want to get the all the images from those url's and save it as zip

Issue : when ever i am able download the file as zip and try to extract it i am getting error as could not open image.zip as archieve and if i save as single image also the image is not opening up and is there any way to store the

below is my code

downloadImageData(){


  var blob = new Blob([this.data], { type:  'application/zip'' });

  FileSaver.saveAs(blob,'image.zip');

}

here i am having both png & jpg and various type of data so what ever data the links will get has to downloaded as zip file is there any approach for angular 5+. i am using filesave angular package also

JS ZIP _body resp

By using the http module im getting the below data [

  {
    "_body": {

    },
    "status": 200,
    "ok": true,
    "statusText": "OK",
    "headers": {
      "date": [
        "Sun",
        " 25 Nov 2018 12:18:47 GMT"
      ],
      "cache-control": [
        "public",
        " max-age=43200"
      ],
      "expires": [
        "Mon",
        " 26 Nov 2018 00:18:47 GMT"
      ],
      "content-disposition": [
        "attachment; filename=2B.JPG"
      ],
      "content-length": [
        "40649"
      ],
      "server": [
        "Werkzeug/0.14.1 Python/2.7.13"
      ],
      "content-type": [
        "image/jpg"
      ]
    },
    "type": 2,
    "url": "http://some url"
  }
]
Share Improve this question edited Nov 25, 2018 at 12:40 Madpop asked Nov 20, 2018 at 16:52 MadpopMadpop 7254 gold badges28 silver badges63 bronze badges 6
  • You have 3 ' in 'application/zip', maybe it's an error from copying, but if you have it in your code then you should remove one – ams Commented Nov 22, 2018 at 18:15
  • @ams That's typo error in application I have 2 only verified that – Madpop Commented Nov 22, 2018 at 18:46
  • have you tried downloading the file without using FileSaver? For example with an a tag, I could provide an example if you want to. – ams Commented Nov 22, 2018 at 19:07
  • 1 If this is all your code, the problem is, that you have to download the binary data first. You cannot simply add an array of URLs and make it magically be a zip file by providing a content type. In angular you'd use the HttpClient to download the files. – Christoph Lütjen Commented Nov 22, 2018 at 21:22
  • @ams no i tried only using that as i thought it makes things simple & sure u can provide a sample by using the above urls – Madpop Commented Nov 23, 2018 at 3:49
 |  Show 1 more ment

2 Answers 2

Reset to default 4

I have created a demo application here.

P.S: The code is for guidance only, and may not include standard coding practices but may guide you to create your own version of the solution.

I'm using jszip to zip file.

app.module.ts:

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/mon/http';
import { AppComponent }  from './app.ponent';
import * as JSZip from 'jszip';
import { saveAs } from 'file-saver';

@NgModule({
  imports:      [ BrowserModule, HttpClientModule ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

app.ponent.ts:

import { OnInit, Component } from '@angular/core';
import { HttpClient } from '@angular/mon/http';
import * as JSZip from 'jszip';
import { saveAs } from 'file-saver';

@Component({
  selector: 'my-app',
  template: `<button (click)='downloadZip()'>Download</button>`
})
export class AppComponent {

  constructor(private http: HttpClient) {
  }

  downloadZip() {
    this.loadSvgData("https://c.staticblitz./assets/client/icons/file-icons/angular-ponent-31179578a9a8a16512e9e90ade26549a.svg",
    this.saveAsZip);
  }

  private loadSvgData(url: string, callback: Function) : void{
    this.http.get(url, { responseType: "arraybuffer" })
             .subscribe(x => callback(x));
  }

  private saveAsZip(content: Blob) : void{
    var zip = new JSZip.default();
    zip.file("image.svg", content);
    zip.generateAsync({ type: "blob" })
       .then(blob => saveAs(blob,'image.zip'));
  };
}

Explanation:

The application only has one button, which on click will download an image file from the server using HttpClient. It will zip downloaded data using jszipand save it to browser using file-saver.

I hope this helps!

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.ponent.ts

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

@Component({
  selector: "app-root",
  templateUrl: "./app.ponent.html",
  styleUrls: ["./app.ponent.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.ponent.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 "pilerOptions" 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 ments, 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.ponent.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.ponent.html",
  styleUrls: ["./app.ponent.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.ponent.html",
  styleUrls: ["./app.ponent.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 })
      )
    );
  }
}
发布评论

评论列表(0)

  1. 暂无评论