0

Im trying to convert an image file to Int8Array. I have something like this:

public onFileChange(event) {
    const reader = new FileReader();
    reader.onload = () => {
      this.productImage = new Int8Array(reader.result);
    };
    
    reader.readAsArrayBuffer(event.target.files[0]);
    
  }

Where event is the uploaded image file. So how to put it in:

productImage: Int8Array;

I would use some help, thanks.

Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • Is it not working? – Vinay Aug 17 '20 at 17:29
  • Yeah. Im doing it in Angular. They dont comply. One is string | ArrayBuffer, the other is Iterable. – Łukasz Jankowski Aug 17 '20 at 17:41
  • You can make your own iterable that iterates on arrayBuffer using Dataview – Vinay Aug 18 '20 at 17:48
  • Please clarify your problem, where does the error comes from? Your code is the way to go. Maybe your typescript IDE is set up to see `FileReader#result` as being a `` since `readAsText` and `readAsDataURL` would indeed produce this, but that's just your IDE lying. – Kaiido Aug 19 '20 at 04:48
  • Not an Angular ninja myself, but Possible duplicate of https://stackoverflow.com/questions/52955710/type-string-arraybuffer-is-not-assignable-to-type-string – Kaiido Aug 19 '20 at 05:00

1 Answers1

0

You can use Dataview and iterate over it using an iterable

/**** Make Iterable ****/
//@arrayBuffer is the file arrayBuffer
var MakeMeIterable = function(arrayBuffer) {
  this.dataview = new DataView(arrayBuffer, 0);
  this.size = arrayBuffer.byteLength;
  this.index = 0;
}

// 1. Iterating construct like ... , for..of loop  initially calls this
MakeMeIterable.prototype[Symbol.iterator] = function() {
  // 2. Afterwards iterating construct utilises this object only for getting further values
  return {
    dataview: this.dataview,
    size: this.size,
    index: this.index,

    current: this.from,
    last: this.to,

    // 3. next() is called on each iteration by the other iterating constructs like ... , for..of loop
    next() {
      // 4. it should return the value as an object {done:.., value :...}
      if (this.index < this.size) {
        var result = this.dataview.getInt8(this.index);
        this.index += 1;
        return {
          done: false,
          value: result
        };
      } else {
        return {
          done: true
        };
      }
    }
  };
};

/**********************/
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="input" type="file"></input>

<script>
  function readFile(f) {
    var reader = new FileReader();

    reader.onload = function() {
      var cursor = new MakeMeIterable(reader.result);
      this.productImage = cursor; //cursor <--iterable!

      /*
      //uncomment to have some fun in console
      for (let num of cursor) {
        console.log(num);
      }
      */

    };

    reader.onerror = function(e) {
      alert('Some error!');
      console.log("Error:", e);
    };
    reader.readAsArrayBuffer(f);
  }

  $(function() {
    $('#input').on("change", function(e) {
      var file = e.currentTarget.files[0];
      readFile(file);
    });
  });
</script>
Vinay
  • 7,442
  • 6
  • 25
  • 48
  • 1
    TypedArrays are iterable so all your code can be replaced with a more performant single liner `new Uint8Array( await file.arrayBuffer() )`. But that will probably not solve OP's problem anyway which is apparently more a type declaration issue which makes `reader.result` is treated as a string. (Also they wanted an Int8Array, not an Uint8) – Kaiido Aug 19 '20 at 04:58
  • Woa didnt know that they themselves are iterables! thanks for pointing about int8 – Vinay Aug 19 '20 at 05:50
  • using dataview seems a bit overkill. however, try `new Uint8Array( new Response(file).arrayBuffer() )` if `file.arrayBuffer()` don't cut it – Endless Aug 19 '20 at 22:45