そもそも
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というメソッドを用いるが,
https://karoten512.hatenablog.com/entry/2018/03/04/131142
によると,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(',').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, …}