代码之家  ›  专栏  ›  技术社区  ›  Madpop

无法使用Angular 6将图像下载为zip文件

  •  3
  • Madpop  · 技术社区  · 6 年前

    下面是这样的动态数据

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

    单击按钮,我想从这些URL中获取所有图像并将其保存为zip

    问题:当我能够以zip格式下载文件并尝试提取它时,我会出错,因为无法以archieve格式打开image.zip;如果我以单个图像保存,则图像也不会打开,是否有任何方法存储

    下面是我的代码

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

    这里我既有PNG&JPG,也有各种类型的数据,所以链接将获得的任何数据都必须作为zip文件下载,对于Angular5+有任何方法。我也在使用filesave angular包

    JS拉链式车身

    通过使用HTTP模块,im获取以下数据[

      {
        "_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"
      }
    ]
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   ams    6 年前

    我有点晚了,但这段代码将使用您的图像数组并创建GET请求。之后,它将执行所有请求,并将响应添加到zip文件中,然后下载。

    如果您不喜欢使用filesaver,我提供了两种下载文件的方法。选择你喜欢的。

    编辑:

    如果您使用的是旧版本的RXJS,则必须导入 forkJoin 以不同的方式,请参考RXJS文档。 还要确保后端允许下载文件,否则会出现CORS错误。

    forkJoin Documentation

    应用组件.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(应用程序组件.html)

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

    我还必须在tsconfig.json中包含jszip的路径。根据角度的不同,你不需要这样做。里面 "compilerOptions" 添加以下内容:

    TSOCONT.JSON

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

    更新:

    这里有一个旧的httpmodule的解决方案,我试过了,它工作了。如果可能的话,我建议更换新的httpclientmodule。

    更新2:

    正如我在评论中所说,在保存文件以处理不同的文件类型时,可以更改文件扩展名。这是一个例子,您可以轻松地扩展这个解决方案。

    应用组件.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 })
          )
        );
      }
    }
    

    更新3:

    从URL提取文件名的解决方案,这样就不需要文件类型:

    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 })
          )
        );
      }
    }
    
        2
  •  2
  •   Dipen Shah    6 年前

    我创建了一个演示应用程序 here .

    P.S:该代码仅供参考,可能不包括标准编码实践,但可能指导您创建自己的解决方案版本。

    我在用 jszip 压缩文件。

    应用模块.ts 以下内容:

    import { NgModule }      from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { HttpClientModule } from '@angular/common/http';
    import { AppComponent }  from './app.component';
    import * as JSZip from 'jszip';
    import { saveAs } from 'file-saver';
    
    @NgModule({
      imports:      [ BrowserModule, HttpClientModule ],
      declarations: [ AppComponent ],
      bootstrap:    [ AppComponent ]
    })
    export class AppModule { }
    

    应用组件.ts:

    import { OnInit, Component } from '@angular/core';
    import { HttpClient } from '@angular/common/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.com/assets/client/icons/file-icons/angular-component-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'));
      };
    }
    

    说明:

    应用程序只有一个按钮,单击该按钮将使用 HttpClient . 它将压缩下载的数据,使用 jszip 并使用将其保存到浏览器 file-saver .

    希望这有帮助!