arithmetic-coding
Advanced tools
Comparing version 1.0.0 to 1.1.0
@@ -7,2 +7,8 @@ # arithmetic-coding CHANGELOG | ||
Finished API and CLI support. | ||
- Finished API and CLI support. | ||
## v1.1.0 | ||
2019.03.30 | ||
- Added Buffer support. |
{ | ||
"name": "arithmetic-coding", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "Arithmetic coding implementation", | ||
@@ -38,3 +38,4 @@ "main": "src/index.js", | ||
"concat-stream": "^2.0.0", | ||
"long": "^4.0.0" | ||
"long": "^4.0.0", | ||
"which": "^1.3.1" | ||
}, | ||
@@ -41,0 +42,0 @@ "devDependencies": { |
@@ -12,3 +12,3 @@ # arithmetic-coding | ||
Install as module: | ||
Install as module for API usage: | ||
@@ -27,12 +27,24 @@ ```js | ||
Simply call `encode` and `decode` function. | ||
From file path: | ||
```js | ||
const ariCoding = require('arithmetic-coding'); | ||
// Encode | ||
// Encode from file | ||
ariCoding.encode(__dirname + '/txt/long.txt', __dirname + '/txt/long-encoded.txt'); | ||
// Decode | ||
// Decode from file | ||
ariCoding.decode(__dirname + '/txt/long-encoded.txt', __dirname + '/txt/long-decoded.txt'); | ||
``` | ||
From `Buffer`: | ||
```js | ||
let data = Buffer.from('Example data', 'utf8'); | ||
// Encode from Buffer | ||
let encoded = encode.encodeFromBuffer(data); | ||
console.log(`encoded = ${encoded}`); | ||
// Decode from buffer | ||
let decoded = decode.decodeFromBuffer(encoded); | ||
console.log(`decoded = ${decoded}`); | ||
``` | ||
## Command-line interface | ||
@@ -53,3 +65,3 @@ | ||
## About algorithm | ||
## About the algorithm | ||
@@ -56,0 +68,0 @@ 1. [Wikipedia](https://en.wikipedia.org/wiki/Arithmetic_coding) |
const fs = require('fs'); | ||
const CACHE_SIZE = 20000; | ||
/** | ||
@@ -24,2 +27,5 @@ * A stream where bits can be read. | ||
this._numbitsremaining = 0; | ||
this._cachedBytes = Buffer.alloc(0); | ||
this._streamEnded = false; | ||
} | ||
@@ -38,12 +44,18 @@ | ||
if (this._numbitsremaining === 0) { | ||
// console.log(`this._numbitsremaining0 = ${this._numbitsremaining}`); | ||
let temp = Buffer.alloc(1); | ||
let numOfBytesRead = fs.readSync(this._input, temp, 0, 1, null); | ||
// console.log(`numOfBytes read: ${numOfBytesRead}`); | ||
// console.log(`position = ${this._position}`); | ||
if (numOfBytesRead === 0) { | ||
this._currentbyte = -1; | ||
return -1; | ||
if (this._cachedBytes.length === 0) { | ||
if (this._streamEnded) { | ||
this._currentbyte = -1; | ||
return -1; | ||
} else { | ||
let temp = Buffer.alloc(CACHE_SIZE); | ||
let numOfBytesRead = fs.readSync(this._input, temp, 0, CACHE_SIZE, null); | ||
this._cachedBytes = Buffer.concat([this._cachedBytes, temp], numOfBytesRead); | ||
if (numOfBytesRead < CACHE_SIZE) { | ||
this._streamEnded = true; | ||
} | ||
} | ||
} | ||
this._currentbyte = temp[0]; | ||
// console.log(`this._cachedBytes = ${this._cachedBytes}`); | ||
this._currentbyte = this._cachedBytes[0]; | ||
this._cachedBytes = this._cachedBytes.slice(1); | ||
// console.log('Byte read:', temp); | ||
@@ -59,3 +71,3 @@ // console.log(this._currentbyte); | ||
// console.log(`this._numbitsremaining = ${this._numbitsremaining}`); | ||
return (this._currentbyte >> this._numbitsremaining) & 1; | ||
return (this._currentbyte >> this._numbitsremaining) & 1; | ||
} | ||
@@ -62,0 +74,0 @@ |
const fs = require('fs'); | ||
const FrequencyTable = require('./frequency-table'); | ||
const BitInputStream = require('./bit-input-stream'); | ||
const BitInputStreamFromBuffer = require('./bit-input-stream-buffer'); | ||
const Long = require('long'); | ||
@@ -8,3 +9,3 @@ const ArithmeticDecoder = require('./arithmetic-decoder'); | ||
/** | ||
* Encode a file using arithmetic coding algorithm | ||
* Decode a file using arithmetic coding algorithm | ||
* @param {string} inputfile Absolute path of the input file | ||
@@ -22,2 +23,15 @@ * @param {string} outputfile Absolute path of the output file | ||
/** | ||
* Decode a Buffer using arithmetic coding algorithm | ||
* @param {Buffer} inBuffer Input buffer | ||
*/ | ||
function decodeFromBuffer(inBuffer) { | ||
// const inStream = fs.createReadStream(inputfile); | ||
// const outStream = fs.createWriteStream(outputfile); | ||
const bitin = new BitInputStreamFromBuffer(inBuffer); | ||
let freqs = readFrequencies(bitin); | ||
// console.log(`freqs.total = ${freqs.total}`); | ||
return decompressToBuffer(freqs, bitin); | ||
} | ||
function readFrequencies(bitin) { | ||
@@ -64,5 +78,27 @@ function readInt(n) { | ||
/** | ||
* | ||
* @param {FrequencyTable} freqs | ||
* @param {BitInputStreamFromBuffer} bitin | ||
*/ | ||
function decompressToBuffer(freqs, bitin) { | ||
let buffer = Buffer.alloc(0); | ||
const dec = new ArithmeticDecoder(32, bitin); | ||
for (;;) { | ||
let symbol = dec.read(freqs); | ||
// EOF symbol | ||
if (symbol === 256) { | ||
dec.finish(); | ||
break; | ||
} | ||
// console.log(`writing ${symbol}`); | ||
buffer = Buffer.concat([buffer, Buffer.from([symbol])]); | ||
} | ||
return buffer; | ||
} | ||
module.exports = { | ||
readFrequencies, | ||
decode | ||
decode, | ||
decodeFromBuffer | ||
}; |
const fs = require('fs'); | ||
const FrequencyTable = require('./frequency-table'); | ||
const BitOutputStream = require('./bit-output-stream'); | ||
const BitOutputStreamToBuffer = require('./bit-output-stream-buffer'); | ||
const ArithmeticEncoder = require('./arithmetic-encoder'); | ||
const CACHE_SIZE = 20000; | ||
/** | ||
@@ -18,3 +21,3 @@ * Returns a frequency table based on the bytes | ||
); | ||
const temp = Buffer.alloc(100); | ||
const temp = Buffer.alloc(CACHE_SIZE); | ||
let bytesRead; | ||
@@ -34,3 +37,20 @@ for (;;) { | ||
/** | ||
* Decode a file using arithmetic coding algorithm | ||
* Returns a frequency table based on the bytes | ||
* in the given Buffer. | ||
* Also contains an extra entry for symbol 256, | ||
* whose frequency is set to 0. | ||
* @param {Buffer} buffer | ||
*/ | ||
function getFrequenciesFromBuffer(buffer) { | ||
let freqs = new FrequencyTable( | ||
new Array(257).fill(0) | ||
); | ||
for (let byte of buffer) { | ||
freqs.increment(byte); | ||
} | ||
return freqs; | ||
} | ||
/** | ||
* Encode a file using arithmetic coding algorithm | ||
* @param {string} inputfile Absolute path of the input file | ||
@@ -51,2 +71,18 @@ * @param {string} outputfile Absolute path of the output file | ||
/** | ||
* Encode a Buffer using arithmetic coding algorithm | ||
* @param {Buffer} inBuffer Input buffer | ||
*/ | ||
function encodeFromBuffer(inBuffer) { | ||
let freqs = getFrequenciesFromBuffer(inBuffer); | ||
// EOF symbol gets a frequency of 1 | ||
freqs.increment(256); | ||
const bitout = new BitOutputStreamToBuffer(); | ||
writeFrequencies(bitout, freqs); | ||
compressFromBuffer(freqs, inBuffer, bitout); | ||
return bitout.buffer; | ||
} | ||
/** | ||
* Write the frequency table to encoded file. | ||
@@ -86,3 +122,3 @@ * @param {BitOutputStream} bitout the output stream | ||
for(;;) { | ||
const temp = Buffer.alloc(100); | ||
const temp = Buffer.alloc(CACHE_SIZE); | ||
let bytesRead; | ||
@@ -104,5 +140,24 @@ if ((bytesRead = fs.readSync(input, temp, 0, temp.length, null)) === 0) { | ||
/** | ||
* | ||
* @param {FrequencyTable} freqs | ||
* @param {Buffer} inBuffer | ||
* @param {BitOutputStreamToBuffer} bitout | ||
*/ | ||
function compressFromBuffer(freqs, inBuffer, bitout) { | ||
let enc = new ArithmeticEncoder(32, bitout); | ||
for (let byte of inBuffer) { | ||
enc.write(freqs, byte); | ||
} | ||
// EOF | ||
enc.write(freqs, 256); | ||
// Flush remaining code bit | ||
enc.finish(); | ||
// console.log('Encoded okay!'); | ||
} | ||
module.exports = { | ||
getFrequencies, | ||
encode | ||
encode, | ||
encodeFromBuffer | ||
}; |
@@ -1,6 +0,8 @@ | ||
let encode = require('./encode').encode; | ||
let decode = require('./decode').decode; | ||
let encode = require('./encode'); | ||
let decode = require('./decode'); | ||
module.exports = { | ||
encode, | ||
decode | ||
encode: encode.encode, | ||
encodeFromBuffer: encode.encodeFromBuffer, | ||
decode: decode.decode, | ||
decodeFromBuffer: decode.decodeFromBuffer | ||
}; |
@@ -8,2 +8,4 @@ var fs = require('fs'); | ||
decode.decode(__dirname + '/txt/short-encoded.txt', __dirname + '/txt/short-decoded.txt'); | ||
}); | ||
it('should decode & encode equal', function () { | ||
let originalText = fs.readFileSync(__dirname + '/txt/short.txt'); | ||
@@ -10,0 +12,0 @@ let decodedText = fs.readFileSync(__dirname + '/txt/short-decoded.txt'); |
@@ -19,2 +19,12 @@ require('should'); | ||
}); | ||
describe('Buffer support', function() { | ||
it('should encode and decode Buffer okay', function() { | ||
let data = Buffer.from('Example data', 'utf8'); | ||
let encoded = ariCoding.encodeFromBuffer(data); | ||
// console.log(`encoded = ${encoded}`); | ||
let decoded = ariCoding.decodeFromBuffer(encoded); | ||
// console.log(`decoded = ${decoded}`); | ||
data.should.eql(decoded); | ||
}); | ||
}); | ||
}); |
@@ -17,3 +17,3 @@ const cmd = require('./cmd'); | ||
}); | ||
it('should encode & encode okay', async () => { | ||
it('should encode okay', async () => { | ||
await cmd.execute( | ||
@@ -23,2 +23,4 @@ path.resolve(__dirname, '../bin/index.js'), | ||
); | ||
}); | ||
it('should decode okay', async () => { | ||
await cmd.execute( | ||
@@ -28,2 +30,4 @@ path.resolve(__dirname, '../bin/index.js'), | ||
); | ||
}); | ||
it('should encode & decode equal', async () => { | ||
let originalText = fs.readFileSync(__dirname + '/txt/long.txt'); | ||
@@ -30,0 +34,0 @@ let decodedText = fs.readFileSync(__dirname + '/txt/long-decoded.txt'); |
@@ -0,1 +1,2 @@ | ||
require('should'); | ||
// https://medium.com/@zorrodg/integration-tests-on-node-js-cli-part-1-why-and-how-fa5b1ba552fe | ||
@@ -6,3 +7,8 @@ const spawn = require('child_process').spawn; | ||
return spawn('node', args, { | ||
// Require which and child_process | ||
const which = require('which'); | ||
// Find node in PATH | ||
const node = which.sync('node'); | ||
return spawn(node, args, { | ||
env: Object.assign( | ||
@@ -9,0 +15,0 @@ { |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
162202
27
1262
67
5
+ Addedwhich@^1.3.1
+ Addedisexe@2.0.0(transitive)
+ Addedwhich@1.3.1(transitive)