var express = require('express');
var app = express();
const fs = require('fs');
//create server on 3330 port
// app.listen(3330, function () {
// console.log('Example app listening on port 3330!');
// });
//********S**T**A**R**T***H*U*F*F*M*A*N***************//Код хаффмана работает правильно, принимает строку, возвращает строку
var Heap = function(fn) {
this.fn = fn || function(e) {
return e;
};
this.items = [];
};
Heap.prototype = {
swap: function(i, j) {
this.items[i] = [
this.items[j],
this.items[j] = this.items[i]
][0];
},
bubble: function(index) {
var parent = ~~((index - 1) / 2);
if (this.item(parent) < this.item(index)) {
this.swap(index, parent);
this.bubble(parent);
}
},
item: function(index) {
return this.fn(this.items[index]);
},
pop: function() {
return this.items.pop();
},
sift: function(index, end) {
var child = index * 2 + 1;
if (child < end) {
if (child + 1 < end && this.item(child + 1) > this.item(child)) {
child++;
}
if (this.item(index) < this.item(child)) {
this.swap(index, child);
return this.sift(child, end);
}
}
},
push: function() {
var lastIndex = this.items.length;
for (var i = 0; i < arguments.length; i++) {
this.items.push(arguments[i]);
this.bubble(lastIndex++);
}
},
get length() {
return this.items.length;
}
};
var Huffman = {
encode: function(data) {
var prob = {};
var tree = new Heap(function(e) {
return e[0];
});
for (var i = 0; i < data.length; i++) {
if (prob.hasOwnProperty(data[i])) {
prob[data[i]]++;
} else {
prob[data[i]] = 1;
}
}
Object.keys(prob).sort(function(a, b) {
return ~~(Math.random() * 2);
}).forEach(function(e) {
tree.push([prob[e], e]);
});
while (tree.length > 1) {
var first = tree.pop(),
second = tree.pop();
tree.push([first[0] + second[0], [first[1], second[1]]]);
}
var dict = {};
var recurse = function(root, string) {
if (root.constructor === Array) {
recurse(root[0], string + '0');
recurse(root[1], string + '1');
} else {
dict[root] = string;
}
};
tree.items = tree.pop()[1];
recurse(tree.items, '');
var result = '';
for (var i = 0; i < data.length; i++) {
result += dict[data.charAt(i)];
}
var header = Object.keys(dict).map(function(e) {
return e.charCodeAt(0) + '|' + dict[e];
}).join('-') + '/';
huffmanTable = header;
huffmanBitmap = result;
return header + result;
},
decode: function(string) {
string = string.split('/');
var data = string[1].split(''),
header = {};
string[0].split('-').forEach(function(e) {
var values = e.split('|');
header[values[1]] = String.fromCharCode(values[0]);
});
var result = '';
while (data.length) {
var i = 0,
cur = '';
while (data.length) {
cur += data.shift();
if (header.hasOwnProperty(cur)) {
result += header[cur];
break;
}
}
}
// dataBitmap = result;
return result;
}
};
//***********E***N***D**H*U*F*F*M*A*N***************//
var huffmanTable = '',
huffmanBitmap = '',
dataBitmap = '',
bmpBuffer,//read file
bmpHead,//new empty
arrByteTable = [],
tableHuff,//new buffer for tableHuff
currentOffsetByte,//current offset
arrByteBitmap = [],
bmpData,//add info into bmpData
huffData,//add huff info
offsetByte,//new offset
totalLength,//size new buffer
newArrByteBitmap = [],//for encode
newBuffer;//create new buffer
function toReadFile(bmpName) {
bmpBuffer = fs.readFileSync(bmpName);
console.log('bmpBuffer length: '+bmpBuffer.length);
}
function getBmpHead() {
bmpHead = Buffer.alloc(54);
bmpBuffer.copy(bmpHead, 0, 0, 53);
return bmpHead;
}
function getBmpData() {
var leng = bmpBuffer.length - bmpHead.length;
bmpData = Buffer.alloc(leng);
bmpBuffer.copy(bmpData, 0, 54);//запись матрицы в буфер
return bmpData;
}
function toWriteFileEncode() {
totalLength = bmpHead.length + huffData.length + tableHuff.length;
newBuffer = Buffer.concat([bmpHead, tableHuff, huffData], totalLength);
fs.writeFileSync('img/picture-encode.bmp', newBuffer);
}
function toEncode() {
Huffman.encode(bmpData.toString());//выполняется кодирование по хаффману
tableHuff = Buffer.alloc(huffmanTable.length);
tableHuff = Buffer.from(huffmanTable);//запись таблицы кодирования
currentOffsetByte = bmpHead.readUInt8(10);//читаем текущий отступ
offsetByte = currentOffsetByte + tableHuff.length;//создаем новый отступ
bmpHead.writeUInt8(offsetByte, 10);//запись нового отступа
huffData = Buffer.alloc(huffmanBitmap.length);
huffData = Buffer.from(huffmanBitmap);//запись код-матрицы в буфер
toWriteFileEncode();
}
function toDecode() {
currentOffsetByte = bmpHead.readUInt8(10);
tableHuff = Buffer.alloc(currentOffsetByte - 54);
bmpBuffer.copy(tableHuff, 0, 54, currentOffsetByte);//запись таблицы в буфер
huffData = Buffer.alloc(bmpBuffer.length - currentOffsetByte);
bmpBuffer.copy(huffData, 0, currentOffsetByte);//запись код-матрицы в буфер
newBuffer = tableHuff.toString() + huffData.toString();//соединение таблицы и код-матрицы
dataBitmap = Huffman.decode(newBuffer);
bmpData = Buffer.from(dataBitmap);//запись матрицы в буфер
bmpHead.writeUInt8(54, 10);
totalLength = bmpHead.length + bmpData.length;
newBuffer = Buffer.concat([bmpHead, bmpData], totalLength);
fs.writeFileSync('img/picture-decode.bmp', newBuffer);
}
//Запустить для кодирования
// toReadFile('img/picture2.bmp');//чтение файла и запись в буфер
// getBmpHead();//запись заголовока bmp в буфер bmpHead
// getBmpData();//запись тела bmp в буфер до кодирования
// toEncode();
//Запустить для декодирования
toReadFile('img/picture-encode.bmp');//чтение файла и запись в буфер
getBmpHead();//запись заголовока bmp в буфер bmpHead
toDecode();