// ==UserScript==
// @name wytk-tieba
// @namespace http://tampermonkey.net/
// @version 1.0
// @description 无影坦克
// @author cjq
// @match https://tieba.baidu.com/p/*
// @match http://tieba.baidu.com/photo/p*
// @match http://tiebapic.baidu.com/forum/pic/item/*
// @grant GM_setValue
// @grant GM_getValue
// @require http://cdn.bootcss.com/jquery/1.8.3/jquery.min.js
// @run-at document-end
// ==/UserScript==
(function () {
jQuery.noConflict();
//引入原脚本
function utf8Encode(string) {
var utftext = "";
for (var n = 0; n<string.length; n++) {
var c = string.charCodeAt(n);
if (c<128) {
utftext += String.fromCharCode(c);
} else if ((c>127) && (c<2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
}
function utf8Decode(inputStr) {
var outputStr = "";
var code1, code2, code3, code4;
for(var i = 0; i < inputStr.length; i++) {
code1 = inputStr.charCodeAt(i);
if(code1 < 128) {
outputStr += String.fromCharCode(code1);
}else if(code1 < 224) {
code2 = inputStr.charCodeAt(++i);
outputStr += String.fromCharCode(((code1 & 31) << 6) | (code2 & 63));
}else if(code1 < 240) {
code2 = inputStr.charCodeAt(++i);
code3 = inputStr.charCodeAt(++i);
outputStr += String.fromCharCode(((code1 & 15) << 12) | ((code2 & 63) << 6) | (code3 & 63));
}else {
code2 = inputStr.charCodeAt(++i);
code3 = inputStr.charCodeAt(++i);
code4 = inputStr.charCodeAt(++i);
outputStr += String.fromCharCode(((code1 & 7) << 18) | ((code2 & 63) << 12) |((code3 & 63) << 6) | (code2 & 63));
}
}
return outputStr;
}
let IMG1=new Image();
let IMGINFO=[];
let IMG2=new Image();
let MODE=4;
let SRC1="";
let SRC2="";
let CURR_URL="";
var DOMAIN=document.URL;
function a1(){
requestAnimationFrame(function(){
requestAnimationFrame(function(){
try{
let f=gen(MODE);
if(SRC1){URL.revokeObjectURL(SRC1)}
SRC1=URL.createObjectURL(f);
jQuery("#a1").attr("href",SRC1);
jQuery("#img1").attr("src",SRC1);
jQuery("#a1").css("display","inline");
jQuery("#a1").attr("download","download.png");
}catch(e){alert("图片生成失败")}
})
})
}
function a2(){
try{
let f=sol();
if(SRC2){URL.revokeObjectURL(SRC2)}
SRC2=URL.createObjectURL(f[0]);
jQuery("#" + String(id - 1)).attr("src",SRC2)
jQuery("#" + String(id - 1)).before(createTip("图片读取成功!"))
}catch(e){
tryOpenOriginPicWhenDecodeError();
jQuery("#" + String(id - 1)).before(createTip("解析读取失败,试试放大。如果已经放大,那就是无法解析。"))
}
}
function select(){
let l=[0,"500K","1M","1.5M","2M"]
MODE=parseInt(jQuery("#compress_level_select")[0].value);
document.getElementById("info1").innerHTML="建议里图大小:小于"+l[MODE]
}
function ipt1(){
var oFReader = new FileReader();
var ofile = jQuery("#ipt1")[0].files[0];
oFReader.readAsDataURL(ofile);
oFReader.onloadend = function(oFRevent){
var osrc = oFRevent.target.result;
IMG1.src=osrc;
}
}
function ipt(){
var oFReader = new FileReader();
var ofile = jQuery("#ipt")[0].files[0];
oFReader.readAsArrayBuffer(ofile);
oFReader.onloadend = function(oFRevent){
try{
let l=new Uint8Array(oFRevent.target.result);
IMGINFO=[ [l.length,utf8Encode(ofile.name),ofile.type],l];
}catch(e){}
}
}
//解密
function ipt2(){
var oFReader = new FileReader();
//得到文件
var ofile = document.getElementById("ipt2").files[0];
console.log(ofile);
oFReader.readAsDataURL(ofile);
oFReader.onloadend = function(oFRevent){
var osrc = oFRevent.target.result;
IMG2.src=osrc;
console.log(IMG2.src);
IMG2.onload=function(){
console.log('img2.onload')
a2()
}
}
}
function dataURLtoBlob(dataurl) {
var arr = dataurl.split(',');
var _arr = arr[1];
var mime = arr[0].match(/:(.*?);/)[1],
bstr =atob(_arr),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr.buffer], {type: mime});
}
function gen(mode){
let modelist=[0,3,mode];
let word=IMGINFO[0].join(String.fromCharCode(1))+String.fromCharCode(0);
let length=2+parseInt((word.length+IMGINFO[1].length)*8/(mode*3))
let ax=Math.sqrt(length/(IMG1.width*IMG1.height));
let wid=Math.ceil(IMG1.width*ax);
let hit=Math.ceil(IMG1.height*ax);
let cv=document.createElement("canvas");
let cvd=cv.getContext("2d");
cv.width=wid;
cv.height=hit;
cvd.fillStyle="#ffffff";
cvd.fillRect(0,0,wid,hit);
cvd.drawImage(IMG1,0,0,wid,hit);
if(jQuery('#beizhucheckbox').is(':checked')){
let w=jQuery('#beizhu')[0].value;
cvd.font="16px Arial";
cvd.textBaseline="middle";
cvd.fillStyle="rgba(255,255,255,0.75)";
cvd.fillRect(0,0,cvd.measureText(w).width+8,28);
cvd.fillStyle="#000000";
cvd.fillText(w,4,14,wid-8);
}
return new File([dataURLtoBlob(en(mode,modelist,cvd.getImageData(0,0,wid,hit),word,IMGINFO[1]," wytk.github.io"))],"download.png",{type:"image/png"})
}
function sol(){
let cv=document.createElement("canvas");
let cvd=cv.getContext("2d");
cv.width=IMG2.width;
cv.height=IMG2.height;
cvd.drawImage(IMG2,0,0);
let imgdata=cvd.getImageData(0,0,IMG2.width,IMG2.height);
let klist=de(imgdata.data[2]%8,imgdata);
let file=new File([klist[1].buffer],utf8Decode(klist[0][1]),{type:klist[0][2]})
return [file,utf8Decode(klist[0][1])]
}
function closer(mode,m,n){
let a=m % mode
if(255-m<=mode/2 || m<mode/2){
return parseInt(m/mode)*mode+n
}else if(n-a>mode/2){
return parseInt(m/mode)*mode+n-mode
}else if(a-n>=mode/2){
return parseInt(m/mode)*mode+n+mode
}else{
return parseInt(m/mode)*mode+n
}
}
function en(mode,fplist,imgdata,aword,blist,cword){
let aa=Math.ceil(8/3/mode);
let n=imgdata.width*imgdata.height;
let j=0;
let k="";
let i=1;
let mlist=[1,2,4,8,16,32,64,128];
let cv=document.createElement("canvas");
let cvd=cv.getContext("2d");
cv.width=imgdata.width;
cv.height=imgdata.height;
imgdata.data[0]=closer(8,imgdata.data[0],fplist[0]);
imgdata.data[1]=closer(8,imgdata.data[1],fplist[1]);
imgdata.data[2]=closer(8,imgdata.data[2],fplist[2]);
while(i<n && j<aword.length){
k=k+(aword.charCodeAt(j)+256).toString(2).slice(1);
for(let ii=0;ii<aa;ii++){
if(k.length>=mode*3){
imgdata.data[4*i ]=closer(mlist[mode],imgdata.data[4*i ],parseInt(k.slice(0 ,mode ),2));
imgdata.data[4*i+1]=closer(mlist[mode],imgdata.data[4*i+1],parseInt(k.slice(mode ,mode*2),2));
imgdata.data[4*i+2]=closer(mlist[mode],imgdata.data[4*i+2],parseInt(k.slice(mode*2,mode*3),2));
k=k.slice(mode*3);
i++
}
}
j++
}
j=0;
while(i<n && j<blist.length){
k=k+(blist[j]+256).toString(2).slice(1);
for(let ii=0;ii<aa;ii++){
if(k.length>=mode*3){
imgdata.data[4*i ]=closer(mlist[mode],imgdata.data[4*i ],parseInt(k.slice(0 ,mode ),2));
imgdata.data[4*i+1]=closer(mlist[mode],imgdata.data[4*i+1],parseInt(k.slice(mode ,mode*2),2));
imgdata.data[4*i+2]=closer(mlist[mode],imgdata.data[4*i+2],parseInt(k.slice(mode*2,mode*3),2));
k=k.slice(mode*3);
i++
}
}
j++
}
j=0;
while(i<n){
k=k+(cword.charCodeAt(j%cword.length)+256).toString(2).slice(1);
for(let ii=0;ii<aa;ii++){
if(k.length>=mode*3){
imgdata.data[4*i ]=closer(mlist[mode],imgdata.data[4*i ],parseInt(k.slice(0 ,mode ),2));
imgdata.data[4*i+1]=closer(mlist[mode],imgdata.data[4*i+1],parseInt(k.slice(mode ,mode*2),2));
imgdata.data[4*i+2]=closer(mlist[mode],imgdata.data[4*i+2],parseInt(k.slice(mode*2,mode*3),2));
k=k.slice(mode*3);
i++
}
}
j++
}
cvd.putImageData(imgdata,0,0);
return cv.toDataURL();
}
function de(mode,imgdata){
let aa=Math.ceil(3*mode/8);
let n=imgdata.width*imgdata.height;
let j=0;
let k="";
let i=1;
let mlist=[1,2,4,8,16,32,64,128];
let word="";
let blist//=new Uint8Array();
let blength=0;
while(i<n && (word.length==0 || word.slice(-1).charCodeAt(0)>0)){
k=k+(imgdata.data[4*i ]+256).toString(2).slice(-mode);
k=k+(imgdata.data[4*i+1]+256).toString(2).slice(-mode);
k=k+(imgdata.data[4*i+2]+256).toString(2).slice(-mode);
i++
for(let ii=0;ii<aa;ii++){
if(k.length>=8 && (word.length==0 || word.slice(-1).charCodeAt(0)>0)){
word=word+String.fromCharCode(parseInt(k.slice(0,8),2));
k=k.slice(8);
}
}
}
//word分隔符:","
blength=parseInt(word.split(String.fromCharCode(1))[0]);
if(!(blength>-1)){
throw "error"
}
if(!(word.split(String.fromCharCode(1)).length>2)){
throw "error"
}
blist=new Uint8Array(blength);
if(k.length>=8 && j<blength){
blist[j]=parseInt(k.slice(0,8),2);
k=k.slice(8);
j++
}
while(i<n && j<blength){
k=k+(imgdata.data[4*i ]+256).toString(2).slice(-mode);
k=k+(imgdata.data[4*i+1]+256).toString(2).slice(-mode);
k=k+(imgdata.data[4*i+2]+256).toString(2).slice(-mode);
i++
for(let ii=0;ii<aa;ii++){
if(k.length>=8 && j<blength){
blist[j]=parseInt(k.slice(0,8),2);
k=k.slice(8);
j++
}
}
}
return [word.split(String.fromCharCode(0))[0].split(String.fromCharCode(1)),blist]
}
//url转data
function getImageFileFromUrl(url, imageName,callback) {
// imageName一定要带上后缀
var blob = null;
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.setRequestHeader('Accept', 'image/jpeg');
xhr.responseType = "blob";
xhr.onload = () => {
if (xhr.status == 200) {
blob = xhr.response;
let imgFile = new File([blob], imageName, {type: 'image/jpeg'});
console.log(imgFile)
callback.call(this,imgFile);
}else{jQuery("#" + String(id)).before(createTip("网络出错,无法读取。"))}};
xhr.send();
}
//获取协议类型
function getProtocolStr(url){
var reg=/http:/;
if(reg.test(url)){
return "http";
}else{
return "https"
}
}
//得到链接中图片的名称
function getUrlLastPathNameStr(url){
var index = url.lastIndexOf("\/");
var last= url.substring(index + 1, url.length);
return last;
}
//如果解析失败可能是因为图片需要放大解析,但是由于跨域问题,所以要在新页面中解析,此时hover事件再次绑定成功,即可解析
function tryOpenOriginPicWhenDecodeError(){
if(DOMAIN.startsWith("https://tieba.baidu.com")){
window.open('http://tiebapic.baidu.com/forum/pic/item/'+getUrlLastPathNameStr(CURR_URL));
}
}
//创建提示标签
function createTip(str){
return "<p style=\"font-size:15px;color:orange\">"+str+"</p><br/>";
}
var id = 0;
if(!GM_getValue('firstTime')){
GM_setValue('firstTime',true);
GM_setValue('pluginOnOffFlag',true);
GM_setValue('autoJumpOriginFlag',true);
}
console.log(GM_getValue('pluginOnOffFlag'));
var userConfig={
pluginOnOffFlag:GM_getValue('pluginOnOffFlag'),
pluginAutoJumpOriginFlag:GM_getValue('autoJumpOriginFlag')
}
//在firefox下并不总是有效果,所以我把加载内容都给移出了,并且使用了 document-end 注解
window.onload=function(){
console.log("onloading~");
//下面这两行不知道是干什么的,屏蔽掉了
//let w="<!DOCTYPE "+"html>"+document.documentElement.outerHTML;
//document.getElementById("bc").href=URL.createObjectURL(new Blob([w],{type:"text/html"}))
var timerId=setInterval(function(){
//考虑到有些用户会不自觉放大页面
//检查是不是有原图,有则跳转到新标签页显示,因为在原图网页我绑定不了hover事件
var picURL=jQuery('.image_original_original').attr('src');
if(picURL!=undefined && picURL!='' && userConfig.pluginAutoJumpOriginFlag){
window.open(picURL);
clearInterval(timerId);
}
},1000);
console.log("onload end~");
}
//左浮窗功能
jQuery("body").append("\
<div id='plugin_float' \
style='left: 20px;\
bottom: 20px;\
background: #9beee2;\
color:#3e32d2;\
overflow: hidden;\
z-index: 9999;\
position: fixed;\
padding:5px;\
text-align:left;\
font-size:20px;\
'></div>");
jQuery("#plugin_float").append('<p>无影坦克𝐈𝐈:</p>')
.append('<input type="checkbox" id="plugin_enable_state"> 鼠标悬浮解析 <br>')
.append('<input type="checkbox" id="plugin_autojump_state"> 自动跳大图 <br>')
.append('<p>找不到心爱的小锤锤?给你🔨</p>');
if(userConfig.pluginOnOffFlag){
jQuery('#plugin_enable_state').attr('checked','checked');
}
if(userConfig.pluginAutoJumpOriginFlag){
jQuery('#plugin_autojump_state').attr('checked','checked');
}
jQuery("#plugin_float").append("🖼️<a href = \"javascript:void(0)\"onclick = \"document.getElementById('light').style.display='block';document.getElementById('fade').style.display='block'\"> 快速制图 </a>");
//中间浮窗,用来制图
jQuery("body").append("\
<style>\
.black_overlay{\
display: none;\
position: fixed;\
top: 0%;\
left: 0%;\
width: 100%;\
height: 100%;\
background-color: black;\
z-index:1040;\
-moz-opacity: 0.8;\
opacity:.80;\
filter: alpha(opacity=88);\
}\
.white_content {\
display: none;\
position: fixed;\
top: 25%;\
left: 25%;\
width: 55%;\
height: 55%;\
padding: 20px;\
border: 10px solid orange;\
background-color: white;\
z-index:1050;\
overflow: auto;\
}\
</style>");
jQuery("body").append("<div id=\"light\" class=\"white_content\"> \
<br>\
<a href=\"https://wytk.github.io/\">GITHUB官方制图工具链接 https://wytk.github.io/</a> <br>\
\
<summary>制作坦克</summary> \
<span>选择表图</span><br><input type=\"file\" id=\"ipt1\" accept=\"image/*\"> \
<br> \
<span>选择里图</span><br><input type=\"file\" id=\"ipt\" accept=\"image/*\"> \
<br> \
<span>添加备注</span><input id=\"beizhucheckbox\" type=\"checkbox\" checked=\"true\"> \
<br><input type=\"text\" id=\"beizhu\" style=\"width:150px\" value=\"TK\"> \
<br> \
<span>表图压缩度 </span><select id=\"compress_level_select\" \
<option value=\"1\">1</option> \
<option value=\"2\">2</option> \
<option value=\"3\">3</option> \
<option value=\"4\" selected=\"true\">4</option> \
</select>\
<br>\
<span id=\"info1\">建议里图大小:小于2M</span>\
<br>\
<button id=\"a1_button\">合成图片</button> \
<br> \
<img id=\"img1\"> \
<br> \
<a href=\"\" id=\"a1\" style=\"display:none\">保存图片</a> \
\
<a href = \"javascript:void(0)\" onclick = \"document.getElementById('light').style.display='none';document.getElementById('fade').style.display='none'\">关闭窗口<br></a>\
<br> \
</div> \
<div id=\"fade\" class=\"black_overlay\"></div>");
//冒泡事件,防止动态加载
jQuery("body").on("hover","img",function(event){
//只响应鼠标移动到图片上,忽略移开
if(event.type=="mouseenter"){
if(!userConfig.pluginOnOffFlag)
return;
//忽略上次处理过的图片
if(jQuery(this).attr("id")==(id-1))
return;
//忽略制图中的图片,否则会导致无法继续制图
if(jQuery(this).attr("id")=="img1")
return;
jQuery(this).attr("id",String(id));
jQuery("#" + String(id)).before(createTip("正在加载。。。若长时间无反应请手动点击图片!"));
id = id + 1;
var url=jQuery(this).attr("src");
CURR_URL=url;
//请求资源的协议看domain不看资源的src,否则会产生mixed错误
getImageFileFromUrl(getProtocolStr(DOMAIN) + url.substring(4,url.length),'testFile.jpg',function(file){
console.log(file)
var r = new FileReader()
r.readAsDataURL(file)
r.onloadend = function(oFRevent){
var osrc = oFRevent.target.result;
IMG2.src=osrc;
IMG2.onload=function(){
a2()
}
}
});
}
});
jQuery("body").on("click",function(event){
//console.log(event.target);
if(event.target.id=="plugin_enable_state"){
userConfig.pluginOnOffFlag=jQuery('#plugin_enable_state').is(':checked');
GM_setValue('pluginOnOffFlag',userConfig.pluginOnOffFlag);
console.log("插件使能状态改变:"+userConfig.pluginOnOffFlag);
}
if(event.target.id=="plugin_autojump_state"){
userConfig.pluginAutoJumpOriginFlag=jQuery('#plugin_autojump_state').is(':checked');
GM_setValue('autoJumpOriginFlag',userConfig.pluginAutoJumpOriginFlag);
console.log("自动跳大图状态改变:"+userConfig.pluginAutoJumpOriginFlag);
}
if(event.target.id=="a1_button"){
a1();
}
});
jQuery("body").on("change",function(event){
//console.log(event.target);
if(event.target.id=="ipt1"){
ipt1();
}
if(event.target.id=="ipt"){
ipt();
}
if(event.target.id=="compress_level_select"){
select();
}
});
})();