react-native-flip
Version:
191 lines (139 loc) • 4.29 kB
JavaScript
'use strict';
var paethPredictor = require('./paeth-predictor');
function filterNone(pxData, pxPos, byteWidth, rawData, rawPos) {
for (var x = 0; x < byteWidth; x++) {
rawData[rawPos + x] = pxData[pxPos + x];
}
}
function filterSumNone(pxData, pxPos, byteWidth) {
var sum = 0;
var length = pxPos + byteWidth;
for (var i = pxPos; i < length; i++) {
sum += Math.abs(pxData[i]);
}
return sum;
}
function filterSub(pxData, pxPos, byteWidth, rawData, rawPos, bpp) {
for (var x = 0; x < byteWidth; x++) {
var left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
var val = pxData[pxPos + x] - left;
rawData[rawPos + x] = val;
}
}
function filterSumSub(pxData, pxPos, byteWidth, bpp) {
var sum = 0;
for (var x = 0; x < byteWidth; x++) {
var left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
var val = pxData[pxPos + x] - left;
sum += Math.abs(val);
}
return sum;
}
function filterUp(pxData, pxPos, byteWidth, rawData, rawPos) {
for (var x = 0; x < byteWidth; x++) {
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
var val = pxData[pxPos + x] - up;
rawData[rawPos + x] = val;
}
}
function filterSumUp(pxData, pxPos, byteWidth) {
var sum = 0;
var length = pxPos + byteWidth;
for (var x = pxPos; x < length; x++) {
var up = pxPos > 0 ? pxData[x - byteWidth] : 0;
var val = pxData[x] - up;
sum += Math.abs(val);
}
return sum;
}
function filterAvg(pxData, pxPos, byteWidth, rawData, rawPos, bpp) {
for (var x = 0; x < byteWidth; x++) {
var left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
var val = pxData[pxPos + x] - ((left + up) >> 1);
rawData[rawPos + x] = val;
}
}
function filterSumAvg(pxData, pxPos, byteWidth, bpp) {
var sum = 0;
for (var x = 0; x < byteWidth; x++) {
var left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
var val = pxData[pxPos + x] - ((left + up) >> 1);
sum += Math.abs(val);
}
return sum;
}
function filterPaeth(pxData, pxPos, byteWidth, rawData, rawPos, bpp) {
for (var x = 0; x < byteWidth; x++) {
var left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
var upleft = pxPos > 0 && x >= bpp ? pxData[pxPos + x - (byteWidth + bpp)] : 0;
var val = pxData[pxPos + x] - paethPredictor(left, up, upleft);
rawData[rawPos + x] = val;
}
}
function filterSumPaeth(pxData, pxPos, byteWidth, bpp) {
var sum = 0;
for (var x = 0; x < byteWidth; x++) {
var left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
var upleft = pxPos > 0 && x >= bpp ? pxData[pxPos + x - (byteWidth + bpp)] : 0;
var val = pxData[pxPos + x] - paethPredictor(left, up, upleft);
sum += Math.abs(val);
}
return sum;
}
var filters = {
0: filterNone,
1: filterSub,
2: filterUp,
3: filterAvg,
4: filterPaeth
};
var filterSums = {
0: filterSumNone,
1: filterSumSub,
2: filterSumUp,
3: filterSumAvg,
4: filterSumPaeth
};
module.exports = function(pxData, width, height, options, bpp) {
var filterTypes;
if (!('filterType' in options) || options.filterType === -1) {
filterTypes = [0, 1, 2, 3, 4];
}
else if (typeof options.filterType === 'number') {
filterTypes = [options.filterType];
}
else {
throw new Error('unrecognised filter types');
}
if (options.bitDepth === 16) {
bpp *= 2;
}
var byteWidth = width * bpp;
var rawPos = 0;
var pxPos = 0;
var rawData = new Buffer((byteWidth + 1) * height);
var sel = filterTypes[0];
for (var y = 0; y < height; y++) {
if (filterTypes.length > 1) {
// find best filter for this line (with lowest sum of values)
var min = Infinity;
for (var i = 0; i < filterTypes.length; i++) {
var sum = filterSums[filterTypes[i]](pxData, pxPos, byteWidth, bpp);
if (sum < min) {
sel = filterTypes[i];
min = sum;
}
}
}
rawData[rawPos] = sel;
rawPos++;
filters[sel](pxData, pxPos, byteWidth, rawData, rawPos, bpp);
rawPos += byteWidth;
pxPos += byteWidth;
}
return rawData;
};