gchudnov / inkjet

JPEG-image decoding, encoding & EXIF reading library for a browser and node.js
MIT License
225 stars 6 forks source link

Getting an ArrayBuffer with a byteLength of 611 when encoding. #2

Closed Tvde1 closed 7 years ago

Tvde1 commented 7 years ago

So I have been trying to encode at a jpeg (for a 'needs more jpeg tool'). I save the image from an url to file, and open it again. For some reason I get an ArrayBuffer { byteLength: 611 } (when it should be 8) whenI do console.log(encoded.data.buffer).

I'd want to save the image when it's encoded.

This is the code I've been using: const inkjet = require('inkjet'); const fs = require('fs');

let download = function(uri, filename, callback){
  request.head(uri, function(err, res, body){
    console.log('content-type:', res.headers['content-type']);
    console.log('content-length:', res.headers['content-length']);

    request(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
  });
};

cost url = 'https://cdn.discordapp.com/attachments/276406555660779520/283962006044803073/avatar.jpg';

const filePath = 'temp/jpeg.jpg';

download(image, filePath, function() {

  const buf = fs.readFileSync(filePath);
  let width; 
  let height;

  inkjet.info(buf, function(err, data) {
    if (err) throw err;
    width = data.width;
    height = data.height;
  });

  const options = { width: width, height: height, quality: 80 };

  inkjet.encode(buf, options, function(err, encoded) {
    if (err) throw err;

    console.log(encoded.data.buffer);      
  });
});
gchudnov commented 7 years ago

Hi @Tvde1, Please note that calls to info and encode are asynchronous. You should place encode inside of info call or use some exteral library to orchestrate the calls, like async

something like this:

    let download = function (uri, filename, callback) {
      request.head(uri, function (err, res, body) {
        console.log('content-type:', res.headers['content-type']);
        console.log('content-length:', res.headers['content-length']);

        request(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
      });
    };

    const url = 'https://cdn.discordapp.com/attachments/276406555660779520/283962006044803073/avatar.jpg';

    const filePath = 'myfile.jpg';

    download(url, filePath, function () {

      const buf = fs.readFileSync(filePath);
      let width;
      let height;

      inkjet.info(buf, function (err, data) {
        if(err) { console.log(err); return; }

        width = data.width;
        height = data.height;

        const options = { width: width, height: height, quality: 80 };

        inkjet.encode(buf, options, function (err, encoded) {
          if(err) throw err;

          console.log(encoded.data.buffer);
        });
      });

After execution, the following text is printed:

content-type: image/jpeg
content-length: 9694
ArrayBuffer { byteLength: 5540 }
Tvde1 commented 7 years ago

And how'd I go about saving this to a file?

fs.writeFile('temp/encoded.jpg', encoded.data.buffer, function(err) {
    if (err) throw err;
    message.channel.sendFile('temp/encoded.jpg');
});

After console.log(encoded.data.buffer) creates a file that, when opened with notepad, contains

[object ArrayBuffer]

Edit: And using Buffer.from(encoded.data.buffer) gives me this picture: image

gchudnov commented 7 years ago

If you need to re-encode the image, check the following code in tests

Tvde1 commented 7 years ago

Do I need all of that or just a part?

gchudnov commented 7 years ago

Do I need all of that or just a part?

Sorry, not sure what are you trying to implement, it is difficult to recommend anything.

If you need to process images in node.js only, probably you need a different library.

If you need to re-encode in browser (or create an app that works in browser and node.js), you can use this library or jpeg-asm which is a port of libjpeg to JavaScript with a minimal set of exported functions.

If you want to stick with this library (or jpeg-asm), you need 2 operations to re-encode JPEG: 1) decode -- you'll get the dimensions & buffer with RGB-data. 2) encode -- provide dimensions, buffer and quality and you'll get the encoded buffer that you can save if needed.

tests and examples directories contain the code you can use as an example.