そもそも

Imageオブジェクト,Fileオブジェクト,dataurlというのがキーワードになる.

FIleオブジェクトはInputタグから読み込んだもの.dataurlはブラウザ上で表示できるように文字列で表したもの.dataurlはdata:image/jpeg;base64,/9j/4AAQSkZJRgABAgEASAB****という文字列になる.

Inputタグからファイルを読み込んでcanvasに描写したい場合,Fileオブジェクトをdataurlに変換したあと,ImageオブジェクトのSRCとしてこれを設定する.canvasはdataurlを直接受け取ることはできないためImageオブジェクトに変換する.

一方,canvasからfirebaseのStorageに書き込む場合は,canvasからdataurlを生成し,それをバイナリデータであるFileオブジェクトに変換する.FileオブジェクトはそのままStorageに保存できる.

base64, blob,もあるが,base64はdataurlと似たもので,blobはブラウザ上で生成されたFileオブジェクトのことだと理解している.

基本

Inputタグから読み込んで,canvas要素に描写する.

  <div class="upload">
    <input type="file" accept="image/*"
           (change)="fileChangeEvent($event)">
  </div>

  <div class="parent">
    <canvas #canvas></canvas>
  </div>
import { Component,ElementRef,Input,ViewChild } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-tab1',
  templateUrl: 'tab1.page.html',
  styleUrls: ['tab1.page.scss']
})
export class Tab1Page {
  file: File = null;
  @ViewChild('canvas') public canvas: ElementRef;
  width:number;// = 1400;
  height:number;// = 1400;
  private cx: CanvasRenderingContext2D;

  constructor(
  ) {
  }

  ionViewDidEnter(){
    this.width=window.innerWidth;
    this.height=window.innerHeight;
    const canvasEl: HTMLCanvasElement = this.canvas.nativeElement;
    this.cx = canvasEl.getContext('2d');
  }

  fileChangeEvent(event: any): void {
    if (event.target.files.length === 0) {
      this.file = null;
      return;
    }
    console.log(this.cx,'cx');
    console.log(event.target.files[0],'event.target.files[0]');
    this.cellRender(event.target.files[0]).subscribe((dataUrl)=>{
      console.log(dataUrl,123);
      const image = new Image();
      let aa:any =this.cx;
      image.onload = function() {
        
        aa.drawImage(image, 0, 0);   
      }
      image.src = dataUrl;


    })

}

cellRender(file):Observable<any>{
  return new Observable(observer => {
    let reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = function(){
      var dataUrl:any = reader.result;
      observer.next(dataUrl);
    }
  })
}
}

Inputタグで読み込んだデータは,event.target.filesで容易にアクセスできる.配列になっているので一つしか選択していない場合はevent.target.files[0]で取得できる.

% event.target.files[0]
File {name: "スクリーンショット 2021-05-19 7.04.28.jpg", lastModified: 1621375474163, lastModifiedDate: Wed May 19 2021 07:04:34 GMT+0900 (日本標準時), webkitRelativePath: "", size: 615460, …} "event.target.files[0]"

dataURLの形式にすると便利だが,AngularだとObserverを導入するとうまくいった.

fileChangeEvent(event: any): void { if (event.target.files.length === 0) { this.file = null; return; } this.imageRender(event.target.files[0]).subscribe((dataUrl)=>{ console.log(dataUrl) //data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEASAB**** }) } imageRender(file):Observable<any>{ return new Observable(observer => { let reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function(){ var dataUrl:any = reader.result; observer.next(dataUrl); } }) }

さらにDataURLをcanvasに描写する.canvasで画像を描く際、drawImageというメソッドを用いるが,

によると,imageはHTMLImageElement, HTMLCanvasElement, HTMLVideoElement のいずれかを取ることができるということなので,dataUrlは受け取れない.従ってconst image = new Image();のように生成しておいて,image.srcでdataURLを読み込ませる.new Image()といってもconsole.log(image)で確認すると<img src=”da” />の形式だった.

fileChangeEvent(event: any): void { //fileが選択されていなければリセット if (event.target.files.length === 0) { this.file = null; return; } console.log(event.target.files[0],'event.target.files[0]'); this.imageRender(event.target.files[0]).subscribe((dataUrl)=>{ console.log(dataUrl,123); const image = new Image(); let canvasVar:any =this.cx; image.onload = function() { canvasVar.drawImage(image, 0, 0); } image.src = dataUrl; }) } imageRender(file):Observable<any>{ return new Observable(observer => { let reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function(){ var dataUrl:any = reader.result; observer.next(dataUrl); } }) }

以上でファイルオブジェクトからdataURL(base64と同等)に変換し,canvasへImageオブジェクトに変換して描写する流れができたので,次はcanvasからDataURlを生成し,ファイルオブジェクトを生成する.

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

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

  <div class="upload">
    <input type="file" accept="image/*"
           (change)="fileChangeEvent($event)">
  </div>

  <div class="parent">
    <canvas #canvas></canvas>
  </div>

  + <ion-button expand="full" shape='round' (click)='save()'>Save</ion-button>


</ion-content>
save(){
const canvasEl: HTMLCanvasElement = this.canvas.nativeElement; var dataURI = canvasEl.toDataURL( "image/jpeg", 0.75 ) ; console.log(dataURI,'dataURI'); var bin = atob(dataURI.split(',')[1].replace(/^.*,/, '')); var buffer = new Uint8Array(bin.length); for (var i = 0; i < bin.length; i++) { buffer[i] = bin.charCodeAt(i); } this.createdFileObject = new File([buffer.buffer], "name.jpg",{type: "image/jpeg"}); }
 

console.log(created)すると下記が確認できる.

{name: "name.jpg", lastModified: 1622154958219, lastModifiedDate: Fri May 28 2021 07:35:58 GMT+0900 (日本標準時), webkitRelativePath: "", size: 569, …}