3

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);
}
4
  • does event.target.result return a base64-encoded string or binary data? Commented May 1, 2017 at 19:58
  • returns in something like this data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAIBAQEBAQIBAQECAg... Commented May 1, 2017 at 20:03
  • The code looks correct. Do you mean that it is corrupted on the server after upload, or in the Angular app? How are you 'using' it, and what leads you to believe that it is corrupted? Commented May 1, 2017 at 20:07
  • well when i download it after the upload, it says the file is corrupted and can't open... Basically, if i just upload the original file from the input, everything works fine. If I upload the Blob/File i've created, the file is corrupted when i download it Commented May 1, 2017 at 20:11

2 Answers 2

3

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

    }

}
Sign up to request clarification or add additional context in comments.

2 Comments

thanks! But now it really looks like the base64 string has been transmuted...i've updated the post above
I don't understand your new code at all, why do you have a file reader reading the file inside another file reader? You only need to read the uploaded file(s) once
0

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?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.