UNPKG

4.28 kBJavaScriptView Raw
1"use strict";
2
3let paethPredictor = require("./paeth-predictor");
4
5function filterNone(pxData, pxPos, byteWidth, rawData, rawPos) {
6 for (let x = 0; x < byteWidth; x++) {
7 rawData[rawPos + x] = pxData[pxPos + x];
8 }
9}
10
11function filterSumNone(pxData, pxPos, byteWidth) {
12 let sum = 0;
13 let length = pxPos + byteWidth;
14
15 for (let i = pxPos; i < length; i++) {
16 sum += Math.abs(pxData[i]);
17 }
18 return sum;
19}
20
21function filterSub(pxData, pxPos, byteWidth, rawData, rawPos, bpp) {
22 for (let x = 0; x < byteWidth; x++) {
23 let left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
24 let val = pxData[pxPos + x] - left;
25
26 rawData[rawPos + x] = val;
27 }
28}
29
30function filterSumSub(pxData, pxPos, byteWidth, bpp) {
31 let sum = 0;
32 for (let x = 0; x < byteWidth; x++) {
33 let left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
34 let val = pxData[pxPos + x] - left;
35
36 sum += Math.abs(val);
37 }
38
39 return sum;
40}
41
42function filterUp(pxData, pxPos, byteWidth, rawData, rawPos) {
43 for (let x = 0; x < byteWidth; x++) {
44 let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
45 let val = pxData[pxPos + x] - up;
46
47 rawData[rawPos + x] = val;
48 }
49}
50
51function filterSumUp(pxData, pxPos, byteWidth) {
52 let sum = 0;
53 let length = pxPos + byteWidth;
54 for (let x = pxPos; x < length; x++) {
55 let up = pxPos > 0 ? pxData[x - byteWidth] : 0;
56 let val = pxData[x] - up;
57
58 sum += Math.abs(val);
59 }
60
61 return sum;
62}
63
64function filterAvg(pxData, pxPos, byteWidth, rawData, rawPos, bpp) {
65 for (let x = 0; x < byteWidth; x++) {
66 let left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
67 let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
68 let val = pxData[pxPos + x] - ((left + up) >> 1);
69
70 rawData[rawPos + x] = val;
71 }
72}
73
74function filterSumAvg(pxData, pxPos, byteWidth, bpp) {
75 let sum = 0;
76 for (let x = 0; x < byteWidth; x++) {
77 let left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
78 let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
79 let val = pxData[pxPos + x] - ((left + up) >> 1);
80
81 sum += Math.abs(val);
82 }
83
84 return sum;
85}
86
87function filterPaeth(pxData, pxPos, byteWidth, rawData, rawPos, bpp) {
88 for (let x = 0; x < byteWidth; x++) {
89 let left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
90 let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
91 let upleft =
92 pxPos > 0 && x >= bpp ? pxData[pxPos + x - (byteWidth + bpp)] : 0;
93 let val = pxData[pxPos + x] - paethPredictor(left, up, upleft);
94
95 rawData[rawPos + x] = val;
96 }
97}
98
99function filterSumPaeth(pxData, pxPos, byteWidth, bpp) {
100 let sum = 0;
101 for (let x = 0; x < byteWidth; x++) {
102 let left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
103 let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
104 let upleft =
105 pxPos > 0 && x >= bpp ? pxData[pxPos + x - (byteWidth + bpp)] : 0;
106 let val = pxData[pxPos + x] - paethPredictor(left, up, upleft);
107
108 sum += Math.abs(val);
109 }
110
111 return sum;
112}
113
114let filters = {
115 0: filterNone,
116 1: filterSub,
117 2: filterUp,
118 3: filterAvg,
119 4: filterPaeth,
120};
121
122let filterSums = {
123 0: filterSumNone,
124 1: filterSumSub,
125 2: filterSumUp,
126 3: filterSumAvg,
127 4: filterSumPaeth,
128};
129
130module.exports = function (pxData, width, height, options, bpp) {
131 let filterTypes;
132 if (!("filterType" in options) || options.filterType === -1) {
133 filterTypes = [0, 1, 2, 3, 4];
134 } else if (typeof options.filterType === "number") {
135 filterTypes = [options.filterType];
136 } else {
137 throw new Error("unrecognised filter types");
138 }
139
140 if (options.bitDepth === 16) {
141 bpp *= 2;
142 }
143 let byteWidth = width * bpp;
144 let rawPos = 0;
145 let pxPos = 0;
146 let rawData = Buffer.alloc((byteWidth + 1) * height);
147
148 let sel = filterTypes[0];
149
150 for (let y = 0; y < height; y++) {
151 if (filterTypes.length > 1) {
152 // find best filter for this line (with lowest sum of values)
153 let min = Infinity;
154
155 for (let i = 0; i < filterTypes.length; i++) {
156 let sum = filterSums[filterTypes[i]](pxData, pxPos, byteWidth, bpp);
157 if (sum < min) {
158 sel = filterTypes[i];
159 min = sum;
160 }
161 }
162 }
163
164 rawData[rawPos] = sel;
165 rawPos++;
166 filters[sel](pxData, pxPos, byteWidth, rawData, rawPos, bpp);
167 rawPos += byteWidth;
168 pxPos += byteWidth;
169 }
170 return rawData;
171};