最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

html - Client PNG compression using javascript like pngcrush? - Stack Overflow

matteradmin8PV0评论

I'm developing HTML5 apps.

When user uploads image from their mobile, the size was too large.

I want to press the image as PNG like the pngcrush way.

Is there any good way to choice on the frontend (like a javascript library)?

Or is it possible to port the pngcrush library to javascript?

I'm developing HTML5 apps.

When user uploads image from their mobile, the size was too large.

I want to press the image as PNG like the pngcrush way.

Is there any good way to choice on the frontend (like a javascript library)?

Or is it possible to port the pngcrush library to javascript?

Share Improve this question asked Sep 24, 2015 at 1:13 Alfred HuangAlfred Huang 18.3k33 gold badges124 silver badges194 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 5

There are a few projects out there which seem to be based around the idea of using emscripten (a LLVM-to-JavaScript piler) to actually pile the source code from pngcrush to working JavaScript for the browser.

  • JavaScript-Packer/PNGCrush.html - based on pngcrush-1.7.27
  • richardassar/pngcrush.js - based on pngcrush-1.7.27
  • pngcrush-crushed - based on pngcrush-1.7.58

The version for pngcrush-1.7.27 is currently the only one that doesn't seem to produce corrupted images for me. I put together an example which uses promises here: http://plnkr.co/edit/iLpbOjlYiacR04oGdXSI?p=preview

Here's a basic usage example:

var instance = new pngcrush();

instance.exec(inputFile, function (stdoutEvent) {
  console.log(stdoutEvent.data.line);
}).then(function (doneEvent) {
  var outputFile = new Blob([doneEvent.data.data], { type: 'image/png' });
  // do something with the outputFile
});

Here are the contents of the pngcrush-class.js file from the above plunker for reference:

(function(exports) {

  var noop = function () {};

  function pngcrush () {
    this.callbacks = {
      'error':  [],
      'done':   [],
      'start':  [],
      'stdout': []
    };
  }

  pngcrush.prototype.exec = function (file, notify) {
    var self = this;

    if (this.execPromise) {
      return this.execPromise.catch(noop).then(function () {
        return self.exec(file, notify);
      });
    }

    if (file.type !== 'image/png') {
      return Promise.reject(file);
    }

    var promise = this.execPromise = this.readAsArrayBuffer(file).then(function (event) {
      var arrayBuffer = event.target.result;
      return self.initWorker().then(function (worker) {
        var done = new Promise(function (resolve, reject) {
          var offDone, offError, offStdout;
          offDone = self.once('done', function (event) {
            offError();
            offStdout();
            resolve(event);
          });
          offError = self.once('error', function (event) {
            offDone();
            offStdout();
            reject(event);
          });
          offStdout = self.on('stdout', function (event) {
            if (typeof notify === 'function') {
              notify.call(self, event);
            }
          });
          worker.postMessage({
            'type': 'file',
            'data': new Uint8Array(arrayBuffer)
          });
          worker.postMessage({
            'type': 'mand',
            'mand': 'go'
          });
        });
        done.catch(noop).then(function () {
          worker.terminate();
        });
        return done;
      });
    });

    promise.catch(noop).then(function () {
      if (promise === self.execPromise) {
        delete self.execPromise;
      }
    });

    return promise;
  };

  pngcrush.prototype.initWorker = function () {
    var self = this;

    if (this.workerPromise) {
      return this.workerPromise;
    }

    var promise = this.workerPromise = new Promise(function (resolve, reject) {
      var worker = new Worker('worker.js');
      worker.onerror = function (event) {
        var callbacks = [];
        reject(event);
        Array.prototype.push.apply(callbacks, self.callbacks.error);
        while (callbacks.length) {
          callbacks.shift().call(self, event);
        }
      };
      worker.onmessage = function (event) {
        if (event.data.type === 'ready') {
          worker.onmessage = function (event) {
            var name = event.data.type;
            if (typeof self.callbacks[name] !== 'undefined') {
              var callbacks = [];
              Array.prototype.push.apply(callbacks, self.callbacks[name]);
              while (callbacks.length) {
                callbacks.shift().call(self, event);
              }
            }
          };
          resolve(worker);
        }
      };
    });

    promise.catch(noop).then(function () {
      if (promise === self.workerPromise) {
        delete self.workerPromise;
      }
    });

    return promise;
  };

  pngcrush.prototype.on = function (name, callback) {
    var self = this;
    if (typeof this.callbacks[name] !== 'undefined' && typeof callback === 'function') {
      this.callbacks[name].push(callback);
      var off = (function () {
        var ran = false;
        return function () {
          if (ran === true) {
            return;
          }
          ran = true;
          var idx = self.callbacks[name].lastIndexOf(callback);
          if (idx !== -1) {
            self.callbacks[name].splice(idx - 1, 1);
          }
        };
      })();
      return off;
    }
    return noop;
  };

  pngcrush.prototype.once = function (name, callback) {
    var off = this.on(name, function () {
      off();
      callback.apply(this, arguments);
    });
    return off;
  };

  pngcrush.prototype.readAsArrayBuffer = function (file) {
    var fileReader = new FileReader();
    return new Promise(function (resolve, reject) {
      fileReader.onerror = reject;
      fileReader.onload  = resolve;
      fileReader.readAsArrayBuffer(file);
    });
  };

  pngcrush.prototype.readAsDataURL = function (file) {
    var fileReader = new FileReader();
    return new Promise(function (resolve, reject) {
      fileReader.onerror = reject;
      fileReader.onload  = resolve;
      fileReader.readAsDataURL(file);
    });
  };

  exports.pngcrush = pngcrush;

})(this);
Post a comment

comment list (0)

  1. No comments so far