Browse Source

optimize jpg embed extraction

pull/54/head
coomdev 2 years ago
parent
commit
ec5e075927
  1. 2
      README.md
  2. 444
      chrome/dist/main.js
  3. 2
      chrome/manifest.json
  4. 444
      dist/main.js
  5. 444
      firefox/dist/main.js
  6. 2
      firefox/manifest.json
  7. 2
      firefox_update.json
  8. 2
      main.meta.js
  9. 446
      main.user.js
  10. BIN
      pngextraembedder-0.288.xpi
  11. BIN
      pngextraembedder-0.289.xpi
  12. BIN
      pngextraembedder-0.290.xpi
  13. BIN
      pngextraembedder-0.291.xpi
  14. BIN
      pngextraembedder-0.292.xpi
  15. BIN
      pngextraembedder-0.294.xpi
  16. BIN
      pngextraembedder-0.295.xpi
  17. BIN
      pngextraembedder-0.299.xpi
  18. BIN
      pngextraembedder-0.302.xpi
  19. BIN
      pngextraembedder-0.305.xpi
  20. BIN
      pngextraembedder-0.306.xpi
  21. 471
      src/f5stego.ts
  22. 7
      src/main.ts

2
README.md

@ -25,7 +25,7 @@ Please report any issue you have with those (only for mainstream browsers)
Also, use this if you plan to use b4k's archive. Also, use this if you plan to use b4k's archive.
- [Install 4chanX (recommended)](https://www.4chan-x.net/builds/4chan-X.user.js) - [Install 4chanX (recommended)](https://www.4chan-x.net/builds/4chan-X.user.js)
- Install the correct WebExtension for your Browser ([Firefox](https://git.coom.tech/fuckjannies/lolipiss/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/pngextraembedder-0.305.xpi) or Chrome-based (Down for "maintainance")) - Install the correct WebExtension for your Browser ([Firefox](https://git.coom.tech/fuckjannies/lolipiss/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/pngextraembedder-0.306.xpi) or Chrome-based (Down for "maintainance"))
For FF users, the extension is signed so you can just drag and drop it on your about:addons tab. For FF users, the extension is signed so you can just drag and drop it on your about:addons tab.

444
chrome/dist/main.js

File diff suppressed because one or more lines are too long

2
chrome/manifest.json

@ -2,7 +2,7 @@
"manifest_version": 3, "manifest_version": 3,
"name": "PngExtraEmbedder", "name": "PngExtraEmbedder",
"description": "Discover embedded files on 4chan and archives!", "description": "Discover embedded files on 4chan and archives!",
"version": "0.305", "version": "0.306",
"icons": { "icons": {
"64": "1449696017588.png" "64": "1449696017588.png"
}, },

444
dist/main.js

File diff suppressed because one or more lines are too long

444
firefox/dist/main.js

File diff suppressed because one or more lines are too long

2
firefox/manifest.json

@ -7,7 +7,7 @@
}, },
"name": "PngExtraEmbedder", "name": "PngExtraEmbedder",
"description": "Discover embedded files on 4chan and archives!", "description": "Discover embedded files on 4chan and archives!",
"version": "0.305", "version": "0.306",
"icons": { "icons": {
"64": "1449696017588.png" "64": "1449696017588.png"
}, },

2
firefox_update.json

@ -1 +1 @@
{"addons":{"{34ac4994-07f2-44d2-8599-682516a6c6a6}":{"updates":[{"version":"0.305","update_link":"https://git.coom.tech/fuckjannies/lolipiss/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/pngextraembedder-0.305.xpi"}]}}} {"addons":{"{34ac4994-07f2-44d2-8599-682516a6c6a6}":{"updates":[{"version":"0.306","update_link":"https://git.coom.tech/fuckjannies/lolipiss/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/pngextraembedder-0.306.xpi"}]}}}

2
main.meta.js

@ -1,7 +1,7 @@
// ==UserScript== // ==UserScript==
// @name PNGExtraEmbed // @name PNGExtraEmbed
// @namespace https://coom.tech/ // @namespace https://coom.tech/
// @version 0.305 // @version 0.306
// @description uhh // @description uhh
// @author You // @author You
// @match https://boards.4channel.org/* // @match https://boards.4channel.org/*

446
main.user.js

File diff suppressed because one or more lines are too long

BIN
pngextraembedder-0.288.xpi

Binary file not shown.

BIN
pngextraembedder-0.289.xpi

Binary file not shown.

BIN
pngextraembedder-0.290.xpi

Binary file not shown.

BIN
pngextraembedder-0.291.xpi

Binary file not shown.

BIN
pngextraembedder-0.292.xpi

Binary file not shown.

BIN
pngextraembedder-0.294.xpi

Binary file not shown.

BIN
pngextraembedder-0.295.xpi

Binary file not shown.

BIN
pngextraembedder-0.299.xpi

Binary file not shown.

BIN
pngextraembedder-0.302.xpi

Binary file not shown.

BIN
pngextraembedder-0.305.xpi

Binary file not shown.

BIN
pngextraembedder-0.300.xpi → pngextraembedder-0.306.xpi

Binary file not shown.

471
src/f5stego.ts

@ -1,3 +1,4 @@
/* eslint-disable no-constant-condition */
/* This software is licensed under the MIT License. /* This software is licensed under the MIT License.
Copyright (c) 2016 desudesutalk Copyright (c) 2016 desudesutalk
@ -46,7 +47,6 @@
CONDITIONS OF ANY KIND, either express or implied. See the License for the CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License. specific language governing permissions and limitations under the License.
jpeg encoder license: jpeg encoder license:
JPEG encoder ported to JavaScript, optimized by Andreas Ritter JPEG encoder ported to JavaScript, optimized by Andreas Ritter
@ -104,14 +104,67 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
import { BitstreamWriter, revbyte } from "./bitstream";
/* global define, module, exports */ /* global define, module, exports */
/* jshint sub:true */ /* jshint sub:true */
// Standard Huffman tables for coder initialization // Standard Huffman tables for coder initialization
// =========================================================================================================== // ===========================================================================================================
var bitcode = new Array(65535),
function* f5get(): Generator<void, Buffer, number> {
let extrBit = 0;
//var pm = this.#stegShuffle(coeff),
// gamma = pm.gamma,
// gammaI = 0;
let k = 0;
for (let i = 0; i < 4; ++i) {
const b = (yield);
k |= b << i;
}
k = (k & 15) + 1;
let toread = 8; // length is on 16 bits, unless bit 0 on the second byte is 1, in which case it's 23 bits
let len = 0;
while (toread--) {
len = len * 2 + (yield);
}
const b = yield;
toread += 8;
if (b)
toread += 7;
else
len *= 2;
while (toread--) {
len = len * 2 + (yield);
}
let rlen = revbyte(len, b ? 23 : 16);
len = rlen;
if (len >= 256) // don't know if length decoding is correct so let's be safe and trim
len = rlen = 256;
len *= 8; // bytes to bits
// k must be 1
const chunks: Uint8Array[] = [];
const bw = new BitstreamWriter({
write(chunk) {
chunks.push(chunk);
},
});
while (len) {
extrBit = yield;
bw.write(1, extrBit);
len--;
}
bw.end();
return Buffer.concat(chunks).slice(0, rlen);
}
const bitcode = new Array(65535),
category = new Array(65535), category = new Array(65535),
std_dc_luminance_nrcodes = [0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], std_dc_luminance_nrcodes = [0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
std_dc_luminance_values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], std_dc_luminance_values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
@ -167,18 +220,18 @@ var bitcode = new Array(65535),
]; ];
function _initCategoryNumber() { function _initCategoryNumber() {
var nrlower = 1; let nrlower = 1;
var nrupper = 2; let nrupper = 2;
for (var cat = 1; cat <= 15; cat++) { for (let cat = 1; cat <= 15; cat++) {
//Positive numbers //Positive numbers
for (var nr = nrlower; nr < nrupper; nr++) { for (let nr = nrlower; nr < nrupper; nr++) {
category[32767 + nr] = cat; category[32767 + nr] = cat;
bitcode[32767 + nr] = []; bitcode[32767 + nr] = [];
bitcode[32767 + nr][1] = cat; bitcode[32767 + nr][1] = cat;
bitcode[32767 + nr][0] = nr; bitcode[32767 + nr][0] = nr;
} }
//Negative numbers //Negative numbers
for (var nrneg = -(nrupper - 1); nrneg <= -nrlower; nrneg++) { for (let nrneg = -(nrupper - 1); nrneg <= -nrlower; nrneg++) {
category[32767 + nrneg] = cat; category[32767 + nrneg] = cat;
bitcode[32767 + nrneg] = []; bitcode[32767 + nrneg] = [];
bitcode[32767 + nrneg][1] = cat; bitcode[32767 + nrneg][1] = cat;
@ -192,11 +245,11 @@ function _initCategoryNumber() {
_initCategoryNumber(); _initCategoryNumber();
function _computeHuffmanTbl(nrcodes: number[], std_table: number[]) { function _computeHuffmanTbl(nrcodes: number[], std_table: number[]) {
var codevalue = 0; let codevalue = 0;
var pos_in_table = 0; let pos_in_table = 0;
var HT: number[][] = []; const HT: number[][] = [];
for (var k = 1; k <= 16; k++) { for (let k = 1; k <= 16; k++) {
for (var j = 1; j <= nrcodes[k]; j++) { for (let j = 1; j <= nrcodes[k]; j++) {
HT[std_table[pos_in_table]] = []; HT[std_table[pos_in_table]] = [];
HT[std_table[pos_in_table]][0] = codevalue; HT[std_table[pos_in_table]][0] = codevalue;
HT[std_table[pos_in_table]][1] = k; HT[std_table[pos_in_table]][1] = k;
@ -213,7 +266,6 @@ const YDC_HT = _computeHuffmanTbl(std_dc_luminance_nrcodes, std_dc_luminance_val
YAC_HT = _computeHuffmanTbl(std_ac_luminance_nrcodes, std_ac_luminance_values), YAC_HT = _computeHuffmanTbl(std_ac_luminance_nrcodes, std_ac_luminance_values),
UVAC_HT = _computeHuffmanTbl(std_ac_chrominance_nrcodes, std_ac_chrominance_values); UVAC_HT = _computeHuffmanTbl(std_ac_chrominance_nrcodes, std_ac_chrominance_values);
type FrameComponentType = { type FrameComponentType = {
componentId: number, componentId: number,
h: number, h: number,
@ -257,88 +309,56 @@ export class f5stego {
constructor(key: ArrayLike<number>, private maxPixels: number = 4096 * 4096) { constructor(key: ArrayLike<number>, private maxPixels: number = 4096 * 4096) {
} }
embed(image: Uint8Array, data: ArrayLike<number>, k?: number) { embed(image: Uint8Array, data: ArrayLike<number>, k: number) {
this.parse(image); this.parse(image);
this.f5put(data, k); this.f5put(data, k);
return this.pack(); return this.pack();
}; }
extract(image: Uint8Array) { extract(image: Uint8Array) {
this.parse(image, true); try {
return this.f5get(); this.gengen = f5get();
}; this.gengen.next(); // run shit
this.parse(image, true);
return this.f5get();
} catch (e) {
if (e instanceof Buffer)
return e;
throw e;
}
}
#_raw?: Uint8Array; #_raw?: Uint8Array;
#jfif?: any; #jfif?: any;
#APPn?: any; #APPn?: any;
#qts?: any[]; #qts?: any[];
#frame: FrameType | null = null; #frame: FrameType | null = null;
#tail: Uint8Array | null = null; #tail: Uint8Array | null = null;
#_analyze(coeff: Int16Array) {
var _one = 0,
_zero = 0,
_large, _ratio, usable, i, k, embedded, matched, changed;
for (i = 0; i < coeff.length; i++) {
if (i % 64 === 0) continue;
if (coeff[i] === 0) _zero++;
if (coeff[i] == 1 || coeff[i] == -1) _one++;
}
_large = coeff.length - _zero - _one - coeff.length / 64;
_ratio = _one / (_large + _one);
var res = {
'capacity': [0, ((_large + (0.49 * _one)) >> 3) - 1],
'coeff_total': coeff.length,
'coeff_large': _large,
'coeff_zero': _zero,
'coeff_one': _one,
'coeff_one_ratio': _one / (_large + _one)
};
for (i = 2; i < 17; i++) {
k = (1 << i) - 1;
usable = _large + _one;
embedded = 0;
while (usable > k) {
matched = (usable / k / (1 << i) / (1 << i)) | 0;
usable -= matched * k;
changed = (usable * (1 - _ratio) / k * 0.96) | 0;
usable -= changed * k;
embedded += changed + matched;
k++;
}
res.capacity[i] = ((i * embedded) >> 3) - 1;
}
return res;
}
#_f5write(coeff: Int16Array, data: ArrayLike<number>, k: number) { #_f5write(coeff: Int16Array, data: ArrayLike<number>, k: number) {
var coeff_count = coeff.length; const coeff_count = coeff.length;
var _changed = 0, let _changed = 0,
_embedded = 0, _embedded = 0,
_examined = 0, _examined = 0,
_thrown = 0, _thrown = 0,
shuffled_index = 0, shuffled_index = 0,
i, n, ii; i, ii: number;
//let { gamma, pm } = this.#stegShuffle(coeff_count); //let { gamma, pm } = this.#stegShuffle(coeff_count);
//let gammaI = 0; //let gammaI = 0;
var next_bit_to_embed = 0, let next_bit_to_embed = 0,
byte_to_embed = data.length, byte_to_embed = data.length,
data_idx = 0, data_idx = 0,
available_bits_to_embed = 0; available_bits_to_embed = 0;
n = (1 << k) - 1; const n = (1 << k) - 1;
byte_to_embed = k - 1; byte_to_embed = k - 1;
byte_to_embed ^= 0; // nop byte_to_embed ^= 0; // nop
@ -353,7 +373,7 @@ export class f5stego {
if (shuffled_index % 64 === 0 || coeff[shuffled_index] === 0) continue; if (shuffled_index % 64 === 0 || coeff[shuffled_index] === 0) continue;
var cc = coeff[shuffled_index]; const cc = coeff[shuffled_index];
_examined++; _examined++;
if (cc > 0 && (cc & 1) != next_bit_to_embed) { if (cc > 0 && (cc & 1) != next_bit_to_embed) {
@ -385,7 +405,7 @@ export class f5stego {
if (k != 1) { if (k != 1) {
//ii--; //ii--;
var is_last_byte = false, let is_last_byte = false,
k_bits_to_embed = 0; k_bits_to_embed = 0;
while (!is_last_byte || (available_bits_to_embed !== 0 && is_last_byte)) { while (!is_last_byte || (available_bits_to_embed !== 0 && is_last_byte)) {
@ -409,8 +429,8 @@ export class f5stego {
} }
var code_word = []; const code_word: number[] = [];
var ci = null; let ci: number | null = null;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
while (true) { while (true) {
@ -427,8 +447,8 @@ export class f5stego {
_examined += n; _examined += n;
while (true) { while (true) {
var vhash = 0, let vhash = 0;
extracted_bit; let extracted_bit;
for (i = 0; i < code_word.length; i++) { for (i = 0; i < code_word.length; i++) {
if (coeff[code_word[i]] > 0) { if (coeff[code_word[i]] > 0) {
@ -484,32 +504,10 @@ export class f5stego {
}; };
} }
analyze() { f5put(data: ArrayLike<number>, k: number) {
if (!this.#frame)
throw "Parser not run";
var i, comp = this.#frame.components[0];
if (comp.componentId != 1) {
for (i = 0; i < this.#frame.components.length; i++) {
if (this.#frame.components[i].componentId == 1) {
comp = this.#frame.components[i];
break;
}
}
}
if (!('blocks' in comp)) {
throw "Blocks failed to be parsed";
}
return this.#_analyze(comp.blocks);
};
f5put(data: ArrayLike<number>, k?: number) {
if (!this.#frame) if (!this.#frame)
throw "Parser not run"; throw "Parser not run";
var t, i, comp = this.#frame.components[0]; let t, i, comp = this.#frame.components[0];
// Looks funny, but who knows? // Looks funny, but who knows?
// From the other hand you need ~80MB jpeg to hide 8MB of data and this will be bigger than 4096x4096 pixels // From the other hand you need ~80MB jpeg to hide 8MB of data and this will be bigger than 4096x4096 pixels
@ -537,69 +535,20 @@ export class f5stego {
} }
} }
if (k) {
if (!('blocks' in comp)) {
throw "Blocks failed to be parsed";
}
return this.#_f5write(comp.blocks, t, k);
}
if (!('blocks' in comp)) { if (!('blocks' in comp)) {
throw "Blocks failed to be parsed"; throw "Blocks failed to be parsed";
} }
let ret: { return this.#_f5write(comp.blocks, t, k);
k: number;
embedded: number;
examined: number;
changed: number;
thrown: number;
efficiency: string;
stats?: {
capacity: number[];
coeff_total: number;
coeff_large: number;
coeff_zero: number;
coeff_one: number;
coeff_one_ratio: number;
}
};
let prop = this.#_analyze(comp.blocks);
k = 0;
for (i = prop.capacity.length - 1; i >= 0; i--) {
if (prop.capacity[i] >= t.length) {
k = i;
break;
}
}
if (k === 0) throw 'capacity exceeded';
try {
ret = this.#_f5write(comp.blocks, t, k);
} catch (e) {
k--;
if (k === 0) throw 'capacity exceeded';
ret = this.#_f5write(comp.blocks, t, k);
}
ret['stats'] = prop;
return ret;
} }
f5get() { f5get() {
if (!this.#frame) if (!this.#frame)
throw "Parser not run"; throw "Parser not run";
var comp = this.#frame.components[0]; let comp = this.#frame.components[0];
if (comp.componentId != 1) { if (comp.componentId != 1) {
for (var i = 0; i < this.#frame.components.length; i++) { for (let i = 0; i < this.#frame.components.length; i++) {
if (this.#frame.components[i].componentId == 1) { if (this.#frame.components[i].componentId == 1) {
comp = this.#frame.components[i]; comp = this.#frame.components[i];
break; break;
@ -611,47 +560,45 @@ export class f5stego {
throw "Blocks failed to be parsed"; throw "Blocks failed to be parsed";
} }
var coeff = new Int16Array(comp.blocks.length); const coeff = new Int16Array(comp.blocks.length);
coeff.set(comp.blocks); coeff.set(comp.blocks);
var pos = -1, let pos = -1,
extrBit = 0, extrBit = 0;
cCount = coeff.length - 1; const cCount = coeff.length - 1;
//var pm = this.#stegShuffle(coeff), //var pm = this.#stegShuffle(coeff),
// gamma = pm.gamma, // gamma = pm.gamma,
// gammaI = 0; // gammaI = 0;
var n, k = 0; let k = 0;
var out = new Uint8Array((coeff.length / 8) | 0), const out = new Uint8Array((coeff.length / 8) | 0);
extrByte = 0, let extrByte = 0;
outPos = 0, let outPos = 0;
bitsAvail = 0, let bitsAvail = 0;
code = 0, let code = 0;
hash = 0; let hash = 0;
while (bitsAvail < 4) { while (bitsAvail < 4) {
pos++; pos++;
//console.log(pos)
if (coeff[pos] === 0) { if (coeff[pos] === 0) {
continue; continue;
} }
extrBit = coeff[pos] & 1; extrBit = coeff[pos] & 1;
if (coeff[pos] < 0) { if (coeff[pos] < 0) {
extrBit = 1 - extrBit; extrBit = 1 - extrBit;
} }
k |= extrBit << bitsAvail; k |= extrBit << bitsAvail;
bitsAvail++; bitsAvail++;
} }
//k = (k ^ gamma[gammaI++] & 15) + 1; //k = (k ^ gamma[gammaI++] & 15) + 1;
k = (k & 15) + 1; k = (k & 15) + 1;
n = (1 << k) - 1; const n = (1 << k) - 1;
bitsAvail = 0; bitsAvail = 0;
@ -718,7 +665,7 @@ export class f5stego {
extrByte = extrByte >> 8; extrByte = extrByte >> 8;
} }
var s = 2, let s = 2,
l = out[0]; l = out[0];
if (out[1] & 128) { if (out[1] & 128) {
@ -727,21 +674,21 @@ export class f5stego {
} else { } else {
l += out[1] << 8; l += out[1] << 8;
} }
return out.subarray(s, s + l); return out.subarray(s, s + l);
} }
gengen!: Generator<void, Buffer, number>;
parse(data: Uint8Array, tolerant = false) { parse(data: Uint8Array, tolerant = false) {
var offset = 0; let offset = 0;
function _buildHuffmanTable(nrcodes: Uint8Array, values: Uint8Array) { function _buildHuffmanTable(nrcodes: Uint8Array, values: Uint8Array) {
var codevalue = 0, let codevalue = 0;
pos_in_table = 0, let pos_in_table = 0;
HT = new Uint16Array(65536); const HT = new Uint16Array(65536);
for (var k = 0; k < 16; k++) { for (let k = 0; k < 16; k++) {
for (var j = 0; j < nrcodes[k]; j++) { for (let j = 0; j < nrcodes[k]; j++) {
for (var i = codevalue << (15 - k), cntTo = ((codevalue + 1) << (15 - k)); i < cntTo; i++) { for (let i = codevalue << (15 - k), cntTo = ((codevalue + 1) << (15 - k)); i < cntTo; i++) {
HT[i] = values[pos_in_table] + ((k + 1) << 8); HT[i] = values[pos_in_table] + ((k + 1) << 8);
} }
pos_in_table++; pos_in_table++;
@ -752,7 +699,7 @@ export class f5stego {
return HT; return HT;
} }
function decodeScan(data: ArrayLike<number>, const decodeScan = (data: ArrayLike<number>,
offset: number, offset: number,
frame: FrameType, frame: FrameType,
components: DiscriminateUnion<FrameComponentType, 'huffmanTableDC', Uint16Array>[], components: DiscriminateUnion<FrameComponentType, 'huffmanTableDC', Uint16Array>[],
@ -760,28 +707,28 @@ export class f5stego {
spectralStart: number, spectralStart: number,
spectralEnd: number, spectralEnd: number,
successivePrev: number, successivePrev: number,
successive: number) { successive: number) => {
var startOffset = offset, const startOffset = offset;
bitsData = 0, let bitsData = 0,
bitsCount = 0, bitsCount = 0,
eobrun = 0, eobrun = 0;
p1 = 1 << successive, /* 1 in the bit position being coded */ const p1 = 1 << successive; /* 1 in the bit position being coded */
m1 = -1 << successive; /* -1 in the bit position being coded */ const m1 = -1 << successive; /* -1 in the bit position being coded */
function decodeBaseline(component: typeof components[0], pos: number) { const decodeBaseline = (component: typeof components[0], pos: number) => {
while (bitsCount < 16) { while (bitsCount < 16) {
bitsData = (bitsData << 8) + (data[offset] | 0); bitsData = (bitsData << 8) + (data[offset] | 0);
bitsCount += 8; bitsCount += 8;
if (data[offset] == 0xFF) offset++; if (data[offset] == 0xFF) offset++;
offset++; offset++;
} }
var t = component.huffmanTableDC[(bitsData >>> (bitsCount - 16)) & 0xFFFF]; let t = component.huffmanTableDC[(bitsData >>> (bitsCount - 16)) & 0xFFFF];
if (!t) throw "invalid huffman sequence"; if (!t) throw "invalid huffman sequence";
bitsCount -= t >>> 8; bitsCount -= t >>> 8;
t &= 255; t &= 255;
var diff = 0; let diff = 0;
if (t !== 0) { if (t !== 0) {
while (bitsCount < t) { while (bitsCount < t) {
bitsData = (bitsData << 8) + data[offset++]; bitsData = (bitsData << 8) + data[offset++];
@ -794,7 +741,7 @@ export class f5stego {
} }
component.blocksDC[pos >> 6] = (component.pred += diff); component.blocksDC[pos >> 6] = (component.pred += diff);
var k = 1, let k = 1,
s, r; s, r;
while (k < 64) { while (k < 64) {
@ -823,22 +770,33 @@ export class f5stego {
if ((bitsData & 0xff) == 0xFF) offset++; if ((bitsData & 0xff) == 0xFF) offset++;
bitsCount += 8; bitsCount += 8;
} }
component.blocks[pos + k] = (bitsData >>> (bitsCount - s)) & ((1 << s) - 1); if (component.componentId == 1) {
// EMIT BITS HERE
component.blocks[pos + k] = (bitsData >>> (bitsCount - s)) & ((1 << s) - 1);
if (component.blocks[pos + k] < 1 << (s - 1)) component.blocks[pos + k] += (-1 << s) + 1;
if (component.blocks[pos + k] != 0) {
const v = (component.blocks[pos + k] < 0) ? 1 - (component.blocks[pos + k] & 1) : (component.blocks[pos + k] & 1);
const it = this.gengen.next(v);
if (it.done) {
throw it.value;
}
}
}
bitsCount -= s; bitsCount -= s;
if (component.blocks[pos + k] < 1 << (s - 1)) component.blocks[pos + k] += (-1 << s) + 1;
k++; k++;
} }
} };
function decodeDCFirst(component: typeof components[0], pos: number) { function decodeDCFirst(component: typeof components[0], pos: number) {
var diff = 0; let diff = 0;
while (bitsCount < 16) { while (bitsCount < 16) {
bitsData = (bitsData << 8) + (data[offset] | 0); bitsData = (bitsData << 8) + (data[offset] | 0);
bitsCount += 8; bitsCount += 8;
if (data[offset] == 0xFF) offset++; if (data[offset] == 0xFF) offset++;
offset++; offset++;
} }
var t = component.huffmanTableDC[(bitsData >>> (bitsCount - 16)) & 0xFFFF]; let t = component.huffmanTableDC[(bitsData >>> (bitsCount - 16)) & 0xFFFF];
if (!t) throw "invalid huffman sequence"; if (!t) throw "invalid huffman sequence";
bitsCount -= t >>> 8; bitsCount -= t >>> 8;
t &= 255; t &= 255;
@ -874,8 +832,7 @@ export class f5stego {
return; return;
} }
let k = spectralStart,
var k = spectralStart,
s, r; s, r;
while (k <= spectralEnd) { while (k <= spectralEnd) {
@ -923,9 +880,8 @@ export class f5stego {
} }
} }
function decodeACSuccessive(component: typeof components[0], pos: number) { function decodeACSuccessive(component: typeof components[0], pos: number) {
var k = spectralStart, let k = spectralStart,
r, s; r, s;
if (frame == null) if (frame == null)
throw "Frame not defined"; throw "Frame not defined";
@ -1003,7 +959,7 @@ export class f5stego {
} }
} }
var decodeFn; let decodeFn;
if (frame.progressive) { if (frame.progressive) {
if (spectralStart === 0) if (spectralStart === 0)
@ -1014,7 +970,7 @@ export class f5stego {
decodeFn = decodeBaseline; decodeFn = decodeBaseline;
} }
var marker, mcuExpected, i, j, k, n, mcusPerLine, mcusPerRow, x, y; let marker, mcuExpected, i, j, k, n, mcusPerLine, mcusPerRow, x, y;
if (components.length == 1) { if (components.length == 1) {
mcusPerLine = components[0].blocksPerLine; mcusPerLine = components[0].blocksPerLine;
@ -1101,17 +1057,17 @@ export class f5stego {
offset -= (bitsCount / 8) | 0; offset -= (bitsCount / 8) | 0;
if (data[offset - 1] == 0xFF) offset--; if (data[offset - 1] == 0xFF) offset--;
return offset - startOffset; return offset - startOffset;
} };
function readUint16() { function readUint16() {
var value = (data[offset] << 8) | data[offset + 1]; const value = (data[offset] << 8) | data[offset + 1];
offset += 2; offset += 2;
return value; return value;
} }
function readDataBlock() { function readDataBlock() {
var length = readUint16(); const length = readUint16();
var array = data.subarray(offset, offset + length - 2); const array = data.subarray(offset, offset + length - 2);
offset += array.length; offset += array.length;
return array; return array;
} }
@ -1123,9 +1079,9 @@ export class f5stego {
this.#frame = null; this.#frame = null;
this.#tail = null; this.#tail = null;
var markerHi, markerLo, i, j, resetInterval, component; let markerHi, markerLo, i, j, resetInterval, component;
let huffmanTablesAC: Uint16Array[] = []; const huffmanTablesAC: Uint16Array[] = [];
let huffmanTablesDC: Uint16Array[] = []; const huffmanTablesDC: Uint16Array[] = [];
while (1) { while (1) {
if (offset >= data.length) { if (offset >= data.length) {
@ -1173,18 +1129,18 @@ export class f5stego {
if (this.#frame.scanLines * this.#frame.samplesPerLine > this.maxPixels) throw "Image is too big."; if (this.#frame.scanLines * this.#frame.samplesPerLine > this.maxPixels) throw "Image is too big.";
var componentsCount = data[offset++], const componentsCount = data[offset++];
componentId; let componentId;
var maxH = 0, let maxH = 0,
maxV = 0; maxV = 0;
for (i = 0; i < componentsCount; i++) { for (i = 0; i < componentsCount; i++) {
componentId = data[offset]; componentId = data[offset];
var h = data[offset + 1] >> 4; const h = data[offset + 1] >> 4;
var v = data[offset + 1] & 15; const v = data[offset + 1] & 15;
if (maxH < h) maxH = h; if (maxH < h) maxH = h;
if (maxV < v) maxV = v; if (maxV < v) maxV = v;
var qId = data[offset + 2]; const qId = data[offset + 2];
var l = this.#frame.components.push({ const l = this.#frame.components.push({
componentId: componentId, componentId: componentId,
h, h,
v, v,
@ -1196,14 +1152,14 @@ export class f5stego {
this.#frame.maxH = maxH; this.#frame.maxH = maxH;
this.#frame.maxV = maxV; this.#frame.maxV = maxV;
var mcusPerLine = Math.ceil(this.#frame.samplesPerLine / 8 / maxH); const mcusPerLine = Math.ceil(this.#frame.samplesPerLine / 8 / maxH);
var mcusPerColumn = Math.ceil(this.#frame.scanLines / 8 / maxV); const mcusPerColumn = Math.ceil(this.#frame.scanLines / 8 / maxV);
for (i = 0; i < this.#frame.components.length; i++) { for (i = 0; i < this.#frame.components.length; i++) {
component = this.#frame.components[i]; component = this.#frame.components[i];
var blocksPerLine = Math.ceil(Math.ceil(this.#frame.samplesPerLine / 8) * component.h / maxH); const blocksPerLine = Math.ceil(Math.ceil(this.#frame.samplesPerLine / 8) * component.h / maxH);
var blocksPerColumn = Math.ceil(Math.ceil(this.#frame.scanLines / 8) * component.v / maxV); const blocksPerColumn = Math.ceil(Math.ceil(this.#frame.scanLines / 8) * component.v / maxV);
var blocksPerLineForMcu = mcusPerLine * component.h; const blocksPerLineForMcu = mcusPerLine * component.h;
var blocksPerColumnForMcu = mcusPerColumn * component.v; const blocksPerColumnForMcu = mcusPerColumn * component.v;
this.#frame.components[i] = { this.#frame.components[i] = {
...component, ...component,
@ -1220,14 +1176,14 @@ export class f5stego {
} }
if (markerLo == 0xC4) { // DHT (Define Huffman Tables) if (markerLo == 0xC4) { // DHT (Define Huffman Tables)
var huffmanLength = readUint16(); const huffmanLength = readUint16();
for (i = 2; i < huffmanLength;) { for (i = 2; i < huffmanLength;) {
var huffmanTableSpec = data[offset++]; const huffmanTableSpec = data[offset++];
var codeLengths = new Uint8Array(16); const codeLengths = new Uint8Array(16);
var codeLengthSum = 0; let codeLengthSum = 0;
for (j = 0; j < 16; j++, offset++) for (j = 0; j < 16; j++, offset++)
codeLengthSum += (codeLengths[j] = data[offset]); codeLengthSum += (codeLengths[j] = data[offset]);
var huffmanValues = new Uint8Array(codeLengthSum); const huffmanValues = new Uint8Array(codeLengthSum);
for (j = 0; j < codeLengthSum; j++, offset++) for (j = 0; j < codeLengthSum; j++, offset++)
huffmanValues[j] = data[offset]; huffmanValues[j] = data[offset];
i += 17 + codeLengthSum; i += 17 + codeLengthSum;
@ -1247,22 +1203,22 @@ export class f5stego {
if (this.#frame == null) if (this.#frame == null)
throw "SOS before SOF"; throw "SOS before SOF";
readUint16(); readUint16();
var selectorsCount = data[offset++]; const selectorsCount = data[offset++];
var components = []; const components: FrameComponentType[] = [];
for (i = 0; i < selectorsCount; i++) { for (i = 0; i < selectorsCount; i++) {
var componentIndex = this.#frame.componentIds[data[offset++]]; const componentIndex = this.#frame.componentIds[data[offset++]];
component = this.#frame.components[componentIndex]; component = this.#frame.components[componentIndex];
var tableSpec = data[offset++]; const tableSpec = data[offset++];
component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4]; component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4];
component.huffmanTableAC = huffmanTablesAC[tableSpec & 15]; component.huffmanTableAC = huffmanTablesAC[tableSpec & 15];
components.push(component); components.push(component);
} }
var spectralStart = data[offset++]; const spectralStart = data[offset++];
var spectralEnd = data[offset++]; const spectralEnd = data[offset++];
var successiveApproximation = data[offset++]; const successiveApproximation = data[offset++];
var processed = decodeScan(data, offset, const processed = decodeScan(data, offset,
this.#frame, components as any, resetInterval, this.#frame, components as any, resetInterval,
spectralStart, spectralEnd, spectralStart, spectralEnd,
successiveApproximation >> 4, successiveApproximation & 15); successiveApproximation >> 4, successiveApproximation & 15);
@ -1295,7 +1251,7 @@ export class f5stego {
if (offset < data.length) this.#tail = data.subarray(offset); if (offset < data.length) this.#tail = data.subarray(offset);
return this; return this;
}; }
pack() { pack() {
let byteout: Uint8Array; let byteout: Uint8Array;
@ -1307,7 +1263,7 @@ export class f5stego {
// IO functions // IO functions
function writeByte(value: number) { function writeByte(value: number) {
var t; let t;
byteout[outpos++] = value; byteout[outpos++] = value;
if (outpos > poslast) { if (outpos > poslast) {
@ -1324,7 +1280,7 @@ export class f5stego {
} }
function writeBlock(block: Uint8Array) { function writeBlock(block: Uint8Array) {
var t; let t;
if (outpos + block.length > poslast) { if (outpos + block.length > poslast) {
t = new Uint8Array(byteout.length * 2 + block.length); t = new Uint8Array(byteout.length * 2 + block.length);
t.set(byteout); t.set(byteout);
@ -1359,7 +1315,7 @@ export class f5stego {
} }
function writeDQT(self: f5stego) { function writeDQT(self: f5stego) {
for (var i = 0; i < self.#qts!.length; i++) { for (let i = 0; i < self.#qts!.length; i++) {
writeWord(0xFFDB); // marker writeWord(0xFFDB); // marker
writeWord(self.#qts![i].length + 2); // length writeWord(self.#qts![i].length + 2); // length
writeBlock(self.#qts![i]); writeBlock(self.#qts![i]);
@ -1367,7 +1323,7 @@ export class f5stego {
} }
function writeAPPn(self: f5stego) { function writeAPPn(self: f5stego) {
for (var i = 0; i < self.#APPn.length; i++) { for (let i = 0; i < self.#APPn.length; i++) {
writeWord(0xFF00 | self.#APPn[i].app); writeWord(0xFF00 | self.#APPn[i].app);
writeWord(self.#APPn[i].data.length + 2); writeWord(self.#APPn[i].data.length + 2);
writeBlock(self.#APPn[i].data); writeBlock(self.#APPn[i].data);
@ -1384,8 +1340,8 @@ export class f5stego {
writeWord(self.#frame.samplesPerLine); writeWord(self.#frame.samplesPerLine);
writeByte(self.#frame.components.length); // nrofcomponents writeByte(self.#frame.components.length); // nrofcomponents
for (var i = 0; i < self.#frame.components.length; i++) { for (let i = 0; i < self.#frame.components.length; i++) {
var c = self.#frame.components[i]; const c = self.#frame.components[i];
writeByte(c.componentId); writeByte(c.componentId);
writeByte(c.h << 4 | c.v); writeByte(c.h << 4 | c.v);
writeByte(c.quantizationTable); writeByte(c.quantizationTable);
@ -1399,20 +1355,20 @@ export class f5stego {
writeWord(0xFFC4); // marker writeWord(0xFFC4); // marker
writeWord(31); // length writeWord(31); // length
writeByte(0); // HTYDCinfo writeByte(0); // HTYDCinfo
for (var i = 0; i < 16; i++) { for (let i = 0; i < 16; i++) {
writeByte(std_dc_luminance_nrcodes[i + 1]); writeByte(std_dc_luminance_nrcodes[i + 1]);
} }
for (var j = 0; j <= 11; j++) { for (let j = 0; j <= 11; j++) {
writeByte(std_dc_luminance_values[j]); writeByte(std_dc_luminance_values[j]);
} }
writeWord(0xFFC4); // marker writeWord(0xFFC4); // marker
writeWord(181); // length writeWord(181); // length
writeByte(0x10); // HTYACinfo writeByte(0x10); // HTYACinfo
for (var k = 0; k < 16; k++) { for (let k = 0; k < 16; k++) {
writeByte(std_ac_luminance_nrcodes[k + 1]); writeByte(std_ac_luminance_nrcodes[k + 1]);
} }
for (var l = 0; l <= 161; l++) { for (let l = 0; l <= 161; l++) {
writeByte(std_ac_luminance_values[l]); writeByte(std_ac_luminance_values[l]);
} }
@ -1420,20 +1376,20 @@ export class f5stego {
writeWord(0xFFC4); // marker writeWord(0xFFC4); // marker
writeWord(31); // length writeWord(31); // length
writeByte(1); // HTUDCinfo writeByte(1); // HTUDCinfo
for (var m = 0; m < 16; m++) { for (let m = 0; m < 16; m++) {
writeByte(std_dc_chrominance_nrcodes[m + 1]); writeByte(std_dc_chrominance_nrcodes[m + 1]);
} }
for (var n = 0; n <= 11; n++) { for (let n = 0; n <= 11; n++) {
writeByte(std_dc_chrominance_values[n]); writeByte(std_dc_chrominance_values[n]);
} }
writeWord(0xFFC4); // marker writeWord(0xFFC4); // marker
writeWord(181); // length writeWord(181); // length
writeByte(0x11); // HTUACinfo writeByte(0x11); // HTUACinfo
for (var o = 0; o < 16; o++) { for (let o = 0; o < 16; o++) {
writeByte(std_ac_chrominance_nrcodes[o + 1]); writeByte(std_ac_chrominance_nrcodes[o + 1]);
} }
for (var p = 0; p <= 161; p++) { for (let p = 0; p <= 161; p++) {
writeByte(std_ac_chrominance_values[p]); writeByte(std_ac_chrominance_values[p]);
} }
} }
@ -1447,8 +1403,8 @@ export class f5stego {
writeWord(6 + self.#frame.components.length * 2); // length writeWord(6 + self.#frame.components.length * 2); // length
writeByte(self.#frame.components.length); // nrofcomponents writeByte(self.#frame.components.length); // nrofcomponents
for (var i = 0; i < self.#frame.components.length; i++) { for (let i = 0; i < self.#frame.components.length; i++) {
var c = self.#frame.components[i]; const c = self.#frame.components[i];
writeByte(c.componentId); writeByte(c.componentId);
if (i === 0) { if (i === 0) {
writeByte(0); writeByte(0);
@ -1463,14 +1419,14 @@ export class f5stego {
} }
function processDU(comp: FrameComponentType, POS: number, DC: number, HTDC: number[][], HTAC: number[][]) { function processDU(comp: FrameComponentType, POS: number, DC: number, HTDC: number[][], HTAC: number[][]) {
var pos, posval, t; let pos, posval, t;
if (bytepos === 0) bytenew = 0; if (bytepos === 0) bytenew = 0;
if (!('blocks' in comp)) if (!('blocks' in comp))
throw "Blocks not parsed"; throw "Blocks not parsed";
var Diff = comp.blocksDC[POS >> 6] - DC; const Diff = comp.blocksDC[POS >> 6] - DC;
DC = comp.blocksDC[POS >> 6]; DC = comp.blocksDC[POS >> 6];
//Encode DC //Encode DC
if (Diff === 0) { if (Diff === 0) {
@ -1514,7 +1470,7 @@ export class f5stego {
} }
} }
//Encode ACs //Encode ACs
var end0pos = 63; // was const... which is crazy let end0pos = 63; // was const... which is crazy
for (; for (;
(end0pos > 0) && (comp.blocks[POS + end0pos] === 0); end0pos--) { } (end0pos > 0) && (comp.blocks[POS + end0pos] === 0); end0pos--) { }
//end0pos = first element in reverse order !=0 //end0pos = first element in reverse order !=0
@ -1535,16 +1491,16 @@ export class f5stego {
} }
return DC; return DC;
} }
var i = 1; let i = 1;
var lng; let lng;
while (i <= end0pos) { while (i <= end0pos) {
var startpos = i; const startpos = i;
for (; for (;
(comp.blocks[POS + i] === 0) && (i <= end0pos); ++i) { } (comp.blocks[POS + i] === 0) && (i <= end0pos); ++i) { }
var nrzeroes = i - startpos; let nrzeroes = i - startpos;
if (nrzeroes >= 16) { if (nrzeroes >= 16) {
lng = nrzeroes >> 4; lng = nrzeroes >> 4;
for (var nrmarker = 1; nrmarker <= lng; ++nrmarker) { for (let nrmarker = 1; nrmarker <= lng; ++nrmarker) {
posval = HTAC[0xF0][1]; posval = HTAC[0xF0][1];
bytenew <<= posval; bytenew <<= posval;
bytenew += HTAC[0xF0][0]; bytenew += HTAC[0xF0][0];
@ -1644,9 +1600,9 @@ export class f5stego {
if (!this.#frame) if (!this.#frame)
throw "Frame not ready"; throw "Frame not ready";
var c, mcuRow, mcuCol, blockRow, blockCol, mcu, i, v, h; let c, mcuRow, mcuCol, blockRow, blockCol, mcu, i, v, h;
var DCdiff = []; const DCdiff: number[] = [];
for (i = 0; i < this.#frame.components.length; i++) { for (i = 0; i < this.#frame.components.length; i++) {
DCdiff.push(0); DCdiff.push(0);
} }
@ -1690,6 +1646,5 @@ export class f5stego {
if (this.#tail) writeBlock(this.#tail); if (this.#tail) writeBlock(this.#tail);
return byteout.slice(0, outpos); return byteout.slice(0, outpos);
}; }
} }

7
src/main.ts

@ -651,13 +651,6 @@ const earlystartup = async () => {
return false; return false;
} }
} }
if (['arch.b4k.co', 'desuarchive.org'].includes(location.host) && execution_mode == "chrome_api") {
if (!Platform.getValue("warning_seen3", false)) {
alert("Due to b4k and desuarchive policies being mean, PEE cannot display content properly here. A \"PEE companion\" extension will be released as including that functionnallity in PEE lengthens ChromeWebStore review delays, please understando.");
Platform.setValue("warning_seen3", true);
return false;
}
}
return true; return true;
}; };

Loading…
Cancel
Save