Han Che
Han Che

Reputation: 8519

typescript angular 2 - creating own blob from input corrupts data

For learning purposes, I want to use the html input tag to select a jpeg image, retrieve the File Object, load it with fileReader and use the retrieved image string (base64) to create a new blob/file.

the service can upload the original file retrieved from the input just fine. However using my newFile the file get's corrupted and the file size somehow is larger.

I figure I'm doing something wrong with the blob constructor?

I'm using angular2 in typescript

<input type="file" (change)="onFileChanged($event)">

onFileChanged(event){
    if (event.target.files && event.target.files[0]) {
        let file = event.target.files[0];
        let newFile;
        let fr = new FileReader();
        fr.onload = (event:any)=>{
            let base64 = event.target.result
            let img = base64.split(',')[1]
            let blob = new Blob([window.atob(img)],{type:'image/jpeg'})
            newFile = this.blobToFile(blob,'test')
        }
        fr.readAsDataURL(file)
        console.log(file)
        console.log(newFile)
        this.service.upload(newFile).subscribe()
    }

}

blobToFile(blob: Blob, fileName: string): File {
        let b: any = blob;
        b.lastModified = moment.now();
        b.lastModifiedDate = new Date();
        b.name = fileName;
        b.webkitRelativePath="";
        return <File>blob
    }

EDIT------------ After finding out that fileReader is asynchronous, i've adjusted it a little bit and indeed the problem is with the blob constructor. loggin the both the target.result of original file and new one revealed that the base64 as been transmuted. Any ideas why?

if (event.target.files && event.target.files[0]) {
            let file = event.target.files[0];
            let base64: string = null;

            if (/^image\//.test(file.type)) {
                let reader = new FileReader();
                reader.onload = (e: any) => {
                    console.log(e.target)
                    base64 = e.target.result

                    let img = base64.split(',')[1];
                    let blob = new Blob([img], { type: 'image/jpeg' })
                    console.log(blob);
                    let fr = new FileReader()
                    fr.onload = (event: any) => {
                        console.log(event.target)
                    }
                    fr.readAsDataURL(blob)
                }
                reader.readAsDataURL(file);
}

Upvotes: 3

Views: 8476

Answers (2)

wannadream
wannadream

Reputation: 1760

I am suspecting your code:

onFileChanged(event){
    if (event.target.files && event.target.files[0]) {
        let file = event.target.files[0];
        let newFile;
        let fr = new FileReader();
        fr.onload = (event:any)=>{
            let base64 = event.target.result
            let img = base64.split(',')[1]
            let blob = new Blob([window.atob(img)],{type:'image/jpeg'})
            newFile = this.blobToFile(blob,'test')
        }
        fr.readAsDataURL(file)
        console.log(file)
        console.log(newFile)
        this.service.upload(newFile).subscribe()
    }

}

onFileChanged(event) and (event:any), these two 'event' mean different objects. event in onFileChanged is the event object of onFileChanged. event in fr.onload is the event object of FileReader.onload. Don't you think it is confusing and might cause cross reference?

Upvotes: 0

Trash Can
Trash Can

Reputation: 6824

Modify your function like this. Because FileReader is asynchronous, to process the result, you need to do it inside the onload callback, but here, you are uploading the file outside of onload which at that point, is undefined or whatever initial value it contains.

onFileChanged(event){
    if (event.target.files && event.target.files[0]) {
        let file = event.target.files[0];
        let newFile;
        let fr = new FileReader();
        fr.onload = (event:any)=>{
            let base64 = event.target.result
            let img = base64.split(',')[1]
            let blob = new Blob([window.atob(img)],{type:'image/jpeg'})
            newFile = this.blobToFile(blob,'test')
            this.service.upload(newFile).subscribe()
        }
        fr.readAsDataURL(file)
        console.log(file)
        console.log(newFile) // Either prints undefined or whatever initial value it contains

    }

}

Upvotes: 3

Related Questions