AngularでWebAPIからblob形式で返された画像データを取得する方法

フロントエンドアプリケーションフレームワークであるAngular(Ionic)を使って、非同期通信で画像を読み込む方法をサンプルアプリとして紹介します。動作確認用にPythonで作成したバックエンドコード付きです。

Angularの場合、非同期通信を実装するにはHttpClientModuleをapp.module.tsに追加して、tsファイルで呼び出して使うだけです。画像の場合は、さらにresponseTypeに’blob’形式を指定し、DomSanitizerでサニタイズして読み込みます。HTML側は<img [src]=imageUrl>で行けます。

AngularはReactと異なりフルスタックなので、この辺の安心感があります。

参考にしたサイト

stackOverflow

ソースコード

githubはこちら

解説

app.module.ts

app.module.tsに
import { HttpClientModule } from ‘@angular/common/http’;
を追加します。importするのも忘れずに

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { HttpClientModule } from '@angular/common/http';

import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [BrowserModule,HttpClientModule, IonicModule.forRoot(), AppRoutingModule],
  providers: [
    StatusBar,
    SplashScreen,
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

Ionicの場合、moduleファイルが複数あリますが、app.module.tsにだけ書いておけば問題ないです。

home.page.ts

こちらには
import { HttpClient } from ‘@angular/common/http’;
import { DomSanitizer } from ‘@angular/platform-browser’;
の2つを追加します。あとは処理を書くだけです。

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { DomSanitizer } from '@angular/platform-browser';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {
  unsafeImageUrl:any;
  imageUrl:any;

  constructor(
    private http: HttpClient,
    private sanitizer:DomSanitizer)
  {
    this.hello();
  }

  hello(){
    this.http.get('http://127.0.0.1:5000',{responseType:'blob'})
     .subscribe(
       (res:any) => {
         console.log(res);
         this.unsafeImageUrl = URL.createObjectURL(res);
         this.imageUrl = this.sanitizer.bypassSecurityTrustUrl(this.unsafeImageUrl);
       })
  }
}

これでOK。anyを指定してしまっていますので書き方知っていたら教えてください。

home.page.html

htmlはを追加するだけです。

<ion-header [translucent]="true">
  <ion-toolbar>
    <ion-title>
      Blank
    </ion-title>
  </ion-toolbar>
</ion-header>

<ion-content [fullscreen]="true">
  <ion-header collapse="condense">
    <ion-toolbar>
      <ion-title size="large">Blank</ion-title>
    </ion-toolbar>
  </ion-header>

  <div id="container">
    <img [src]=imageUrl>
    <strong>Ready to create an app?</strong>
    <p>Start with Ionic <a target="_blank" rel="noopener noreferrer" href="https://ionicframework.com/docs/components">UI Components</a></p>
  </div>
</ion-content>

バックエンド

バックエンドはこちら

# -*- coding: utf-8 -*-
import io
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from flask import Flask, send_file
from flask_cors import CORS
import json

app = Flask(__name__)
CORS(app)

@app.route('/',methods=["GET","POST"])
def hello():
    image = io.BytesIO()
    x = np.linspace(0, 10)
    y = np.sin(x)
    plt.plot(x, y)
    plt.savefig(image, format='png')
    image.seek(0)
    return send_file(image,
                     attachment_filename="image.png",
                     as_attachment=True)

if __name__ == "__main__":
    app.run(host='127.0.0.1',debug=True)