手把手教你做超酷的条形码效果
声明:
-
这篇文章教你在web页面上实现条形码效果,体现的是利用网页制作技术综合解决问题的思路。旨在使对HTML, JavaScript,PhotoShop具有入门级水平的人巩固入门级水平。
若有问题不能及时回复,麻烦请担待,不胜感激。
高手免进。
制作条形码总共分几步?
第一步,把冰箱门儿打开——使用PhotoShop绘制小图片
我们需要制作出一个含有16个元素的条形码图片。
首先打开Photoshop,本篇教程中使用的是CS 简体中文 版本,仅就本教程所涉及的方面来看,操作都大同小异,只要认真阅读,应该不会遇到问题。
打开以后首先按Ctrl N,建一个 8像素 X 8像素的图片,背景选择透明,如图所示:
为了看清楚,可以把图片缩放到最大 1600%。
按一下D,再按一下X,确保前景色为白色背景色为黑色。
使用Ctrl Delele,填充背景色,黑色。
使用铅笔笔工具,参数做如下设置:
刻画线条,隔一列画一个。画成下面这种效果:
将图层1拖动到下面的新建按钮上复制一下:
选择 图层1 副本,将左边第一道白色用铅笔工具涂成黑色(可以按 X 将前景色变成黑色)。如下图所示:
选择 图层1 ,按Ctrl A,再按 Ctrl C,然后选择菜单命令图像=画布大小, 将宽度调整为16个像素,点中 定位 的最左边中间的小块,如下图所示:
选择 图层1 副本。按住Ctrl键,左键单击图层面板上的 图层1 副本 条目以选择 图层1 副本 的选区。按Ctrl Shift I 反选(这一系列也可以用魔术棒操作,选择透明部分就可以了)。按Ctrl V 粘贴成 图层2。
关闭 图层1 和 图层1 副本 的可见性(左键点击小眼睛图标),选择图层2,将左边第二道白色用铅笔工具涂成黑色。如下图所示:
打开 图层1副本 的可见性,确保选择了图层2,按Ctrl E 向下合并。
打开 图层1 的可见性,按住Ctrl键,左键单击图层面板上的 图层1 条目以选择 图层1 的选区。复制并扩大画布,按前面所述的方法继续绘制。在宽度为24,32的时候再做两次,分别把 图层1 模式(pattern)的第三和第四条白色涂成黑色。最后的结果如下图所示:
接下来还需要拓宽,方法是一样的,只不过这次的模式变换的方案是把相邻两个白色之间的黑色涂成白色。比如第五次拓展,其模式是这个样子:
再做几次后,等宽度为 64 时,画布看起来应该是这个样子的:
接下来仍然需要拓宽,思想是删掉相邻两个白色条(注意,可以认为第4个白条和第一个白条是相邻的),于是再做4次的效果是这样的:
还差32个像素就完成了,还需再拓宽,这次是填充两个相邻黑色条为白色条,最后效果如下:
图层1 可以不要了,删掉即可。
接下来我们要去掉黑色的部分,使其透明。使用魔棒工具,将选项做如下设置:
选择以后,按delete键删除,则整个画布变成如下形式:
似乎乱七八糟,是PS对透明背景表达的问题,只要保证步骤对了,做成这个效果就行了。
大功告成选择文件 -- 另存为,类型选择为 gif, 可以起名叫 barcode.gif,在下下面的对话框中,透明这一项一定要选中。 找个合适的地方放好。
于是冰箱门打开了,如果你做出的不是这个样子,用我这个做好的就行了,免得大象装不进去。
第二步,把大象装进去——代码分析
我们的目标是把一个字符串转化为一个条形码显示在页面上。那么一个字符串如何对应出一个条形码呢?上面做个128X8的图片到底是要扯什么蛋?
我们可以考虑数据在存储器中的最基本储存单位——字节(byte) 一个字节是八位(bit)。一个8位二进制数可以通过一个2位的十六进制数表示,表示为 00 - FF。刚才提到了一个16,注意到了吗?
如何把一个字符串转换成字节表示呢?似乎不能直接表示,但是J(ava)script 中的字符串有一个charCodeAt()方法。我们知道单字节若表示整数,其范围是 0 -255,双字节若表
示正整数,范围是 0 - 65535。charCodeAt()方法返回的是一个字符的Unicode表示,这种Unicode方案中,中文是两个字节的,英文是一个字节的。所以对于一个英文字符它总是返回0 - 255 之间的正整数,对于一个中文字符,它总是返回 255 - 65535 之间的正整数(非精确范围)。
再讲一下位运算的知识吧,节选自微软的Jscript脚本参考手册:
对于与运算。 &运算符查看两个表达式的二进制表示法的值,并执行按位“与”操作。该操作的结果如下所示:
0101 (expression1)
1100 (expression2)
----
0100 (result)
任何时候,只要两个表达式的某位都为 1,则结果的该位为 1。否则,结果的该位为 0。
对于移位运算,比如右移运算。expression1 >> expression2 中,>> 运算符 把 expression1 的所有位向右移 expression2 指定的位数。expression1 的符号位被用来填充右移后左边空出来的位。向右移出的位被丢弃。例如,下面的代码被求值后,temp 的值是 -4:-14 (即二进制的 11110010)右移两位等于 -4 (即二进制的 11111100)。
var temp
temp = -14 >> 2注:32位整数类型的数据有符号位的问题,对于负数,填充位为1,正数为0。我们通过charCodeAt()得到的数都是正数,所以不用管这个问题。
对于一个8位二进制数,与二进制 11110000 相与,再右移4位,则可以得到它的最左四位。
直接与 1111 相与,则可以得到他的右边四位。
准备知识了解这么多够了,下面让我开始实践编码。
说,要有一个字符串,于是就有了个字符串。
var strTest = "dknt没有任何含义";
我们就是要把这个字符串转化为一个条形码。
我们要获得它的二进制表示,那我们就建一个函数来获得它的二进制表示。比如 getBinary();
如:
运行代码框
[Ctrl A 全部选择 提示:你可先修改部分代码,再按运行]
为了获得二进制表示,我们要一个字符一个字符的进行,不能着急,首先要获得每个字符对应的Unicode编码。
运行代码框
[Ctrl A 全部选择 提示:你可先修改部分代码,再按运行]
大于 255 的显然是占用两个字节的字符。要想办法分成单一字节的两个数据,以使程序流易于自动化一些。可以使用双字节数值与 二进制 1111111100000000 相与再右移8位来获得第一个字节。直接与11111111相与就可以得到第二个字节的数据。使用十六进制数可能更方便一点。1111111100000000 的十六进制表示为 FF00。11111111显然就是 FF了。
J(ava)script中,用0x前缀表示十六进制数。我们可以实践一下下面的代码。
运行代码框
[Ctrl A 全部选择 提示:你可先修改部分代码,再按运行]
可以看到现在每个数都是小于255的了。
注意,(iDecimalUnicode & 0xFF00) >> 8 中,>> 的优先级比 & 高,所以按照我们的目的,(iDecimalUnicode & 0xFF00) 一定要有括号。
我们希望能有个统一的处理逻辑,把每个字节分成两部分,每个部分用十六进制的1位就可以表示,换句话说,就是每部分都是一个不超过16的十进制数。类似Ruby中的代码段数据类型,在J(ava)script中,也可以用匿名函数来实现类似的功能。我们可以建一个名为tmpOP变量来承接这个匿名函数,然后利用它来简化程序逻辑。此外,我们应该有个东西来储存分解出来的结果。那就用个result数组来装吧。另外按照语义,我们这个函数做的已经不仅仅是转化二进制了,而是转化成意义上的十六进制位了。我们应该是恨敏捷的,所以把函数名改成getHexes吧。
运行代码框
[Ctrl A 全部选择 提示:你可先修改部分代码,再按运行]
很高兴看到现在就弹出一个alert吧,刚才那么多alert是很闹心。我很抱歉。这次因为我们使用了alert一个数组,感觉整齐一点。
现在发现数组的每一个元素都是小于16了吧,很好,大象快装进去了。
有一个问题,我们不能把字符串的每个字符都转化成条形码,若是一个1万多字的文章怎么办,那不扯呢吗。所以我们要限制一下处理的字符数。以条形码的视点来看,似乎宽度应该是固定的,也就是说我们用以对应的 aResult 数组的长度应该是固定的。那也好办,在我们的 tmpOP 里控制一下就行了。我们可以假设我们只需要8个十六进制位来生成条形码。可以在getHexes里加一个 iMaxLength 参数来控制。
如下:
运行代码框
[Ctrl A 全部选择 提示:你可先修改部分代码,再按运行]
现在确实只有8个小于16的数了。
在 tmpOP 中,发现 aResult 数组的长度超过最大值,就返回一个0,外面发现这个0以后,就直接退出循环,因为没有必要再继续往下取字符了。
有些地方略显不妥,本着精益求精的精神,我们要把我们的程序效率提高提高。首先,我们知道了位相与的目的,就可以写一些更直接处理的代码,因为我们把处理双字节时,为了分成两个单字节,实际上多与运算了一次,和后面的分解双十六进制位有重复的位相与。说俗了就是多干了一次没用的事。不如一次就分解出4个十六进制位。
此外,我们总是向数组询问length属性来获知数组长度,要知道数组做这件事是很累的,反正我们也有条件自己心理有数,为什么还要总问它呢。
基于这两点,我们把程序改动如下:
运行代码框
[Ctrl A 全部选择 提示:你可先修改部分代码,再按运行]
看到了效果跟上一个是一样的,说明我们没改错。其中,aPos数组就可以储存掩码,数组的索引 X 4 就是需要右移的位数。tmpOP( iDecimalUnicode , i) 就表示取 iDecimalUnicode 从右边数第i个十六进制位(第0个就是最右边的1个十六进制位)。
大象是勉勉强强塞进去了,下面我们就把活做的利索点,把冰箱门儿带上。要不条形码还没露面,我们怎么收场?
第三步,把冰箱门儿带上——封装和测试用例
接下来的工作重点就是要把条形码做出来。为了测试效果,我们还需要一个用户界面。
皮之不存,毛之焉附,首先做一个界面。随便做一个普通页面就行了。然后在上面安放一个文本框,一个触发按钮,一个条形码显示区域。
运行代码框
[Ctrl A 全部选择 提示:你可先修改部分代码,再按运行]
我们需要把大象移植过来,加在我们的界面上,此外我们还需要让按钮能触发getHexes函数,那就加一个 onclick方法吧。
运行代码框
[Ctrl A 全部选择 提示:你可先修改部分代码,再按运行]
点击Generate按钮可以发现,我们之前的程序逻辑仍然生效。说明移植成功。
问题很大,getHexes始终操作的是一个固定的变量值,怎么让它能操作界面上的值呢?可以操作DOM来获取界面上的值。要使用DOM来操作,最简单的方法就是给所关注的元素上添加 id 属性。此外在 iWidth 这个变量在我们的界面中没有接口,看来是忘了,不过这个忘了很正常,当初根据我们的界面设计语义本来就没有这个内容。我们确实很敏捷,马上添加上去就行了。
运行代码框
[Ctrl A 全部选择 提示:你可先修改部分代码,再按运行]
注意,我们已经把 标签的
var strTest = "dknt没有任何含义";
var iWidth = 8;
两句去掉了。因为他们确实没有什么用了,我们已经不从那里获得数据了。
这回,如果你改动两个文本框中的文字,将会看到另外一组十六进制位。此外,我们觉得加一个对文本框的说明更好一些,所以就在前面加了个div.
现在我们发现似乎把一大串字符写在onlick里似乎有点不自然,如果将来逻辑更复杂了将很难维护,不如就单建个函数专门负责此事。它也可以包含更复杂的调度逻辑。此外,我们对两个文本框的类型没有验证,如果输入的不是我们想要的数据类型怎么办?所以还要加上判断逻辑。所以修改如下:
运行代码框
[Ctrl A 全部选择 提示:你可先修改部分代码,再按运行]
GenerateBarCode 要去掉text左右的空格,然后还要检查width是否是有效值(这里最大设为20,不过你可以随便改,太大似乎就有点变态了)。
然而我们的条形码还是没出来,但是我们已经恨厌倦alert了,这次一定要让getHexes返回一个数组给GenerateBarCode,然后让GenerateBarCode进行后续处理。
运行代码框
[Ctrl A 全部选择 提示:你可先修改部分代码,再按运行]
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的背景颜色。如下:
运行代码框
[Ctrl A 全部选择 提示:你可先修改部分代码,再按运行]
大功告成。
最后,给大家贴一个更完美一点的版本,不细述了。
运行代码框
[Ctrl A 全部选择 提示:你可先修改部分代码,再按运行]
其中修改了一些地方,以使得在Firefox也能显示。首先。Firefox只能识别标准的background-position属性,接受两个值,我们只要把第二个值设为0就可以了。
此外,SELECT对象添加option元素也有一点小区别。
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。
本文地址:/web/xinde/80052.html