Created
August 10, 2015 10:59
-
-
Save batako/3317fb608e2851971c55 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| var electronicWatermark = (function(){ | |
| // 書き込み用バッファ | |
| var _implanted = []; | |
| // チャンク探索 | |
| var _process = function(png, type, handler) { | |
| var dataLength; | |
| var chunkType; | |
| var nextChunkPos; | |
| var Signature = String.fromCharCode(137, 80, 78, 71, 13, 10, 26, 10); | |
| var rpos = 0; | |
| // シグネチャの確認 | |
| if (String.fromCharCode.apply(null, png.subarray(rpos, rpos += 8)) !== Signature) { | |
| throw new Error('invalid signature'); | |
| } | |
| // チャンクの探索 | |
| while (rpos < png.length) { | |
| dataLength = ( | |
| (png[rpos++] << 24) | | |
| (png[rpos++] << 16) | | |
| (png[rpos++] << 8) | | |
| (png[rpos++] ) | |
| ) >>> 0; | |
| nextChunkPos = rpos + dataLength + 8; | |
| chunkType = String.fromCharCode.apply(null, png.subarray(rpos, rpos += 4)); | |
| if (chunkType === type) { | |
| return handler(png, rpos, dataLength); | |
| } | |
| rpos = nextChunkPos; | |
| } | |
| } | |
| // チャンク作成 | |
| var _createNewChunk = function(data) { | |
| var dataLength = data.length; | |
| var chunk = new Uint8Array(4 + 4 + dataLength + 4); | |
| var type = [104, 111, 71, 101]; | |
| var crc; | |
| var pos = 0; | |
| var i; | |
| // length | |
| chunk[pos++] = (dataLength >> 24) & 0xff; | |
| chunk[pos++] = (dataLength >> 16) & 0xff; | |
| chunk[pos++] = (dataLength >> 8) & 0xff; | |
| chunk[pos++] = (dataLength ) & 0xff; | |
| // type | |
| chunk[pos++] = type[0]; | |
| chunk[pos++] = type[1]; | |
| chunk[pos++] = type[2]; | |
| chunk[pos++] = type[3]; | |
| // data | |
| for (i = 0; i < dataLength; ++i) { | |
| chunk[pos++] = data[i]; | |
| } | |
| //crc | |
| crc = Zlib.CRC32.calc(type); | |
| crc = Zlib.CRC32.update(data, crc); | |
| chunk[pos++] = (crc >> 24) & 0xff; | |
| chunk[pos++] = (crc >> 16) & 0xff; | |
| chunk[pos++] = (crc >> 8) & 0xff; | |
| chunk[pos++] = (crc ) & 0xff; | |
| return chunk; | |
| } | |
| // チャンク挿入 | |
| var _insertNewChunk = function(implanted, data, png, rpos) { | |
| var chunk = _createNewChunk(data); | |
| var pos = 0; | |
| // IDAT チャンクの前までコピー | |
| implanted.set(png.subarray(0, rpos), pos); | |
| pos += rpos; | |
| // hoGe チャンクをコピー | |
| implanted.set(chunk, pos); | |
| pos += chunk.length; | |
| // IDAT チャンク以降をコピー | |
| implanted.set(png.subarray(rpos), pos); | |
| return implanted; | |
| } | |
| // | |
| var _getImplantedBase64 = function() { | |
| // Uint8Array から bytestring に変換 | |
| var implantedString = ""; | |
| for (i = 0, il = _implanted.length; i < il; ++i) { | |
| implantedString += String.fromCharCode(_implanted[i]); | |
| } | |
| // Base64 に変換 | |
| var implantedBase64 = window.btoa(implantedString); | |
| return implantedBase64; | |
| } | |
| // | |
| var _getURL = function() { | |
| var implantedBase64 = _getImplantedBase64(); | |
| var implantedDataURL = 'data:image/png;base64,' + implantedBase64; | |
| return implantedDataURL; | |
| } | |
| // | |
| var _getData = function() { | |
| var extractedData = _process(_implanted, "hoGe", function(png, rpos, length) { | |
| return png.subarray(rpos, rpos += length); | |
| }); | |
| var binary = _convertArrayToStr( extractedData ); | |
| var result = _convertBinaryToStr( binary ); | |
| return result; | |
| } | |
| function _convertArrayToStr(array){ | |
| var result = ''; | |
| for(var i=0; i < array.length; i++){ | |
| result += _zeroFormat(8, (array[i]).toString(2)); | |
| } | |
| return result; | |
| } | |
| function _convertStrToArray(str){ | |
| var result = []; | |
| for(var i=0; i < str.length; i++){ | |
| var num = _zeroFormat(16, (str.charCodeAt(i)).toString(2)); | |
| result.push( parseInt( num.slice(0,8), 2) ); | |
| result.push( parseInt( num.slice(8,16), 2) ); | |
| } | |
| return result; | |
| } | |
| function _convertBinaryToStr(beforeStr){ | |
| beforeStr = _toHankakuNum(beforeStr.replace(/\r\n/g,'').replace(/\n/g,'').replace(/\s| /g,'')); | |
| if ( !beforeStr.match(/^[01]+$/) || beforeStr.length % 16 != 0){ | |
| return; | |
| } | |
| var afterStr = ''; | |
| for(var i=0; i < beforeStr.length / 16; i++){ | |
| var startNum = i * 16; | |
| var endNum = startNum + 16; | |
| var word = beforeStr.slice(startNum, endNum); | |
| afterStr += String.fromCharCode(parseInt(word,2)); | |
| } | |
| return afterStr; | |
| } | |
| function _toHankakuNum(beforeStr){ | |
| var han = '0123456789'; | |
| var zen = '0123456789'; | |
| var afterStr = ''; | |
| for (i=0; i<beforeStr.length; i++){ | |
| c = beforeStr.charAt(i); | |
| n = zen.indexOf(c,0); | |
| if (n >= 0) c = han.charAt(n); | |
| afterStr += c; | |
| } | |
| return afterStr; | |
| } | |
| function _zeroFormat(max, num){ | |
| var tmp=''+num; | |
| while(tmp.length<max){ | |
| tmp='0'+tmp; | |
| } | |
| return tmp; | |
| } | |
| var _init = function( b64data, data ) { | |
| if ( !b64data ) { | |
| b64data = ''; | |
| } | |
| // 埋め込みデータ | |
| if ( !data ) { | |
| data = ''; | |
| } else { | |
| data = _convertStrToArray( data ); | |
| } | |
| // Base64 デコード | |
| var decoded = window.atob( b64data ); | |
| // Uint8Array に変換 | |
| var png = new Uint8Array( | |
| decoded.split('').map(function(char) { | |
| return char.charCodeAt(0); | |
| }) | |
| ); | |
| _implanted = new Uint8Array(png.length + data.length + 12); | |
| _process(png, 'IDAT', function(png, rpos, length) { | |
| // rpos - 8 = チャンクの開始位置 | |
| _insertNewChunk(_implanted, data, png, rpos - 8); | |
| }); | |
| } | |
| return { | |
| init: _init, | |
| getBase64: _getImplantedBase64, | |
| getURL: _getURL, | |
| getData: _getData | |
| } | |
| })(); |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
require crc32.min.js
https://github.com/imaya/zlib.js