写了一个帮助躲避审查的小程序,是否能帮忙改进?
编辑于4月19日,之后(一两个星期左右)若是有空,可能会再更新最后一次,修复一些问题并加一些小功能。
增加了文字排序、字串替换、添加干扰字(常用高频汉字)的功能,生成文字可被复制,下载。线条可选择水平或垂直。线条部份不想多做了(如随机每个文字的位置,让文字存在轻微重叠,添加背景干扰等等),觉得这已经够了,毕竟这功能对人工审查应该没多少用途,还是加密功能好。文字颜色的功能已可使用。
图片下载功能还是有问题,下载的图片档案里依然看不到被生成的部份(虽然图片里确实有生成的内容),应该是比例的问题。
由于字数问题(回复字数不得大于 20000 字),删除了部份之前版本的回覆,存档在此。
https://web.archive.org/web/20200419160206/https://pincong.rocks/question/22785
拷贝以下代码到文档,将档案名改成 档案名.html (网页格式),即可在安全的浏览器上运行(浏览器不安全的话,我也没方法),无须联网。
要拷贝的代码, <html> 为第一行,到 </html> 为最后一行。
<html>
<head>
<meta charset="UTF-8" />
</head>
<style>
.tooltip {
position: relative;
display: inline-block;
border-bottom: 1px dotted black;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: #555;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 0;
position: absolute;
z-index: 1;
bottom: 125%;
left: 50%;
margin-left: -60px;
opacity: 0;
transition: opacity 0.3s;
}
.tooltip .tooltiptext::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: #555 transparent transparent transparent;
}
.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}
</style>
<script language="javascript">
function $(obj)
{
return document.getElementById(obj);
}
function isChecked(obj)
{
if (obj.checked)
{
return true;
}
return false;
}
function resetRadio()
{
$("horizontalRightward_verticalDownward").checked = true ;
$("noRandText").checked = true ;
$("addRange").value = 1 ;
$("notRepWord").checked = true ;
$("lineMaxNumber").checked = true ;
}
function activeRadio ()
{
$("verticalDownward_horizontalLeftward").checked = true ;
$("addRandText").checked = true ;
$("repWord").checked = true ;
$("lineMaxNumber").checked = true ;
}
function getCheckedRadio(radioName)
{
var arrRadioBtns = document.getElementsByName(radioName);
for ( i = 0 ; i < arrRadioBtns.length ; i ++ )
{
if (arrRadioBtns[i].checked )
{
return arrRadioBtns[i].value ;
}
}
return " " ;
}
function reverseString(str)
{
return str.split("").reverse().join("");
}
function insertString (str , index , value)
{
return str.substr(0,index) + value + str.substr(index);
}
function getRndNum( min , max )
{
return Math.floor(Math.random() * (max-min) ) + min ;
}
function getMaxLength ( arr )
{
var maxLength = 1 ;
for ( i = 0 ; i < arr.length ; i ++ )
{
if ( maxLength < arr[i].length )
{
maxLength = arr[i].length ;
}
}
return maxLength;
}
function rearrangeText()
{
var oText = $('originalText').value;
var alignment , horizontalDirection, verticalDirection ;
alignment = getCheckedRadio("order");
//文字排序方向
if ( alignment[0] == "R" || alignment[1] == "R" )
{
horizontalDirection = "R" ;
}
else
{
horizontalDirection = "L" ;
}
if ( alignment[0] == "D" || alignment[1] == "D" )
{
verticalDirection = "D" ;
}
else
{
verticalDirection = "U" ;
}
var newString ;
var maxColumn = 1 ;
//替换文字
if($("repWord").checked)
{
var dict = $("replaceWordDict").value ;
var splitDic , dicArray ;
splitDic = dict.split('\n') ;
var orgPattern , repPattern, tempText = "" ;
for ( i = 0 ; i < splitDic.length ; i ++ )
{
dicArray = splitDic[i].split('|');
repPattern = dicArray[1].split(',');
tempText = repPattern[getRndNum(0,repPattern.length)];
var intIndexOfMatch = oText.indexOf( dicArray[0] );
// Loop over the string value replacing out each matching substring.
while (intIndexOfMatch != -1)
{
// Relace out the current instance.
oText = oText.replace( dicArray[0], tempText )
// Get the index of any next matching substring.
intIndexOfMatch = oText.indexOf( dicArray[0] );
tempText = repPattern[getRndNum(0,repPattern.length)];
}
}
}
// 添加干扰字串
var addRandText = false ;
var addRange, addText ;
if($("addRandText").checked)
{
addText = $('addText').value.split('\n');
addRange = $("addRange").value ;
var tempText = "" ;
for ( i = Number(addRange) ; i < oText.length ; i += Number(addRange) + Number(tempText.length) )
{
tempText = addText[getRndNum(0,addText.length)];
oText = insertString (oText , i , tempText) ;
}
}
var text = oText.split('\n');
//若不是水平优先,则排序成垂直
if ( alignment[0] == "U" || alignment[0] == "D" )
{
maxColumn = getMaxLength ( text ) ;
newString = new Array (maxColumn) ;
for ( i = 0 ; i < maxColumn ; i ++ )
{
newString[i] = new Array (text.length) ;
}
for ( i = 0 ; i < text.length ; i ++ )
{
for ( j = 0 ; j < maxColumn ; j ++ )
{
if ( j >= text[i].length )
{
newString[j][i] = " ";
}
else
{
newString[j][i] = text[i][j];
}
}
}
text = new Array (maxColumn) ;
for ( i = 0 ; i < maxColumn ; i ++ )
{
text[i] = newString[i].join("");
}
}
//若不是向右,则逆转文字的横向排序
if (horizontalDirection == "L" )
{
for ( i = 0 ; i < text.length ; i ++ )
{
text[i] = reverseString(text[i]);
}
}
//若不是向下,则逆转文字的纵向排序
if ( verticalDirection == "U" )
{
text.reverse();
}
$('resultText').value = text.join("\n") ;
}
function canvasCoordinate ( isHorizontal , fsize , i , length )
{
var pn = -1, x0 = 0 , y0 = 0 , x1 = 0 , y1 = 0 ,x2 = 0 , y2 = 0 ;
if (Math.random >= 0.5)
{
pn = 1;
}
x0 = (length * fsize / 4 ) + pn * getRndNum(0,length * fsize) / 4 ;
x1 = (length * fsize * 3 / 4 ) + pn * getRndNum(0,length * fsize) / 4 ;
x2 = length * fsize;
y0 = (fsize * i) + getRndNum(0,2 * fsize) ;
y1 = (fsize * i) + getRndNum(0,2 * fsize) ;
y2 = (fsize * i) + getRndNum(0,fsize) ;
if ( isHorizontal )
{
return [x0,y0,x1,y1,x2,y2] ;
}
return [y0,x0,y1,x1,y2,x2] ;
}
function drawCanvas()
{
rearrangeText();
var c = $('canvas');
var t = $('resultText');
var fsize = $('fsize').value;
var lnumber = $('lnumber').value;
var lwidth = $('lwidth').value;
var lines = t.value.split('\n');
var columns = $('twidth').value;
var colLength = 1 , maxLength = getMaxLength ( lines ) ;
//限制每行的字数
if($("lineMaxNumber").checked)
{
for (i = 0; i < lines.length; i++)
{
if (lines[i].length > columns)
{
var end = columns ;
var nLoop = Math.ceil(lines[i].length / columns) ;
for (j = 0; j < nLoop ; j++)
{
end = columns ;
if ( j > 0 && (j == (nLoop-1) ) )
{
end = lines[i].length % columns;
if (end == 0)
{
end = columns;
}
}
lines.splice(i + j+1, 0, lines[i].substr(j * columns, end) );
}
end = i ;
i += Math.floor( lines[i].length / columns ) -1;
lines.splice(end ,1);
}
}
colLength = columns ;
}
else
{
colLength = maxLength ;
}
c.width = (colLength + 2) * fsize ;
c.height = (lines.length + 3) * fsize ;
var ctx = c.getContext('2d') ;
ctx.clearRect(0, 0, canvas.width, canvas.height) ;
ctx.beginPath() ;
ctx.font = fsize + 'px Microsoft YaHei';
ctx.lineWidth = lwidth;
ctx.fillStyle = $("textcolor").value;
var direction = getCheckedRadio("lineDirection");
if (direction == "F" )
{
direction = getCheckedRadio("order");
if ( direction[0] == "U" || direction[0] == "D" )
{
direction = "V" ;
}
else
{
direction = "H" ;
}
}
var canvasPos ;
for (i = 0; i < lines.length; i++)
{
ctx.fillText(lines[i], 0, fsize * (i + 1));
//水平画线
if (direction == "H")
{
for (j = 0; j < lnumber; j++)
{
ctx.moveTo(0, (i * fsize) + getRndNum ( 0 , fsize ) );
canvasPos = canvasCoordinate (true , fsize , i , colLength) ;
ctx.bezierCurveTo( canvasPos[0] , canvasPos[1] , canvasPos[2] , canvasPos[3] , canvasPos[4] , canvasPos[5] );
ctx.stroke();
}
}
}
//垂直画线
if (direction == "V")
{
for (i = 0; i < colLength && i < maxLength; i++)
{
for (j = 0; j < lnumber; j++)
{
ctx.moveTo((i * fsize) + getRndNum ( 0 , fsize ) , 0 );
canvasPos = canvasCoordinate (false , fsize , i , lines.length) ;
ctx.bezierCurveTo( canvasPos[0] , canvasPos[1] , canvasPos[2] , canvasPos[3] , canvasPos[4] , canvasPos[5] );
ctx.stroke();
}
}
}
var imageURI = c.toDataURL();
$('download').href = imageURI;
}
function copyText()
{
var text = $("resultText");
text.select();
text.setSelectionRange(0,99999);
document.execCommand("copy");
}
function download(filename, text)
{
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
function downloadText ()
{
// Generate download of RearrangeText.txt file with some content
var text = $("resultText").value;
var filename = "RearrangeText.txt";
download(filename, text);
}
download_img = function(el)
{
// get image URI from canvas object
var imageURI = document.getElementById("canvas").toDataURL("image/jpg");
el.href = imageURI;
};
</script>
<body style="text-align:center;">
<label><b>排序</b></label><br/>
<p>
<label class="tooltip">原文
<span class="tooltiptext">想要排序或画线的文字</span>
</label>
<textarea id="originalText" wrap="hard" placeholder="请输入文字" rows="8" ></textarea>
</p>
<br/><input type="button" id="resetRadioBtn" value="默认排序" onclick="resetRadio();"/>
<input type="button" id="activeRadioBtn" value="启用全部" onclick="activeRadio();"/><br/>
<p>
<label class="tooltip">文字排序方向
<span class="tooltiptext">从哪个方向开始,到哪里(一共8种排序方式)。</span>
</label><br/>
<input type="radio" name="order" id="horizontalRightward_verticalDownward" value ="RD" checked> 从左到右,从上到下(不变)<br/>
<input type="radio" name="order" id="horizontalLeftward_verticalDownward" value ="LD"> 从右到左,从上到下<br/>
<input type="radio" name="order" id="horizontalRightward_verticalUpward" value ="RU" > 从左到右,从下到上 <br/>
<input type="radio" name="order" id="horizontalLeftward_verticalUpward" value ="LU"> 从右到左,从下到上<br/>
<input type="radio" name="order" id="verticalDownward_horizontalLeftward" value ="DL" > 从上到下,从右到左<br/>
<input type="radio" name="order" id="verticalDownward_horizontalRightward" value ="DR" > 从上到下,从左到右<br/>
<input type="radio" name="order" id="verticalUpward_horizontalLeftward" value ="UL"> 从下到上,从右到左<br/>
<input type="radio" name="order" id="verticalUpward_horizontalRightward" value ="UR"> 从下到上,从左到右<br/><br/>
</p>
<p>
<label class="tooltip">是否替换文字
<span class="tooltiptext">替换掉特定字串,针对直接对比字串的方式。(替换文字后才会进行字串添加)</span>
</label><br/>
<input type="radio" name="ReplaceWord" id="notRepWord" value ="N" checked> 不替换文字(默认)
<input type="radio" name="ReplaceWord" id="repWord" value ="Y"> 替换文字<br/>
<label class="tooltip">替换字串
<span class="tooltiptext">替换掉特定字串,针对直接对比字串的方式,格式为每行一个替换词,在|符号前的是被替换的字串,在|符号后的是用来替换的字串。若是用来替换的字串大于1个,则用来替换的字串之间以,符号为间隔,会随机选择其中一个来进行替换。(可以搜索关键字字库)(依照被替换字串的排序替换,如文字包括12,有两个被替换字串1和12,字串库中被替换字串1在12前面,12就不会被替换,因为在碰到1时,1已经被替换掉了。)</span>
</label>
<textarea id="replaceWordDict" rows="4">1989|¹玖8九,3²*13*17,一九九零减1,1980加九
御坂美琴|炮姐,超电磁炮,BiliBili,哔哩哔哩
0|⁰
1|¹
2|²
3|³
4|⁴
5|⁵
6|⁶
7|⁷
8|⁸
9|⁹
一|壹,ONE
二|貳,TWO
三|參,THREE
四|肆,FOUR
五|伍,FIVE
六|陸,SIX
七|柒,SEVEN
八|捌,EIGHT
九|玖,NINE
十|拾,TEN
百|佰
千|仟
万|萬
亿|億
国家|郭嘉,Country</textarea><br/>
</p>
<p>
<label class="tooltip">是否随机添加文字
<span class="tooltiptext">添加随机文字,针对直接对比字串的方式。(替换文字后才会进行字串添加)</span>
</label><br/>
<input type="radio" name="randAddText" id="noRandText" value ="N" checked> 不添加(默认)
<input type="radio" name="randAddText" id="addRandText" value ="Y"> 添加<br/>
<label class="tooltip" >添加间隔
<span class="tooltiptext">每隔多少个字就添加一次随机文字字串。</span>
</label>
<input type="number" id="addRange" value="1"/><br/>
<label class="tooltip">添加字串
<span class="tooltiptext">添加随机文字,针对直接对比字串的方式。每行为一个添加字串,会在所有字串里随机选择。可以搜索汉字的高出现频率字来加入字串库,避免字数频率统计。</span>
</label>
<textarea id="addText" rows="4">的
我
是
了
来
们
你
他
她
大
和
好
个
说
到
以
一
在
有
这
为
我们
正能量</textarea><br/>
</p>
<label class="tooltip" >生成文字
<span class="tooltiptext">依照以上设定及次序生成文字。</span>
</label>
<textarea id="resultText" rows="4">文字生成结果</textarea><br/>
<input type="button" id="generateText" value="点击以生成文字" onclick="rearrangeText();"/><br/><br/>
<input type="button" id="copyText" value="拷贝生成文字结果到剪貼板" onclick="copyText();"/><br/><br/>
<input type="button" id="downloadTextBtn" value="下载文字txt档案 RearrangeText.txt" onclick="downloadText();"/><br/><br/>
<label class="tooltip" ><b>画线</b>
<span class="tooltiptext">在文字上画线。</span>
</label><br/>
<p><label class="tooltip">字号
<span class="tooltiptext">字体的大小。</span>
</label>
<input type="text" value="20" id="fsize" />
</p>
<p>
<label class="tooltip" >是否启用每行字数
<span class="tooltiptext">启用则限制每行超过字数的文字会被换行。对于从下到上的排序,启用后,原超过字数的每行的内部被换行的排序是依照上到下排序的,而不是从下到上。</span>
</label><br/>
<input type="radio" name="lineMaxNum" id="lineMaxNumber" value ="Y" checked> 启用(自定义字数)(默认)
<input type="radio" name="lineMaxNum" id="noLineMaxNumber" value ="N"> 不启用<br/>
</p>
<p><label class="tooltip">每行字数
<span class="tooltiptext">每行最大允许字数,超过则会自动换行,数字,不低于1。</span>
</label>
<input type="text" value="20" id="twidth" />
</p>
<p><label class="tooltip">颜色
<span class="tooltiptext">文字的颜色。</span>
</label>
<input type="color" id="textcolor" value="#000000" />
</p>
<p>
<label class="tooltip">干扰线条方向
<span class="tooltiptext">是默认跟随文字的排序来画水平/垂直线条,或者固定为水平线条或垂直线条。</span>
</label><br/>
<input type="radio" name="lineDirection" id="lineDFollowWord" value ="F" checked> 跟随文字排序(默认)
<input type="radio" name="lineDirection" id="lineDHorizontal" value ="H"> 水平<br/>
<input type="radio" name="lineDirection" id="lineDVertical" value ="V"> 垂直<br/>
</p>
<p><label class="tooltip">每行干扰线条数
<span class="tooltiptext">线条数量,太多会看不清楚。</span>
</label> <input type="text" id="lnumber" value="2" /></p>
<p><label class="tooltip">干扰线宽度
<span class="tooltiptext">线条宽度,太多会看不清楚。</span>
</label> <input type="text" id="lwidth" value="0.3" /></p>
<p><button type="button" onclick="drawCanvas()">生成</button></p>
<label class="tooltip">生成结果
<span class="tooltiptext">生成的画线结果。(会重新进行一次文字生成,而不是直接拿之前文字生成的结果(若有)。)</span>
</label><br/><br/>
<canvas id="canvas"></canvas>
<a id="download" download="antiCensor.jpg" href="" onclick="download_img(this);">Download to antiCensor.jpg</a><br/><br/>
<label>请勿将此程序用于任何会伤害到他人的地方。</label>
</body>
</html>
好了,代码结束。
_____________
要不设个Array,如果lines[i]里面的字数大过输入字数column,就循环substr出来column长度(最后一个是剩余长度),push进去array里面,小过column就正常push进去lines[i]的数据。
最后再从那个array 里面提取。
(很久没碰代码了,又不方便去试错看value在哪里跑掉,只是建议)
(粗试一下,猜测你取消的部分可能是因为实时加数据,导致loop无限循环,建议自己在错误范围加一堆输出,看那些value在哪个循环开始不对劲,怎样不对劲)
半成品,还有一点问题。太久没碰javascript了,不想继续了。
for (i = 0; i < lines.length; i++)
{
if (lines[i].length > colomns)
{
var end = colomns ;
var nLoop = Math.ceil(lines[i].length / colomns) ;
for (j = 0; j < nLoop ; j++)
{
end = colomns ;
if ( j > 0 && (j == (nLoop-1) ) )
{
end = lines[i].length % colomns;
if (end == 0)
{
end = colomns;
}
}
lines.splice(i + j+1, 0, lines[i].substr(j * colomns, end) );
}
end = i ;
i += Math.floor( lines[i].length / colomns ) -1;
lines.splice( end ,1);
}
}
//没改内容,觉得影响输出显示的行数的部分应该来自这边
for (i = 0; i < lines.length; i++) {
ctx.fillText(lines[i], 0, fsize * (i + 1));
for (j = 0; j < lnumber; j++) {
ctx.moveTo(0, fsize * ((j + Math.random() + 1) / lines.length + i));
ctx.quadraticCurveTo(
((1 + Math.random()) / 3) * colomns * fsize,
fsize * (i + (j + Math.random() + 1) / lines.length),
colomns * fsize,
fsize * ((j + Math.random() + 1) / lines.length + i)
);
ctx.stroke();
}
}
我修改的还是有问题,没找到在哪里会限制到输出显示的行数。如果输入的行数太短,转化后显示的行数不完全,会吞掉几行,要自己在输入那边多打几个换行。(自己试一些输入,有的输出又没问题,有的输入又会出现显示不完全的问题)
__________
今天再看看,找到限制行数显示的问题在哪里了,是设定canvas的位置(height)早了(因为按照字数切完后,list的长度会改变(多数是增加,超过3就有问题了)),我重新修了一下declare c.height位置(移到切完字数的后面)(本来想把按字数切的放去recursive函数,后来没成功,就放弃了),看起来没问题了。加了一个下载图片,不过图片虽然有内容,但是比例不对。
script
function $(obj)
{
return document.getElementById(obj);
}
function submit()
{
var c = $('canvas');
var t = $('textbox');
var fsize = $('fsize').value;
var lnumber = $('lnumber').value;
var lwidth = $('lwidth').value;
var lines = t.value.split('\n');
var columns = $('twidth').value;
for (i = 0; i < lines.length; i++)
{
if (lines[i].length > columns)
{
var end = columns ;
var nLoop = Math.ceil(lines[i].length / columns) ;
for (j = 0; j < nLoop ; j++)
{
end = columns ;
if ( j > 0 && (j == (nLoop-1) ) )
{
end = lines[i].length % columns;
if (end == 0)
{
end = columns;
}
}
lines.splice(i + j+1, 0, lines[i].substr(j * columns, end) );
}
end = i ;
i += Math.floor( lines[i].length / columns ) -1;
lines.splice(end ,1);
}
}
//放在list整理好的后面就没问题了,因为是用lines.length 来 + 3
c.width = (columns + 1) * fsize ;
c.height = (lines.length + 3) * fsize ;
var ctx = c.getContext('2d') ;
ctx.clearRect(0, 0, canvas.width, canvas.height) ;
ctx.beginPath() ;
ctx.font = fsize + 'px Microsoft YaHei';
ctx.lineWidth = lwidth;
//我调整了一下我想要的画线方式
for (i = 0; i < lines.length; i++)
{
ctx.fillText(lines[i], 0, fsize * (i + 1));
var pn = -1 ;
for (j = 0; j < lnumber; j++) {
//随机X的位置是在1/4和3/4的左边(不超过1/4的宽度)还是右边(不超过1/4的宽度)
pn = -1 ;
if (Math.random >= 0.5)
{
pn = 1;
}
//改成了这个函数,多一个点,线条应该会比较多变
ctx.bezierCurveTo(
(columns * fsize / 4 ) + pn * (Math.floor(Math.random() * columns * fsize )) / 4 ,
(fsize * i) + Math.floor(Math.random() * 2 * fsize) ,
(columns * fsize * 3 / 4 ) + pn * (Math.floor(Math.random() * columns * fsize )) / 4 ,
(fsize * i) + Math.floor(Math.random() * 2 * fsize) ,
columns * fsize,
(fsize * i) + Math.floor(Math.random() * fsize)
);
ctx.stroke();
}
}
//图片下载,测试后,觉得下载的内容比例不对
var imageURI = c.toDataURL();
$('download').href = imageURI;
}
HTML body
<p>
<textarea id="textbox" wrap="hard" placeholder="请输入文字" ></textarea>
</p>
<p><label>字号</label><input type="text" value="20" id="fsize" /></p>
<p><label>每行字数</label><input type="text" value="20" id="twidth" /></p>
<p>
<label>颜色</label> <input type="color" id="textcolor" value="#000000" />
</p>
<p>
<label>每行干扰线条数</label> <input type="text" id="lnumber" value="2" />
</p>
<p>
<label>干扰线宽度</label> <input type="text" id="lwidth" value="0.3" />
</p>
<p><button type="button" onclick="submit()">生成</button></p>
<canvas id="canvas"></canvas>
<a id="download" download="antiCensor.jpg" href="" onclick="download_img(this);">Download to antiCensor.jpg</a>
___________
最近几天若是有空,会更新一些功能,也许会加个自定义文字、数字替换功能,也许会加个选择从左到右或相反及从上到下或相反的显示选项,和直线或横线的选项。到时若是有增加其他功能,会编辑增加在此答案的最上方。
增加了文字排序、字串替换、添加干扰字(常用高频汉字)的功能,生成文字可被复制,下载。线条可选择水平或垂直。线条部份不想多做了(如随机每个文字的位置,让文字存在轻微重叠,添加背景干扰等等),觉得这已经够了,毕竟这功能对人工审查应该没多少用途,还是加密功能好。文字颜色的功能已可使用。
图片下载功能还是有问题,下载的图片档案里依然看不到被生成的部份(虽然图片里确实有生成的内容),应该是比例的问题。
由于字数问题(回复字数不得大于 20000 字),删除了部份之前版本的回覆,存档在此。
https://web.archive.org/web/20200419160206/https://pincong.rocks/question/22785
拷贝以下代码到文档,将档案名改成 档案名.html (网页格式),即可在安全的浏览器上运行(浏览器不安全的话,我也没方法),无须联网。
要拷贝的代码, <html> 为第一行,到 </html> 为最后一行。
<html>
<head>
<meta charset="UTF-8" />
</head>
<style>
.tooltip {
position: relative;
display: inline-block;
border-bottom: 1px dotted black;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: #555;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 0;
position: absolute;
z-index: 1;
bottom: 125%;
left: 50%;
margin-left: -60px;
opacity: 0;
transition: opacity 0.3s;
}
.tooltip .tooltiptext::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: #555 transparent transparent transparent;
}
.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}
</style>
<script language="javascript">
function $(obj)
{
return document.getElementById(obj);
}
function isChecked(obj)
{
if (obj.checked)
{
return true;
}
return false;
}
function resetRadio()
{
$("horizontalRightward_verticalDownward").checked = true ;
$("noRandText").checked = true ;
$("addRange").value = 1 ;
$("notRepWord").checked = true ;
$("lineMaxNumber").checked = true ;
}
function activeRadio ()
{
$("verticalDownward_horizontalLeftward").checked = true ;
$("addRandText").checked = true ;
$("repWord").checked = true ;
$("lineMaxNumber").checked = true ;
}
function getCheckedRadio(radioName)
{
var arrRadioBtns = document.getElementsByName(radioName);
for ( i = 0 ; i < arrRadioBtns.length ; i ++ )
{
if (arrRadioBtns[i].checked )
{
return arrRadioBtns[i].value ;
}
}
return " " ;
}
function reverseString(str)
{
return str.split("").reverse().join("");
}
function insertString (str , index , value)
{
return str.substr(0,index) + value + str.substr(index);
}
function getRndNum( min , max )
{
return Math.floor(Math.random() * (max-min) ) + min ;
}
function getMaxLength ( arr )
{
var maxLength = 1 ;
for ( i = 0 ; i < arr.length ; i ++ )
{
if ( maxLength < arr[i].length )
{
maxLength = arr[i].length ;
}
}
return maxLength;
}
function rearrangeText()
{
var oText = $('originalText').value;
var alignment , horizontalDirection, verticalDirection ;
alignment = getCheckedRadio("order");
//文字排序方向
if ( alignment[0] == "R" || alignment[1] == "R" )
{
horizontalDirection = "R" ;
}
else
{
horizontalDirection = "L" ;
}
if ( alignment[0] == "D" || alignment[1] == "D" )
{
verticalDirection = "D" ;
}
else
{
verticalDirection = "U" ;
}
var newString ;
var maxColumn = 1 ;
//替换文字
if($("repWord").checked)
{
var dict = $("replaceWordDict").value ;
var splitDic , dicArray ;
splitDic = dict.split('\n') ;
var orgPattern , repPattern, tempText = "" ;
for ( i = 0 ; i < splitDic.length ; i ++ )
{
dicArray = splitDic[i].split('|');
repPattern = dicArray[1].split(',');
tempText = repPattern[getRndNum(0,repPattern.length)];
var intIndexOfMatch = oText.indexOf( dicArray[0] );
// Loop over the string value replacing out each matching substring.
while (intIndexOfMatch != -1)
{
// Relace out the current instance.
oText = oText.replace( dicArray[0], tempText )
// Get the index of any next matching substring.
intIndexOfMatch = oText.indexOf( dicArray[0] );
tempText = repPattern[getRndNum(0,repPattern.length)];
}
}
}
// 添加干扰字串
var addRandText = false ;
var addRange, addText ;
if($("addRandText").checked)
{
addText = $('addText').value.split('\n');
addRange = $("addRange").value ;
var tempText = "" ;
for ( i = Number(addRange) ; i < oText.length ; i += Number(addRange) + Number(tempText.length) )
{
tempText = addText[getRndNum(0,addText.length)];
oText = insertString (oText , i , tempText) ;
}
}
var text = oText.split('\n');
//若不是水平优先,则排序成垂直
if ( alignment[0] == "U" || alignment[0] == "D" )
{
maxColumn = getMaxLength ( text ) ;
newString = new Array (maxColumn) ;
for ( i = 0 ; i < maxColumn ; i ++ )
{
newString[i] = new Array (text.length) ;
}
for ( i = 0 ; i < text.length ; i ++ )
{
for ( j = 0 ; j < maxColumn ; j ++ )
{
if ( j >= text[i].length )
{
newString[j][i] = " ";
}
else
{
newString[j][i] = text[i][j];
}
}
}
text = new Array (maxColumn) ;
for ( i = 0 ; i < maxColumn ; i ++ )
{
text[i] = newString[i].join("");
}
}
//若不是向右,则逆转文字的横向排序
if (horizontalDirection == "L" )
{
for ( i = 0 ; i < text.length ; i ++ )
{
text[i] = reverseString(text[i]);
}
}
//若不是向下,则逆转文字的纵向排序
if ( verticalDirection == "U" )
{
text.reverse();
}
$('resultText').value = text.join("\n") ;
}
function canvasCoordinate ( isHorizontal , fsize , i , length )
{
var pn = -1, x0 = 0 , y0 = 0 , x1 = 0 , y1 = 0 ,x2 = 0 , y2 = 0 ;
if (Math.random >= 0.5)
{
pn = 1;
}
x0 = (length * fsize / 4 ) + pn * getRndNum(0,length * fsize) / 4 ;
x1 = (length * fsize * 3 / 4 ) + pn * getRndNum(0,length * fsize) / 4 ;
x2 = length * fsize;
y0 = (fsize * i) + getRndNum(0,2 * fsize) ;
y1 = (fsize * i) + getRndNum(0,2 * fsize) ;
y2 = (fsize * i) + getRndNum(0,fsize) ;
if ( isHorizontal )
{
return [x0,y0,x1,y1,x2,y2] ;
}
return [y0,x0,y1,x1,y2,x2] ;
}
function drawCanvas()
{
rearrangeText();
var c = $('canvas');
var t = $('resultText');
var fsize = $('fsize').value;
var lnumber = $('lnumber').value;
var lwidth = $('lwidth').value;
var lines = t.value.split('\n');
var columns = $('twidth').value;
var colLength = 1 , maxLength = getMaxLength ( lines ) ;
//限制每行的字数
if($("lineMaxNumber").checked)
{
for (i = 0; i < lines.length; i++)
{
if (lines[i].length > columns)
{
var end = columns ;
var nLoop = Math.ceil(lines[i].length / columns) ;
for (j = 0; j < nLoop ; j++)
{
end = columns ;
if ( j > 0 && (j == (nLoop-1) ) )
{
end = lines[i].length % columns;
if (end == 0)
{
end = columns;
}
}
lines.splice(i + j+1, 0, lines[i].substr(j * columns, end) );
}
end = i ;
i += Math.floor( lines[i].length / columns ) -1;
lines.splice(end ,1);
}
}
colLength = columns ;
}
else
{
colLength = maxLength ;
}
c.width = (colLength + 2) * fsize ;
c.height = (lines.length + 3) * fsize ;
var ctx = c.getContext('2d') ;
ctx.clearRect(0, 0, canvas.width, canvas.height) ;
ctx.beginPath() ;
ctx.font = fsize + 'px Microsoft YaHei';
ctx.lineWidth = lwidth;
ctx.fillStyle = $("textcolor").value;
var direction = getCheckedRadio("lineDirection");
if (direction == "F" )
{
direction = getCheckedRadio("order");
if ( direction[0] == "U" || direction[0] == "D" )
{
direction = "V" ;
}
else
{
direction = "H" ;
}
}
var canvasPos ;
for (i = 0; i < lines.length; i++)
{
ctx.fillText(lines[i], 0, fsize * (i + 1));
//水平画线
if (direction == "H")
{
for (j = 0; j < lnumber; j++)
{
ctx.moveTo(0, (i * fsize) + getRndNum ( 0 , fsize ) );
canvasPos = canvasCoordinate (true , fsize , i , colLength) ;
ctx.bezierCurveTo( canvasPos[0] , canvasPos[1] , canvasPos[2] , canvasPos[3] , canvasPos[4] , canvasPos[5] );
ctx.stroke();
}
}
}
//垂直画线
if (direction == "V")
{
for (i = 0; i < colLength && i < maxLength; i++)
{
for (j = 0; j < lnumber; j++)
{
ctx.moveTo((i * fsize) + getRndNum ( 0 , fsize ) , 0 );
canvasPos = canvasCoordinate (false , fsize , i , lines.length) ;
ctx.bezierCurveTo( canvasPos[0] , canvasPos[1] , canvasPos[2] , canvasPos[3] , canvasPos[4] , canvasPos[5] );
ctx.stroke();
}
}
}
var imageURI = c.toDataURL();
$('download').href = imageURI;
}
function copyText()
{
var text = $("resultText");
text.select();
text.setSelectionRange(0,99999);
document.execCommand("copy");
}
function download(filename, text)
{
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
function downloadText ()
{
// Generate download of RearrangeText.txt file with some content
var text = $("resultText").value;
var filename = "RearrangeText.txt";
download(filename, text);
}
download_img = function(el)
{
// get image URI from canvas object
var imageURI = document.getElementById("canvas").toDataURL("image/jpg");
el.href = imageURI;
};
</script>
<body style="text-align:center;">
<label><b>排序</b></label><br/>
<p>
<label class="tooltip">原文
<span class="tooltiptext">想要排序或画线的文字</span>
</label>
<textarea id="originalText" wrap="hard" placeholder="请输入文字" rows="8" ></textarea>
</p>
<br/><input type="button" id="resetRadioBtn" value="默认排序" onclick="resetRadio();"/>
<input type="button" id="activeRadioBtn" value="启用全部" onclick="activeRadio();"/><br/>
<p>
<label class="tooltip">文字排序方向
<span class="tooltiptext">从哪个方向开始,到哪里(一共8种排序方式)。</span>
</label><br/>
<input type="radio" name="order" id="horizontalRightward_verticalDownward" value ="RD" checked> 从左到右,从上到下(不变)<br/>
<input type="radio" name="order" id="horizontalLeftward_verticalDownward" value ="LD"> 从右到左,从上到下<br/>
<input type="radio" name="order" id="horizontalRightward_verticalUpward" value ="RU" > 从左到右,从下到上 <br/>
<input type="radio" name="order" id="horizontalLeftward_verticalUpward" value ="LU"> 从右到左,从下到上<br/>
<input type="radio" name="order" id="verticalDownward_horizontalLeftward" value ="DL" > 从上到下,从右到左<br/>
<input type="radio" name="order" id="verticalDownward_horizontalRightward" value ="DR" > 从上到下,从左到右<br/>
<input type="radio" name="order" id="verticalUpward_horizontalLeftward" value ="UL"> 从下到上,从右到左<br/>
<input type="radio" name="order" id="verticalUpward_horizontalRightward" value ="UR"> 从下到上,从左到右<br/><br/>
</p>
<p>
<label class="tooltip">是否替换文字
<span class="tooltiptext">替换掉特定字串,针对直接对比字串的方式。(替换文字后才会进行字串添加)</span>
</label><br/>
<input type="radio" name="ReplaceWord" id="notRepWord" value ="N" checked> 不替换文字(默认)
<input type="radio" name="ReplaceWord" id="repWord" value ="Y"> 替换文字<br/>
<label class="tooltip">替换字串
<span class="tooltiptext">替换掉特定字串,针对直接对比字串的方式,格式为每行一个替换词,在|符号前的是被替换的字串,在|符号后的是用来替换的字串。若是用来替换的字串大于1个,则用来替换的字串之间以,符号为间隔,会随机选择其中一个来进行替换。(可以搜索关键字字库)(依照被替换字串的排序替换,如文字包括12,有两个被替换字串1和12,字串库中被替换字串1在12前面,12就不会被替换,因为在碰到1时,1已经被替换掉了。)</span>
</label>
<textarea id="replaceWordDict" rows="4">1989|¹玖8九,3²*13*17,一九九零减1,1980加九
御坂美琴|炮姐,超电磁炮,BiliBili,哔哩哔哩
0|⁰
1|¹
2|²
3|³
4|⁴
5|⁵
6|⁶
7|⁷
8|⁸
9|⁹
一|壹,ONE
二|貳,TWO
三|參,THREE
四|肆,FOUR
五|伍,FIVE
六|陸,SIX
七|柒,SEVEN
八|捌,EIGHT
九|玖,NINE
十|拾,TEN
百|佰
千|仟
万|萬
亿|億
国家|郭嘉,Country</textarea><br/>
</p>
<p>
<label class="tooltip">是否随机添加文字
<span class="tooltiptext">添加随机文字,针对直接对比字串的方式。(替换文字后才会进行字串添加)</span>
</label><br/>
<input type="radio" name="randAddText" id="noRandText" value ="N" checked> 不添加(默认)
<input type="radio" name="randAddText" id="addRandText" value ="Y"> 添加<br/>
<label class="tooltip" >添加间隔
<span class="tooltiptext">每隔多少个字就添加一次随机文字字串。</span>
</label>
<input type="number" id="addRange" value="1"/><br/>
<label class="tooltip">添加字串
<span class="tooltiptext">添加随机文字,针对直接对比字串的方式。每行为一个添加字串,会在所有字串里随机选择。可以搜索汉字的高出现频率字来加入字串库,避免字数频率统计。</span>
</label>
<textarea id="addText" rows="4">的
我
是
了
来
们
你
他
她
大
和
好
个
说
到
以
一
在
有
这
为
我们
正能量</textarea><br/>
</p>
<label class="tooltip" >生成文字
<span class="tooltiptext">依照以上设定及次序生成文字。</span>
</label>
<textarea id="resultText" rows="4">文字生成结果</textarea><br/>
<input type="button" id="generateText" value="点击以生成文字" onclick="rearrangeText();"/><br/><br/>
<input type="button" id="copyText" value="拷贝生成文字结果到剪貼板" onclick="copyText();"/><br/><br/>
<input type="button" id="downloadTextBtn" value="下载文字txt档案 RearrangeText.txt" onclick="downloadText();"/><br/><br/>
<label class="tooltip" ><b>画线</b>
<span class="tooltiptext">在文字上画线。</span>
</label><br/>
<p><label class="tooltip">字号
<span class="tooltiptext">字体的大小。</span>
</label>
<input type="text" value="20" id="fsize" />
</p>
<p>
<label class="tooltip" >是否启用每行字数
<span class="tooltiptext">启用则限制每行超过字数的文字会被换行。对于从下到上的排序,启用后,原超过字数的每行的内部被换行的排序是依照上到下排序的,而不是从下到上。</span>
</label><br/>
<input type="radio" name="lineMaxNum" id="lineMaxNumber" value ="Y" checked> 启用(自定义字数)(默认)
<input type="radio" name="lineMaxNum" id="noLineMaxNumber" value ="N"> 不启用<br/>
</p>
<p><label class="tooltip">每行字数
<span class="tooltiptext">每行最大允许字数,超过则会自动换行,数字,不低于1。</span>
</label>
<input type="text" value="20" id="twidth" />
</p>
<p><label class="tooltip">颜色
<span class="tooltiptext">文字的颜色。</span>
</label>
<input type="color" id="textcolor" value="#000000" />
</p>
<p>
<label class="tooltip">干扰线条方向
<span class="tooltiptext">是默认跟随文字的排序来画水平/垂直线条,或者固定为水平线条或垂直线条。</span>
</label><br/>
<input type="radio" name="lineDirection" id="lineDFollowWord" value ="F" checked> 跟随文字排序(默认)
<input type="radio" name="lineDirection" id="lineDHorizontal" value ="H"> 水平<br/>
<input type="radio" name="lineDirection" id="lineDVertical" value ="V"> 垂直<br/>
</p>
<p><label class="tooltip">每行干扰线条数
<span class="tooltiptext">线条数量,太多会看不清楚。</span>
</label> <input type="text" id="lnumber" value="2" /></p>
<p><label class="tooltip">干扰线宽度
<span class="tooltiptext">线条宽度,太多会看不清楚。</span>
</label> <input type="text" id="lwidth" value="0.3" /></p>
<p><button type="button" onclick="drawCanvas()">生成</button></p>
<label class="tooltip">生成结果
<span class="tooltiptext">生成的画线结果。(会重新进行一次文字生成,而不是直接拿之前文字生成的结果(若有)。)</span>
</label><br/><br/>
<canvas id="canvas"></canvas>
<a id="download" download="antiCensor.jpg" href="" onclick="download_img(this);">Download to antiCensor.jpg</a><br/><br/>
<label>请勿将此程序用于任何会伤害到他人的地方。</label>
</body>
</html>
好了,代码结束。
_____________
要不设个Array,如果lines[i]里面的字数大过输入字数column,就循环substr出来column长度(最后一个是剩余长度),push进去array里面,小过column就正常push进去lines[i]的数据。
最后再从那个array 里面提取。
(很久没碰代码了,又不方便去试错看value在哪里跑掉,只是建议)
(粗试一下,猜测你取消的部分可能是因为实时加数据,导致loop无限循环,建议自己在错误范围加一堆输出,看那些value在哪个循环开始不对劲,怎样不对劲)
半成品,还有一点问题。太久没碰javascript了,不想继续了。
for (i = 0; i < lines.length; i++)
{
if (lines[i].length > colomns)
{
var end = colomns ;
var nLoop = Math.ceil(lines[i].length / colomns) ;
for (j = 0; j < nLoop ; j++)
{
end = colomns ;
if ( j > 0 && (j == (nLoop-1) ) )
{
end = lines[i].length % colomns;
if (end == 0)
{
end = colomns;
}
}
lines.splice(i + j+1, 0, lines[i].substr(j * colomns, end) );
}
end = i ;
i += Math.floor( lines[i].length / colomns ) -1;
lines.splice( end ,1);
}
}
//没改内容,觉得影响输出显示的行数的部分应该来自这边
for (i = 0; i < lines.length; i++) {
ctx.fillText(lines[i], 0, fsize * (i + 1));
for (j = 0; j < lnumber; j++) {
ctx.moveTo(0, fsize * ((j + Math.random() + 1) / lines.length + i));
ctx.quadraticCurveTo(
((1 + Math.random()) / 3) * colomns * fsize,
fsize * (i + (j + Math.random() + 1) / lines.length),
colomns * fsize,
fsize * ((j + Math.random() + 1) / lines.length + i)
);
ctx.stroke();
}
}
我修改的还是有问题,没找到在哪里会限制到输出显示的行数。如果输入的行数太短,转化后显示的行数不完全,会吞掉几行,要自己在输入那边多打几个换行。(自己试一些输入,有的输出又没问题,有的输入又会出现显示不完全的问题)
__________
今天再看看,找到限制行数显示的问题在哪里了,是设定canvas的位置(height)早了(因为按照字数切完后,list的长度会改变(多数是增加,超过3就有问题了)),我重新修了一下declare c.height位置(移到切完字数的后面)(本来想把按字数切的放去recursive函数,后来没成功,就放弃了),看起来没问题了。加了一个下载图片,不过图片虽然有内容,但是比例不对。
script
function $(obj)
{
return document.getElementById(obj);
}
function submit()
{
var c = $('canvas');
var t = $('textbox');
var fsize = $('fsize').value;
var lnumber = $('lnumber').value;
var lwidth = $('lwidth').value;
var lines = t.value.split('\n');
var columns = $('twidth').value;
for (i = 0; i < lines.length; i++)
{
if (lines[i].length > columns)
{
var end = columns ;
var nLoop = Math.ceil(lines[i].length / columns) ;
for (j = 0; j < nLoop ; j++)
{
end = columns ;
if ( j > 0 && (j == (nLoop-1) ) )
{
end = lines[i].length % columns;
if (end == 0)
{
end = columns;
}
}
lines.splice(i + j+1, 0, lines[i].substr(j * columns, end) );
}
end = i ;
i += Math.floor( lines[i].length / columns ) -1;
lines.splice(end ,1);
}
}
//放在list整理好的后面就没问题了,因为是用lines.length 来 + 3
c.width = (columns + 1) * fsize ;
c.height = (lines.length + 3) * fsize ;
var ctx = c.getContext('2d') ;
ctx.clearRect(0, 0, canvas.width, canvas.height) ;
ctx.beginPath() ;
ctx.font = fsize + 'px Microsoft YaHei';
ctx.lineWidth = lwidth;
//我调整了一下我想要的画线方式
for (i = 0; i < lines.length; i++)
{
ctx.fillText(lines[i], 0, fsize * (i + 1));
var pn = -1 ;
for (j = 0; j < lnumber; j++) {
//随机X的位置是在1/4和3/4的左边(不超过1/4的宽度)还是右边(不超过1/4的宽度)
pn = -1 ;
if (Math.random >= 0.5)
{
pn = 1;
}
//改成了这个函数,多一个点,线条应该会比较多变
ctx.bezierCurveTo(
(columns * fsize / 4 ) + pn * (Math.floor(Math.random() * columns * fsize )) / 4 ,
(fsize * i) + Math.floor(Math.random() * 2 * fsize) ,
(columns * fsize * 3 / 4 ) + pn * (Math.floor(Math.random() * columns * fsize )) / 4 ,
(fsize * i) + Math.floor(Math.random() * 2 * fsize) ,
columns * fsize,
(fsize * i) + Math.floor(Math.random() * fsize)
);
ctx.stroke();
}
}
//图片下载,测试后,觉得下载的内容比例不对
var imageURI = c.toDataURL();
$('download').href = imageURI;
}
HTML body
<p>
<textarea id="textbox" wrap="hard" placeholder="请输入文字" ></textarea>
</p>
<p><label>字号</label><input type="text" value="20" id="fsize" /></p>
<p><label>每行字数</label><input type="text" value="20" id="twidth" /></p>
<p>
<label>颜色</label> <input type="color" id="textcolor" value="#000000" />
</p>
<p>
<label>每行干扰线条数</label> <input type="text" id="lnumber" value="2" />
</p>
<p>
<label>干扰线宽度</label> <input type="text" id="lwidth" value="0.3" />
</p>
<p><button type="button" onclick="submit()">生成</button></p>
<canvas id="canvas"></canvas>
<a id="download" download="antiCensor.jpg" href="" onclick="download_img(this);">Download to antiCensor.jpg</a>
___________
最近几天若是有空,会更新一些功能,也许会加个自定义文字、数字替换功能,也许会加个选择从左到右或相反及从上到下或相反的显示选项,和直线或横线的选项。到时若是有增加其他功能,会编辑增加在此答案的最上方。
非常好,你可以找个开源输入法集成进去。
现在很多手机输入法可以输入文字选择图片发出,集成了你这个程序后可以有效避免被审查。
现在很多手机输入法可以输入文字选择图片发出,集成了你这个程序后可以有效避免被审查。
说实话我还是觉得抽象话和火星文生成器效果更好一些,只有人类才有才能理解的黑话会让AI直接傻眼只能人工审查
這種方法是很危險的, 一旦被發現, 發言人就被關了!
/**
*图片宽高&文本的高度& 保存路径自己调整
*/
publicclaDemo{
/**
*图片的宽度
*/
publictaticfinalintIMAGE_WIDTH=150;
/**
*图片的高度
*/
publictaticfinalintIMAGE_HEIGHT=30;
publictaticvoidmain(String[]arg){
Sytem.out.println("pleaeinputfucktext:");
//获取图片对象
BufferedImagebufferedImage=generatorImage(getTextFromKeybord(),null);
//将图片写到本地
aveImage2Local(bufferedImage,null,"e:/fuck.png");
}
/**
*从键盘读取文本
*return
*/
publictaticStringgetTextFromKeybord(){
Stringtext=newScanner(Sytem.in).next(); //也可以使用BufferedReader.next()读取
returntext;
}
/**
*创建图片对象
*paramimageType 图片类型
*paramimageText要保存到图片上的文本信息
*return图片对象
*/
publictaticBufferedImagegeneratorImage(StringimageText,IntegerimageType){
//设置图片类型&图片文本的默认值
imageType=(imageType==null||imageType<0)?BufferedImage.TYPE_INT_RGB:imageType;
imageText=(StringUtil.iBlank(imageText))?"空文本":imageText;
BufferedImagebufferedImage=newBufferedImage(IMAGE_WIDTH,IMAGE_HEIGHT,imageType);
Graphic2Dgraphic=(Graphic2D)bufferedImage.getGraphic();
//绘制图片背景
drawImageBG(graphic,null);
//绘制文本
drawText2Image(graphic,Color.BLACK,imageText,newFont("楷体",Font.BOLD,20));
//绘制干扰线
drawRandomLine(graphic,null,10);
returnbufferedImage;
}
/**
*绘制图片背景
*paramg绘制对象
*paramcutomColor自定义背景颜色
*/
publictaticvoiddrawImageBG(Graphic2Dg,ColorcutomColor){
//默认背景为白色
g.etColor((cutomColor==null)?Color.WHITE:cutomColor);
//绘制...
g.fillRect(1,1,IMAGE_WIDTH-2,IMAGE_HEIGHT-2);
}
/**
*将文本绘制到图片上
*paramg绘制对象
*paramcolor文本颜色
*paramtext文本
*paramfont字体
*/
privatetaticvoiddrawText2Image(Graphic2Dg,Colorcolor,Stringtext,Fontfont){
g.etColor(color);
g.etFont(font);
//定义文本的开始坐标
inttartX=20,tartY=15;
for(inti=0;text!=null&&i<text.length();i++){
//获取每个文本值
Stringch=text.charAt(i)+"";
g.drawString(ch,tartX,tartY);
tartX+=font.getSize();
}
}
/**
*绘制随机干扰线
*paramgraphic2D绘制对象
*paramlineNumber干扰线条数
*paramcolor干扰线颜色
*/
publictaticvoiddrawRandomLine(Graphic2Dgraphic2D,Colorcolor,intlineNumber){
//默认干扰线为青色
color=(color==null)?Color.CYAN:color;
//设置默认的干扰线条数
lineNumber=(lineNumber<=0)?4:lineNumber;
//设置干扰线颜色
graphic2D.etColor(color);
for(inti=0;i<lineNumber;i++){
//线条的起始坐标----随机
inttartX=newRandom().nextInt(IMAGE_WIDTH-1);
inttartY=newRandom().nextInt(IMAGE_HEIGHT-1);
intendX=newRandom().nextInt(IMAGE_HEIGHT-2);
intendY=newRandom().nextInt(IMAGE_HEIGHT-2);
graphic2D.drawLine(tartX,tartY,endX,endY);
}
}
/**
*将生成好的图片保存到本地
*parambufferedImage 图片
*paramimageFormat图片格式(PNGJPEGGIF...)
*paramfilePath 保存路径
*/
publictaticvoidaveImage2Local(BufferedImagebufferedImage,StringimageFormat,StringfilePath){
try{
imageFormat=(StringUtil.iBlank(imageFormat))?"png":imageFormat;
ImageIO.write(bufferedImage,imageFormat,newFileOutputStream(filePath));
Sytem.out.println("图片保存成功!===>"+filePath);
}catch(IOExceptione){
e.printStackTrace();
thrownewRuntimeException("保存图片失败!!"+e.getMeage());
}
}
}
感覺上專門辨認 CAPTCHA 的機械人會很容易將其攻破,可能要再將字體扭曲,而且這種方法防不了人手審查(不過逼使人手審查也是一種加大維穩成本的手段)
另一方面,這種劃線令我想起之前一班截圖品葱又一堆紅叉劃線,企圖罵品葱又意外為品葱宣傳的粉紅。如果你的方向改成裝作罵你想宣傳的文章/截圖,而不是避過自動偵測的話,可能會更好
另一方面,這種劃線令我想起之前一班截圖品葱又一堆紅叉劃線,企圖罵品葱又意外為品葱宣傳的粉紅。如果你的方向改成裝作罵你想宣傳的文章/截圖,而不是避過自動偵測的話,可能會更好
