설명:
1. 이 글에서는 웹 페이지 제작 기술을 활용하여 문제를 종합적으로 해결한다는 아이디어를 구현하여 웹 페이지에 바코드 효과를 구현하는 방법을 설명합니다. HTML, JavaScript 및 PhotoShop에 대한 초급 수준의 숙련도를 갖춘 사람들을 위한 초급 수준 기술을 통합하도록 설계되었습니다.
2. 문의사항이 있어 시간 내에 답변을 드릴 수 없는 경우, 불편을 끼쳐드려 죄송합니다.
3. 전문가는 참가가 면제됩니다.
바코드를 만드는 데는 몇 단계가 있나요?
첫 번째 단계는 냉장고 문을 여는 것입니다. PhotoShop을 사용하여 작은 그림을 그려보세요
16개 요소가 포함된 바코드 이미지를 만들어야 합니다.
먼저 Photoshop을 엽니다. 이 튜토리얼에서는 중국어 간체 버전을 사용하므로 주의 깊게 읽으면 아무런 문제도 발생하지 않습니다.
열린 후 먼저 Ctrl N을 눌러 8픽셀을 만듭니다.
다음으로 검은색 부분을 제거하여 투명하게 만들어야 합니다. 마술봉 도구를 사용하여 다음과 같이 옵션을 설정합니다.
선택 후 삭제 키를 눌러 삭제하면 전체 캔버스가 다음과 같이 됩니다.
지저분해 보입니다. PS 투명한 배경으로 표현하는 문제와 관련하여 이 효과를 얻으려면 단계가 올바른지 확인하세요.
파일 선택 - 다른 이름으로 저장하고 형식을 gif로 선택하면 아래 대화 상자에서 투명 옵션을 지정할 수 있습니다. 선택해야 합니다. 놓을 적절한 장소를 찾으십시오.
그러다가 냉장고 문이 열렸어요. 이렇게 안되면 막히지 않도록 제가 만든 걸 사용하세요. 척하는 코끼리가 들어갑니다.
두 번째 단계는 코끼리를 넣는 것입니다 - 코드 분석
우리의 목표는 캐릭터를 넣는 것입니다. 문자열은 바코드로 변환되어 페이지에 표시됩니다. 그렇다면 문자열은 바코드와 어떻게 일치합니까? 위의 128X8 그림을 만드는 이유는 무엇입니까?
메모리에서 가장 기본적인 데이터 저장 단위인 바이트는 8비트라고 생각할 수 있습니다. 8비트 이진수는 00 - FF로 표시되는 2자리 16진수로 표시될 수 있습니다. 방금 16이라고 언급했는데, 눈치채셨나요?
문자열을 바이트 표현으로 변환하는 방법은 무엇입니까? 직접적으로 표현할 수 없을 것 같지만, J(ava)script의 문자열에는 charCodeAt() 메소드가 있습니다. 단일 바이트가 정수를 나타내는 경우 범위는 0 - 255이고 더블 바이트가 양의 정수를 나타내는 경우 범위는 0 - 65535입니다. charCodeAt() 메서드는 문자의 유니코드 표현을 반환합니다. 이 유니코드 체계에서 중국어는 2바이트이고 영어는 1바이트입니다. 따라서 영어 문자의 경우 항상 0 - 255 사이의 양의 정수를 반환하고, 중국어 문자의 경우 항상 255 - 65535(정확한 범위는 아님) 사이의 양의 정수를 반환합니다.
Microsoft의 Jscript 스크립트 참조 매뉴얼에서 발췌한 비트 연산에 대해 다시 이야기해 보겠습니다.
0101(표현식1)
1100(표현식2)
----
0100(결과)
언제든지 두 가지 표현식이 있습니다. 특정 비트는 모두 1이고 결과의 비트는 1입니다. 그렇지 않으면 결과의 이 비트는 0입니다.
temp = -14 >> 2
참고: 32비트 정수형 데이터에는 부호 비트 문제가 있습니다. 음수의 경우 패딩 비트는 1이고 양수의 경우 패딩 비트는 0입니다. charCodeAt()를 통해 얻은 숫자는 모두 양수이므로 이 문제에 대해 걱정하지 마십시오.
8비트 이진수 AND 이진수 11110000의 경우 오른쪽으로 4비트 이동하면 가장 왼쪽 4자리를 얻을 수 있습니다.
그리고 1111을 직접 보면 오른쪽에 숫자 4개가 나옵니다.
이제 준비 지식은 이것으로 충분합니다. 이제 코딩 연습을 시작하겠습니다.
문자열이 있어야 문자열이 있다고 하더군요.
var strTest = "dknt는 의미가 없습니다.";
이 문자열을 바코드로 변환하고 싶습니다.
우리는 이진 표현을 얻으려는 다음 이진 표현을 얻는 함수를 만듭니다. 예를 들어 getBinary();
예:
<script> function getBinary(sText){ alert(sText); }; var strTest = "dknt没有任何含义"; getBinary(strTest ); </script>
<script> function getBinary(sText){ for(var i = 0; i < sText.length; i++){ alert( sText.charCodeAt( i ) ); } }; var strTest = "dknt没有任何含义"; getBinary(strTest ); </script>
<script> function getBinary(sText){ for(var i = 0; i < sText.length; i++){ var iDecimalUnicode =sText.charCodeAt( i ); if( iDecimalUnicode > 255 ){ alert( (iDecimalUnicode & 0xFF00) >> 8); alert( iDecimalUnicode & 0xFF ); }else{ alert( iDecimalUnicode ); } } }; var strTest = "dknt没有任何含义"; getBinary(strTest ); </script>
可以看到现在每个数都是小于255的了。
注意,(iDecimalUnicode & 0xFF00) >> 8 中,>> 的优先级比 & 高,所以按照我们的目的,(iDecimalUnicode & 0xFF00) 一定要有括号。
我们希望能有个统一的处理逻辑,把每个字节分成两部分,每个部分用十六进制的1位就可以表示,换句话说,就是每部分都是一个不超过16的十进制数。类似Ruby中的代码段数据类型,在J(ava)script中,也可以用匿名函数来实现类似的功能。我们可以建一个名为tmpOP变量来承接这个匿名函数,然后利用它来简化程序逻辑。此外,我们应该有个东西来储存分解出来的结果。那就用个result数组来装吧。另外按照语义,我们这个函数做的已经不仅仅是转化二进制了,而是转化成意义上的十六进制位了。我们应该是恨敏捷的,所以把函数名改成getHexes吧。
<script> function getHexes(sText){ var aResult = []; var tmpOP = function(iByte){ aResult.push( (iByte & 0xF0) >> 4 ); aResult.push( iByte & 0xF ); }; for(var i = 0; i < sText.length; i++){ var iDecimalUnicode =sText.charCodeAt( i ); if( iDecimalUnicode > 255 ){ tmpOP( (iDecimalUnicode & 0xFF00) >> 8); tmpOP( iDecimalUnicode & 0xFF ); }else{ tmpOP( iDecimalUnicode ); } } alert(aResult); }; var strTest = "dknt没有任何含义"; getHexes(strTest ); </script>
很高兴看到现在就弹出一个alert吧,刚才那么多alert是很闹心。我很抱歉。这次因为我们使用了alert一个数组,感觉整齐一点。
现在发现数组的每一个元素都是小于16了吧,很好,大象快装进去了。
有一个问题,我们不能把字符串的每个字符都转化成条形码,若是一个1万多字的文章怎么办,那不扯呢吗。所以我们要限制一下处理的字符数。以条形码的视点来看,似乎宽度应该是固定的,也就是说我们用以对应的 aResult 数组的长度应该是固定的。那也好办,在我们的 tmpOP 里控制一下就行了。我们可以假设我们只需要8个十六进制位来生成条形码。可以在getHexes里加一个 iMaxLength 参数来控制。
如下:
<script> function getHexes(sText, iMaxLength){ var aResult = []; var tmpOP = function(iByte){ aResult.push( (iByte & 0xF0) >> 4 ); if( aResult.length > iMaxLength ) return 0; aResult.push( iByte & 0xF ); if( aResult.length > iMaxLength ) return 0; return 1; }; for(var i = 0; i < sText.length; i++){ var iDecimalUnicode =sText.charCodeAt( i ); if( iDecimalUnicode > 255 ){ if( !tmpOP( (iDecimalUnicode & 0xFF00) >> 8) ) break;; if( !tmpOP( iDecimalUnicode & 0xFF ) ) break; }else{ if( !tmpOP( iDecimalUnicode ) ) break; } } alert(aResult); }; var strTest = "dknt没有任何含义"; var iWidth = 8; getHexes(strTest, iWidth); </script>
现在确实只有8个小于16的数了。
在 tmpOP 中,发现 aResult 数组的长度超过最大值,就返回一个0,外面发现这个0以后,就直接退出循环,因为没有必要再继续往下取字符了。
有些地方略显不妥,本着精益求精的精神,我们要把我们的程序效率提高提高。首先,我们知道了位相与的目的,就可以写一些更直接处理的代码,因为我们把处理双字节时,为了分成两个单字节,实际上多与运算了一次,和后面的分解双十六进制位有重复的位相与。说俗了就是多干了一次没用的事。不如一次就分解出4个十六进制位。
此外,我们总是向数组询问length属性来获知数组长度,要知道数组做这件事是很累的,反正我们也有条件自己心理有数,为什么还要总问它呢。
基于这两点,我们把程序改动如下:
<script> function getHexes(sText, iMaxLength){ var aResult = [], aPos=[0xF, 0xF0, 0xF00, 0xF000], iLength = 0; var tmpOP = function(iByte, iPos){ aResult.push( (iByte & aPos[iPos]) >> iPos * 4 ); iLength++ if( iLength == iMaxLength ) return 0; return 1; }; for(var i = 0; i < sText.length; i++){ var iDecimalUnicode =sText.charCodeAt( i ); if( iDecimalUnicode > 255 ){ if( !tmpOP( iDecimalUnicode , 3) ) break;; if( !tmpOP( iDecimalUnicode , 2) ) break; if( !tmpOP( iDecimalUnicode , 1) ) break; if( !tmpOP( iDecimalUnicode , 0) ) break; }else{ if( !tmpOP( iDecimalUnicode , 1) ) break;; if( !tmpOP( iDecimalUnicode , 0) ) break; } } alert(aResult); }; var strTest = "dknt没有任何含义"; var iWidth = 8; getHexes(strTest, iWidth); </script>
看到了效果跟上一个是一样的,说明我们没改错。其中,aPos数组就可以储存掩码,数组的索引 X 4 就是需要右移的位数。tmpOP( iDecimalUnicode , i) 就表示取 iDecimalUnicode 从右边数第i个十六进制位(第0个就是最右边的1个十六进制位)。
大象是勉勉强强塞进去了,下面我们就把活做的利索点,把冰箱门儿带上。要不条形码还没露面,我们怎么收场?
第三步,把冰箱门儿带上——封装和测试用例
接下来的工作重点就是要把条形码做出来。为了测试效果,我们还需要一个用户界面。
皮之不存,毛之焉附,首先做一个界面。随便做一个普通页面就行了。然后在上面安放一个文本框,一个触发按钮,一个条形码显示区域。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Barcode Test Case</title> </head> <body> <p style="float:left;"> <input type="text" /> <input type="button" value="Generate"/> </p> <p style="float:left;"></p> </body> </html>
我们需要把大象移植过来,加在我们的界面上,此外我们还需要让按钮能触发getHexes函数,那就加一个 onclick方法吧。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Barcode Test Case</title> <script> function getHexes(sText, iMaxLength){ var aResult = [], aPos=[0xF, 0xF0, 0xF00, 0xF000], iLength = 0; var tmpOP = function(iByte, iPos){ aResult.push( (iByte & aPos[iPos]) >> iPos * 4 ); iLength++ if( iLength == iMaxLength ) return 0; return 1; }; for(var i = 0; i < sText.length; i++){ var iDecimalUnicode =sText.charCodeAt( i ); if( iDecimalUnicode > 255 ){ if( !tmpOP( iDecimalUnicode , 3) ) break;; if( !tmpOP( iDecimalUnicode , 2) ) break; if( !tmpOP( iDecimalUnicode , 1) ) break; if( !tmpOP( iDecimalUnicode , 0) ) break; }else{ if( !tmpOP( iDecimalUnicode , 1) ) break;; if( !tmpOP( iDecimalUnicode , 0) ) break; } } alert(aResult); }; var strTest = "dknt没有任何含义"; var iWidth = 8; </script> </head> <body> <div style="float:left;"> <input type="text" /> <input type="button" value="Generate" onclick="getHexes(strTest, iWidth)"/> </div> <div style="float:left;"></div> </body> </html>
点击Generate按钮可以发现,我们之前的程序逻辑仍然生效。说明移植成功。
问题很大,getHexes始终操作的是一个固定的变量值,怎么让它能操作界面上的值呢?可以操作DOM来获取界面上的值。要使用DOM来操作,最简单的方法就是给所关注的元素上添加 id 属性。此外在 iWidth 这个变量在我们的界面中没有接口,看来是忘了,不过这个忘了很正常,当初根据我们的界面设计语义本来就没有这个内容。我们确实很敏捷,马上添加上去就行了。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Barcode Test Case</title> <script> function getHexes(sText, iMaxLength){ var aResult = [], aPos=[0xF, 0xF0, 0xF00, 0xF000], iLength = 0; var tmpOP = function(iByte, iPos){ aResult.push( (iByte & aPos[iPos]) >> iPos * 4 ); iLength++ if( iLength == iMaxLength ) return 0; return 1; }; for(var i = 0; i < sText.length; i++){ var iDecimalUnicode =sText.charCodeAt( i ); if( iDecimalUnicode > 255 ){ if( !tmpOP( iDecimalUnicode , 3) ) break;; if( !tmpOP( iDecimalUnicode , 2) ) break; if( !tmpOP( iDecimalUnicode , 1) ) break; if( !tmpOP( iDecimalUnicode , 0) ) break; }else{ if( !tmpOP( iDecimalUnicode , 1) ) break;; if( !tmpOP( iDecimalUnicode , 0) ) break; } } alert(aResult); }; </script> </head> <body> <div style="float:left;"> <div style="float:left; width:70px; font-size:18px;line-height:25px; font-family:Arial"> Text: Width: </div> <div style="float:left;"> <input id="text" type="text" value="dknt没有任何含义" /> <input id="width" type="text" value="8"/></div> <div style="float:left;margin-left:20px"> <input type="button" value="Generate" onclick="getHexes(document.getElementById('text').value, parseInt( document.getElementById ('width').value) )"/></div> </div> <div style="float:left;"></div> </body>
注意,我们已经把 标签的
var strTest = "dknt没有任何含义";
var iWidth = 8;
两句去掉了。因为他们确实没有什么用了,我们已经不从那里获得数据了。
这回,如果你改动两个文本框中的文字,将会看到另外一组十六进制位。此外,我们觉得加一个对文本框的说明更好一些,所以就在前面加了个p.
现在我们发现似乎把一大串字符写在onlick里似乎有点不自然,如果将来逻辑更复杂了将很难维护,不如就单建个函数专门负责此事。它也可以包含更复杂的调度逻辑。此外,我们对两个文本框的类型没有验证,如果输入的不是我们想要的数据类型怎么办?所以还要加上判断逻辑。所以修改如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Barcode Test Case</title> <script> function getHexes(sText, iMaxLength){ var aResult = [], aPos=[0xF, 0xF0, 0xF00, 0xF000], iLength = 0; var tmpOP = function(iByte, iPos){ aResult.push( (iByte & aPos[iPos]) >> iPos * 4 ); iLength++ if( iLength == iMaxLength ) return 0; return 1; }; for(var i = 0; i < sText.length; i++){ var iDecimalUnicode =sText.charCodeAt( i ); if( iDecimalUnicode > 255 ){ if( !tmpOP( iDecimalUnicode , 3) ) break;; if( !tmpOP( iDecimalUnicode , 2) ) break; if( !tmpOP( iDecimalUnicode , 1) ) break; if( !tmpOP( iDecimalUnicode , 0) ) break; }else{ if( !tmpOP( iDecimalUnicode , 1) ) break;; if( !tmpOP( iDecimalUnicode , 0) ) break; } } alert(aResult); }; function GenerateBarCode(){ var sText = document.getElementById('text').value, iWidth = parseInt( document.getElementById('width').value ); sText = sText.replace(/(^\s+|\s+$)/ig, ''); iWidth = iWidth || 0; if( iWidth > 20 || iWidth < 0) return false; if(sText.length < iWidth ) return false; getHexes(sText, iWidth) } </script> </head> <body> <div style="float:left;"> <div style="float:left; width:70px; font-size:18px;line-height:25px; font-family:Arial"> Text: Width: </div> <div style="float:left;"> <input id="text" type="text" value="dknt没有任何含义" /> <input id="width" type="text" value="8"/></div> <div style="float:left;margin-left:20px"> <input type="button" value="Generate" onclick="GenerateBarCode()"/></div> </div> <div style="float:left;"></div> </body>
GenerateBarCode 要去掉text左右的空格,然后还要检查width是否是有效值(这里最大设为20,不过你可以随便改,太大似乎就有点变态了)。
然而我们的条形码还是没出来,但是我们已经恨厌倦alert了,这次一定要让getHexes返回一个数组给GenerateBarCode,然后让GenerateBarCode进行后续处理。
<title>Barcode Test Case</title> <script> function getHexes(sText, iMaxLength){ var aResult = [], aPos=[0xF, 0xF0, 0xF00, 0xF000], iLength = 0; var tmpOP = function(iByte, iPos){ aResult.push( (iByte & aPos[iPos]) >> iPos * 4 ); iLength++ if( iLength == iMaxLength ) return 0; return 1; }; for(var i = 0; i < sText.length; i++){ var iDecimalUnicode =sText.charCodeAt( i ); if( iDecimalUnicode > 255 ){ if( !tmpOP( iDecimalUnicode , 3) ) break;; if( !tmpOP( iDecimalUnicode , 2) ) break; if( !tmpOP( iDecimalUnicode , 1) ) break; if( !tmpOP( iDecimalUnicode , 0) ) break; }else{ if( !tmpOP( iDecimalUnicode , 1) ) break;; if( !tmpOP( iDecimalUnicode , 0) ) break; } } return aResult ; }; function GenerateBarCode(){ var sText = document.getElementById('text').value, iWidth = parseInt( document.getElementById('width').value ); sText = sText.replace(/(^\s+|\s+$)/ig, ''); iWidth = iWidth || 0; if( iWidth > 20 || iWidth < 1) return false; var aHexes = getHexes(sText, iWidth), sDivString=''; for (var i = 0; i < iWidth; i++){ sDivString += "<div style=\"width:8px;height:8px;float:left;background-image:url("+gifURL+");background-position-x:"+(8 * aHexes[i]) +"px\"></div>" } document.getElementById('BarCode_Field').innerHTML = sDivString; } var gifURL = "/upload/200742411119165.gif"; </script> </head> <body> <div style="float:left;"> <div style="float:left; width:70px; font-size:18px;line-height:25px; font-family:Arial"> Text: Width: </div> <div style="float:left;"> <input id="text" type="text" value="dknt没有任何含义" /> <input id="width" type="text" value="8"/></div> <div style="float:left;margin-left:20px"> <input type="button" value="Generate" onclick="GenerateBarCode()"/></div> </div> <div id="BarCode_Field" style="float:left;margin-left:20px"></div> </body>
GenerateBarCode接到getHexes传过来的数组以后开始使用其中的十六进制位构造DIV小单元。其中,我们用 background-image 来指明背景文件的位置,正好我刚才上传了做好的gif文件,用gifURL保存它的位置。background-position-x表示背景图片水平方向偏移,我们用十六进制位(范围是0-15) X 8 (即gif小单元的像素宽度) 正好就可以让我们想要的gif小单元作为当前div的背景了。这就是我们的gif为什么要做成那样的原因。实际上,之所以要把所有的小单元放在一个图片里,主要是为了节省I/O调用的次数,提高效率。
GenerateBarCode中的for循环,终止条件是iWidth,以便让sText补足iWidth位时,也能显示出 iWidth 位来,因为数组空元素的默认值可以返回0。
我们给承接结果的div赋以id为BarCode_Field,将构造好的HTML片段放在这个div中,页面就可以呈现出条形码了。
然而似乎还是没看到条形码。那当然了,我们的gif背景透明色已经让页面的背景白色透过来了,白成一片了,当然看不着。我们得改一下Body的背景颜色。如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Barcode Test Case</title> <script> function getHexes(sText, iMaxLength){ var aResult = [], aPos=[0xF, 0xF0, 0xF00, 0xF000], iLength = 0; var tmpOP = function(iByte, iPos){ aResult.push( (iByte & aPos[iPos]) >> iPos * 4 ); iLength++ if( iLength == iMaxLength ) return 0; return 1; }; for(var i = 0; i < sText.length; i++){ var iDecimalUnicode =sText.charCodeAt( i ); if( iDecimalUnicode > 255 ){ if( !tmpOP( iDecimalUnicode , 3) ) break;; if( !tmpOP( iDecimalUnicode , 2) ) break; if( !tmpOP( iDecimalUnicode , 1) ) break; if( !tmpOP( iDecimalUnicode , 0) ) break; }else{ if( !tmpOP( iDecimalUnicode , 1) ) break;; if( !tmpOP( iDecimalUnicode , 0) ) break; } } return aResult ; }; function GenerateBarCode(){ var sText = document.getElementById('text').value, iWidth = parseInt( document.getElementById('width').value ); sText = sText.replace(/(^\s+|\s+$)/ig, ''); iWidth = iWidth || 0; if( iWidth > 20 || iWidth < 1) return false; var aHexes = getHexes(sText, iWidth), sDivString=''; for (var i = 0; i < iWidth; i++){ sDivString += "<div style=\"width:8px;height:8px;float:left;background-image:url("+gifURL+");background-position-x:"+(8 * aHexes[i]) +"px\"></div>" } document.getElementById('BarCode_Field').innerHTML = sDivString; } var gifURL = "/upload/200742411119165.gif"; </script> </head> <body style="background-color:#000000; color:white"> <div style="float:left;"> <div style="float:left; width:70px; font-size:18px;line-height:25px; font-family:Arial"> Text: Width: </div> <div style="float:left;"> <input id="text" type="text" value="dknt没有任何含义" /> <input id="width" type="text" value="8"/></div> <div style="float:left;margin-left:20px"> <input type="button" value="Generate" onclick="GenerateBarCode()"/></div> </div> <div id="BarCode_Field" style="float:left;margin-left:20px"></div> </body>
大功告成。