@ -1,3 +1,4 @@
/* eslint-disable no-constant-condition */
/ * T h i s s o f t w a r e i s l i c e n s e d u n d e r t h e M I T L i c e n s e .
/ * T h i s s o f t w a r e i s l i c e n s e d u n d e r t h e M I T L i c e n s e .
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 ;
le t huffmanTablesAC : Uint16Array [ ] = [ ] ;
cons t huffmanTablesAC : Uint16Array [ ] = [ ] ;
le t huffmanTablesDC : Uint16Array [ ] = [ ] ;
cons t 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 ) ;
} ;
}
}
}