产生跨平台的WBMP
--使用JavaBeans和JSP从XML数据动态的产生WBMP
Bilal Siddiqui (
wap_monster@yahoo.com)
CEO, WAP Monster
May 2001
WBMP (Wireless BitMap) 是WAP (Wireless Application Protocol)
规范的图像格式。 WML (Wireless Markup Language) 使用这个格式在 WAP
网站上显示图象。在这篇文章里,我们将讨论这个图象格式,并且通过 JSP 和 Java Beans 读取 XML 数据来产生 WBMP。我已经定义了一个 XML
结构来储存显示图像的数据。接下来,我们将使用 SAX 来解析XML数据,用 JavaBeans 来生成WBMP所需的字节流。最后,我们将设计一个 JSP
网页用它来生成一个内嵌了WBMP图象的WML 文件。
虽然 WBMP 是无线的图象格式,但它目前仅支持未压缩的黑白图象。称之为型态0 WBMPs.
在产生 WBMP 之前,让我们先看看它的格式。如 图1. 黑白的图象所示。我们将从 XML
的数据动态的生成它。
图1. 显示在手机上的黑白图象

WBMP 格式定义了一组八位位组(每一个这样的字节包含了8二进制数位 -- C++ 和 Java
程序设计师更熟悉它被称为 "字节")。如同一般的,WBMP 档案是一个二进制的文件, 我们将要处理的是单个的bits。所有的WBMP
文件在位于实际图象元素之前都有一个"Header" 标头部分,标头部分的第一个八位位组指明了WBMP的型态。因为目前只有型态0(黑白,非压缩)的 WBMP
格式被定义,第一个8个位组应该为零(意思是依顺序排列的8 个bits皆为0)。接下来的就是所谓的"固定的标头"部分,也应该全部为0。
下一个八位位组指出了图象的长度和宽度。宽是指图象的水平尺寸,用多字节整数格式表示,一个多字节整数由一个或多个字节构成。一个多位整数中,每一个字节的第一个bit将
告诉我们是否有更多的构成该多位整数的字节跟随在后面。如果该字节的第一个 bit 是0,意味着其后面没有更多的字节了,所以,将字节的第一个 bit
设为1意味着在着该多字节整数由多个字节构成。最有意义的 bits将被第一个传送。下面的范例说明了这个逻辑:
Width = 94 (decimal) pixels = 0x5E pixels = 01011110
(single-byte sequence)
Width = 134 (decimal) pixels = 0x86 pixels = 10000001
00000110 (multibyte sequence)
高度是图象的垂直尺寸,同样使用多字节格式表示。
接下来是图象数据。现在我们知道 WBMP 格式将根据标头部分设定的图象宽度来设定图象资料。举例来说,如果图象的宽度是 96
pixels,那么第一行(水平方向)将有十二个字节的图象资料(12 X 8 = 96 bits)。后面所有的字节将是每一组 12
个字节,每一个字节代表一行。如果图象的高度是 40 pixels,这里就应该有40 组这样的字节。 0 代表"灰" 或 "黑" pixel, 同时 1 代表
"白" pixel.
除此之外:如果图象的宽度不是8的倍数,每一行最后一个字节多出来的 bit 都会被设成 0。举例来说,如果图象的宽度是 99
pixels,那么每一行就必须有 13 个字节,每一行最后的那个字节的最后 5 个 bit 会被设为 0。
以下面的范例来说,参见Figure 2。改图是一个扩大的 3 x 3 pixels
图象。包含该图象的二进制的WBMP文件应该有一个以下的 bit 排列:
Octet 1: 00000000 (WBMP type)
Octet 2:
00000000 (Fixed header)
Octet 3: 00000011 (Width)
Octet 4: 00000011
(Height)
Octet 5: 01000000 (Row 1)
Octet 6: 10100000 (Row 2)
Octet
7: 01000000 (Row 3)
Figure 2. An example WBMP image file

清单1, 如下所示,展示了一个 WML 档案包含了一个单一的图象。我们使用 <img/>
元素在WML档案内,内嵌一个 WBMP 图象。稍后我们将透过 JSP 网页,产生一个相同的 WML 档案,并且将由 JavaBeans 来产生
WBMP。
清单1. A WML card that contains a WBMP image
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC
"-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card
id="menu">
<p>
<img
src="file:/g:/wirelessimages/graph.wbmp"
alt="image"/>
</p>
</card>
</wml>
透过 JavaBeans
产生 WBMP
我们现在将要写一个可重复使用的 Java 组件来产生 WBMP 图象。基本的构想是去写一个包含了可画出 WBMP
图象方法的 JavaBean。这个方法的例子包括画直线、画文字和画圆弧。在这个 Bean 里,我们将实现 low-level 功能,稍后,我们将在一个 SAX
parser 里使用这个 Bean 来根据 XML 的资料画出图象。如清单2提供了这样一个 JavaBean 的程序代码。
清单2. Low level JavaBean to produce images in WBMP
format
/*
* @(#)SAXParser.java
2001-03-15
* BS/tenco
*/
package
com.xml.wbmp;
import java.io.*;
import
java.awt.*;
import javax.swing.*;
public class
WirelessBitmap
{
// Private data members:
// Store
the dimensions of bitmap.
private int m_OriginalWidth,
m_height;
private int m_OctetWidth;
// Take a two dimensional
array. We will later (in the
// constructor) decide its
size.
private int BitMapDataArray[][];
// Public member
functions:
// Public constructor.
public WirelessBitmap(int
width, int height)
{
m_OriginalWidth =
width;
m_OctetWidth = (width%8 == 0) ? width
: width +
(8-(width%8));
m_height = height;
// Make dynamic allocation
of memory for array BitMapDataArray.
BitMapDataArray = new int
[m_height][m_OctetWidth];
//Initialize.
for (int row = 0; row <
m_height; row++)
for (int col = 0; col < m_OctetWidth;
col++)
BitMapDataArray[row][col] = 0;
}// WirelessBitmap()
// Public function for drawing lines.
// Draws a
line from point1 to point2.
public void drawLine (float point1x, float
point1y,
float point2x, float point2y)
{
// Draw the point
(point1x)(point1).
BitMapDataArray[(int)point1y-1][(int)point1x-1] =
1;
// If there was only one point to draw, return.
if
((point1x==point2x)&&(point1y==point2y)) return;
float slope, intercept; // store slope and
intercept.
// Check if there are more points to draw along x- or
y-axis.
// This check results in more accurate drawing.
if
(Math.abs(point2x -
point1x)>=Math.abs(point2y-point1y))
{
// Calculate slope
of line.
slope = (point1y - point2y) / (point2x - point1x);
// Calculate y-intercept.
intercept = (slope *
point2x) + point2y;
// We need to calculate the values of y for each
x
// from point1x to point2x, according to the formula:
// y =
slope * x - intercept.
// If point1 lies to the right of point2, we
should
// rather draw from point2x to point1x.
if
(point1x>point2x)
{
point1x+=point2x;
point2x=point1x-point2x;
point1x=point1x-point2x;
}//if
(point1x>point2x)
// Now run a loop from point1x to point2x.
for
(float count = point1x+1; count <= point2x; count++)
{
//
Check if this point is out of bounds.
// If so, bring it into the
boundary.
int y_coord = ((int)((int)(-(slope * (count)) + intercept))-1
);
if (y_coord<0) y_coord = 1;
if (y_coord>m_height)
y_coord = m_height;
BitMapDataArray[y_coord][(int)count-1] = 1;
}//
for
} //if
else
{
// Calculate slope of
line.
slope = (point1x - point2x) / (point2y - point1y);
// Calculate x-intercept.
intercept = (slope *
point2y) + point2x;
// We need to calculate the values of x for each
y
// from point1y to point2y, according to the formula:
// x =
slope * y - intercept.
// If point1 lies below point2, we
should
// rather draw from point2y to point1y.
if
(point1y>point2y)
{
point1y+=point2y;
point2y=point1y-point2y;
point1y=point1y-point2y;
}//if
(point1y>point2y)
// Now run a loop from point1y to point2y.
for
(float count = point1y+1; count <= point2y; count++)
{
//
Check if this point is out of bounds.
// If so, bring it into the
boundary.
int x_coord = ((int)((int)(-(slope * (count)) + intercept))-1
);
if (x_coord<0) x_coord = 1;
if
(x_coord>m_OriginalWidth) x_coord = m_OriginalWidth;
BitMapDataArray[(int)count-1][x_coord] = 1;
}//
for
}//else
}// drawLine
// Public function to write WBMP code to
file.
// Converts the present status of data present in
BitMapDataArray
// to WBMP format and writes it to
file.
public void writeWBMPCodeToFile()
{
// Hold the
data into a byte array.
byte tempByteArray[] = new byte[m_OctetWidth *
m_height];
int indexcounter = 0;
// Hold one byte of data.
// We shall later write
this data to tempByteArray[].
byte tempByte = 0;
for (int y =
0; y < m_height; y++)
{
for (int x = 0; x <
m_OctetWidth; x++)
{
if
(BitMapDataArray[y][x]==1)
{
// Find the correct position of
this bit.
// Then write it to its position in
tempByte.
tempByte = (byte)(tempByte | (1<<(7-(x%8)
)));
}
if ((x !=0) && ((x%8)==7))
{
//
tempByte is full, so write it to
tempByteArray.
tempByteArray[indexcounter++] = tempByte;
//
Reinitialize tempByte.
tempByte = 0;
}//if
}//for (int x = 0; x < m_OctetWidth; x++)
}//for (int y = 0; y < m_height; y++)
// Write
correctly formatted data to output file.
try{
FileOutputStream
output = new
FileOutputStream(
"g:\\wirelessimages\\graph.wbmp");
output.write((byte)0);//
WBMP type.
output.write((byte)0);// Fixed
header.
output.write((byte)m_OriginalWidth);//
Width.
output.write((byte)m_height);// Height.
//Image
data.
for (int i = 0; i<
indexcounter;i++)
{
output.write(tempByteArray[i]);
}
output.close();
}//try
catch(IOException
e){
System.out.println("Error in file
handdling");
}//catch
}// writeWBMPCodeToFile()
}//
class
让我们描述一下清单2 是如何运作的。WirelessBitmap
类包含一个存储图象数据的装置,当开始绘图时,将其中需要绘制的点的相应bit置为1 ,然后立即按照要求将这些图象数据转换成WBMP
格式。我们将直接解释这程序代码是怎么运作的而不拘泥于讨论详细的数据结构和算法。相信你可以很容易的理解这些简单的算法。
在清单1:的 WirelessBitmap class 有三个 私有成员变量,分别是: m_width、m_height 和
BitMapDataArray. 就像字面上的意思,前面两个变量代表 WBMP 图象的长和高
,第三个变量是一个二维的数组,用来保存图象数据。当在其它外部的程序或别的Java类中初始化WirelessBitmap bean时,m_width
和m_height 这两个变量的值将被传递给这个bean的构造函数。
我们在构造函数中将BitMapDataArray 数组的初始值置为 0,这相当于我们有一个全黑的图象。改数组的每一行代表
WBMP 图象的一个pixel,也就是图象数据中的一个bit。 。我们的目标是把该数组每一行的值表示成图象数据的每一行。
接下来是画线的子程序,就是在在点一和点二中画出一条线。我们使用四个 "float"
型的变量当参数。无疑它们是我们要画出的线的要点。
两点间直线最短。所以,为了在两点间画出一条直线,我们的工作是真实详细计算两点间最短的路径。我们将使用简单的几何学去达成这个目的。
这里我们将检查三个条件:
如果仅要画出一个点,画出它,然后返回。这个条件仅当点1x相当于点2x,并且点 1y 相当于点
2y时成立。
如果第一个条件不成立,就检验看看是否有更多的像素必须越过 X 轴和
Y轴。我们必须如此做,因为处理像素是不自然的。在另一方面,画出一条直线是固有的连续不断运作。如果我们适应我们的绘图算法,根据无论是否有更多的点在X轴和Y轴上,我们从第一个点到第二的点的图素将更近似实际的线段。对于这些你知道的简单分析几何学,在X轴上更多的点描绘出一段斜率小于一的线段。同样的,在Y轴上更多的点代表我们的线段斜率大于一。这显示在
Figure 3.如果我们有更多的点穿越X轴,这 "if" 条件(if (Math.abs(point2x -
point1x)>=Math.abs(point2y-point1y)) 得到运算的控制权。为了去计算两点间的绝对值,我们使用 java.lang 的
Math 对象的 abs() 方法,这保证了我们的算法将顺利的运作,无论点1位于点2的上下左右任何地方。
如果有更多的点越过Y轴(斜率大于1),"else" 部分将得到绘图运算的控制权。
Figure 3. Effect of slope on pixels along x- and
y-axes
在讨论完上面三个条件后,我们开始绘图运算。我们在 "if"
区块作的第一件事是去计算线段的斜率。线段的斜率是Y轴的差距除以X轴的差距(slope = (point1y - point2y) / (point2x -
point1x))。接下来,程序计算 y-intercept,线段在Y轴上的长度。方程式是 Y-intercept = (slope * point2x) +
point2y. 我们不要去证明这个方程式, 因为他们在基本的几何分析学中都可以找到。
我们将从点1x到点2x跑一个循环。为了这个目的。我们将确定点1x小于点2x;如果不是,便将两点交换。这个方法将使我们的程序运作正常,无论点1是位于点2的右边或左边。
一旦我们达到这个点,我们就得到所有点 1x 到点 2x 的 X 值了,并且计算每一点的 Y 值。这个计算是根据著名的直线方程 y
= slope times x + y-intercept. 你将注意到在程序的好几个地方有额外的 -1
﹛这是因为JAVA的数组起使值为0,不是1的结果)。
在计算了坐标轴的每一个点后,我们在BitMapDataArray 的元素中写入1。在发生在 "for" 循环从点1x
到点2x。
"else" 部分处理了在Y轴上有更多的图素。在这个例子里,我们交换X轴和Y轴的角色,并且使用相同的绘图几何学。这
getWBMPCode 子程序的工作是转换 BitmapDataArray 为 WBMP 格式。它一列一列的分析 BitmapDataArray,然后写入
bit-wise 到一个名为 tempByte 的暂存变量中。在每写8个 bits, 或一个八字节到 tempByte,就新增 tempByte
到一个数组。在结束时,他写入数组到 WBMP 档案。
Using XML data to draw WBMP
images
我们现在开始准备设计一个XML结构,根据这个结构编写内容、分析它,然后调用 WirelessBitmap class 去根据 XML
资料画出 WBMP 。来看看 XML 文件,在 清单3:
清单3. XML file representing tabular data
<table>
<tr>
<td>8</td><td>45</td>
</tr>
<tr>
<td>21</td><td>56</td>
</tr>
<tr>
<td>34</td><td>55</td>
</tr>
<tr>
<td>47</td><td>73</td>
</tr>
<tr>
<td>60</td><td>72</td>
</tr>
<tr>
<td>73</td><td>34</td>
</tr>
<tr>
<td>86</td><td>45</td>
</tr>
<tr>
<td>99</td><td>43</td>
</tr>
<tr>
<td>112</td><td>74</td>
</tr>
</table>
我们需要一个表格的型态去呈现资料。我们的目标是去拥有一个XML数据结构,必须拥有可以记载两个关连资料,让我们可以画出图形。
这样两个量的例子是一个星期的库存交换索引值倾向。在这个例子,我们可以有一个星期几的值,从1
(Monday)开始,第二个值是索引的值,参见为什么选择XML来存储数据?.
最容易的选择是使用大家熟知的<table>、<tr> 和 <td>
原件在XML里结构资料。这是我们在清单2. 做的。另一个选择是使用单一的组件 ,并且以 x、y参数储存表格资料。 清单4告诉我们如何做:
清单4. Alternate XML file to represent tabular
data
<table>
<entry x="8"
y="45"/>
<entry x="21" y="56"/>
<entry x="34"
y="55"/>
<entry x="47" y="73"/>
<entry x="60"
y="72"/>
<entry x="73" y="34"/>
<entry x="86"
y="45"/>
<entry x="99" y="43"/>
<entry x="112"
y="74"/>
</table>
现在,让我们来考虑一个可以解析在清单3中出现的XML文件的XML解析器,这样我们就可以使用WirelessBitmap类的简单的
绘图能力。为了达成这个目的,我们使用 SAX 解析器,让我们无论何时都能分析一个存在的XML文件并生成任何形式的输出。通常而言,SAX
解析器解析出的结果是客户端的文件,像是HTML、WML、XHTML、Style sheets
或客户端的scripts。但是我们现在要从SAX生成WBMP的图象。所以,在这个情况下,我们要从SAX产生二进制的文件。
我将使用 Sun's SAX 解析器,Java API 里的一个 XML Processing (JAXP)
包来进行演示。JAXP 包含了一个详细的如何使用SAX parser 教学。(参阅参考资料.)
我们已经设计了一个 WirelessBitmap class ,它能够根据 WBMP 画出一条直线并且将把WBMP
档案形式的结果存到server 上指定位置。所以我们的任务是去使用 SAX 解析器 来分析 XML ,产生正确的资料格式,传入 WirelessBitmap
class 中。
SAX 解析器对 XML 档案作分析。我们将用一个 在清单5,parser class 的 public 方法
parseFile(),首先产生一个新的 SAXParserFactory ,在这个 factory 创造一个新的 parser,将我们的 XML
档案传入。这个 saxParser.parse 子程序是值得我们去看的。我们传入 "this" 来当作这个 parser 的第二个参数。这意味着分析这个 XML
档案时,这个 parser 将传递控制权给 SAX 事件 (parser class 的程序代码在清单5.)
为什么选择XML来存储数据?
XML (eXtensible Markup
Language) 是一种开放式的结构,它正逐步流行于应用之间交换文档和数据。 在现实世界,尤其是商业领域中的应用将依据从不同来源汇聚的数据生成WBMP的图象。
举个例子,假设一个金融顾问将为一个Web站点收集各个不同股票市场数据库中的数据。XML
将是一个极好的开发此应用的方案。因为对于这种应用而言,那些XML格式的数据将已经是可用的了。在这,我们已经 用它来产生WBMP了。
现在让我们来看看 清单5.
清单5. JavaBean that parses XML data and uses
WirelessBitmap class to draw a WBMP image
/*
* @(#)parser.java 2001-03-20
*
BS/tenco
*/
package com.xml.wbmp;
import
java.util.*;
import java.io.*;
import
org.xml.sax.*;
import
javax.xml.parsers.SAXParserFactory;
import
javax.xml.parsers.ParserConfigurationException;
import
javax.xml.parsers.SAXParser;
import
com.xml.wbmp.WirelessBitmap;
public class parser extends
HandlerBase
{
private String CurrentElement =
"";
private boolean First = false;
private boolean Second =
false;
private ArrayList x_List = new ArrayList();
private
ArrayList y_List = new ArrayList();
private String temp_x =
"";
private String temp_y = "";
private WirelessBitmap
wirelessbitmap;
public void parser(){}
public void parseFile()
{
First =
false;
Second = false;
// Use the default (non-validating)
parser
SAXParserFactory factory =
SAXParserFactory.newInstance();
try
{
SAXParser
saxParser = factory.newSAXParser();
saxParser.parse( new
File("..\\webapps\\examples\\xml_files\\table.xml"),
this
);
}//try
catch (Throwable
t)
{
t.printStackTrace
();
}//catch
}//parseFile
public void drawGraph()
{
wirelessbitmap
= new WirelessBitmap(120,90);//size of
WBMP
wirelessbitmap.drawLine(8,8,8,82);//y-axis
wirelessbitmap.drawLine(8,82,112,82);//x-axis
for
(int k = 0; k < x_List.size()-1;
k++)
wirelessbitmap.drawLine(
Integer.parseInt((String)x_List.get(k)),
(82-Integer.parseInt((String)y_List.get(k))),
Integer.parseInt((String)x_List.get(k+1)),
(82-Integer.parseInt((String)y_List.get(k+1)))
);
wirelessbitmap.writeWBMPCodeToFile();
}//drawGraph
//====================================================
//
SAX DocumentHandler
methods
//====================================================
public void startElement (String name, AttributeList
attrs)
throws SAXException
{
CurrentElement =
name;
if (name=="tr")
{
First = true;
Second
= false;
}//if (name=="tr")
}// startElement
public void endElement (String name)
throws
SAXException
{
CurrentElement = "";
if
("tr"==name)
{
First=false;
Second=false;
x_List.add(temp_x);
y_List.add(temp_y);
}//if
("tr"==name)
if (name=="td")
{
if
((First)&&(!Second))
{
First=false;
Second=true;
}//if
(First)&&(!Second)
}//if (name=="td")
}//endElement
public void characters (char buf [], int offset, int
len)
throws SAXException
{
String s = new String(buf,
offset, len);
if (CurrentElement == "td")
if (First &&
!Second)
temp_x = s;
else
temp_y =
s;
}//characters
}//parser
清单5显示这个 parser class
有多个私有数据成员。这些成员将协调工作从而使解析器执行正确的功能。第一个和第二个数据成员是布尔型 变量。ParseFile() 方法初始化它们的值为
false。当分析开始,根据连续读入的XML档案,控制权交给 SAX 事件处理器。举例来说,如果 Linting 2 的 XML
档案被分析,接下来将发生以下连续事件 (我们的parser class只使用三个事件处理机制,分别名为 startElement, endElement, 和
characters; 还有其它一些SAX事件没有在这个程序使用。参考 JAXP 教学手册,在参考资料 有更详细的 SAX 事件)
startElement 得到控制权在名为"table"
startElement 得到控制权在名为"tr"
startElement 得到控制权在名为"td"
characters 得到控制权在buffer中为字符串8 (内容是<td>
组件)
endElement 得到控制权在名为"td"
以此类推...
所以,你已经知道了我们如何在三个事件中处理操作。记住这些事件被呼叫的顺序,一个 <tr> 开放组件设定"First"
为 true ,以及 "Second" 为 false. 这确保了<td>
组件的内容紧接下来的值为我们要画的图形的两个关连资料的第一个。
再来观察在"characters" 事件中发生了什么。这个事件处理只有当 CurrentElement 是 <td>
时才被操作,因为所有我们的资料都在<td>、</td> 这对组件中。在这个"if (CurrentElement == "td")"
区域中,我们检查内容呼叫是否是从第一个或第二个量,并且各自的将他储存在 temp_x 或temp_y 中。
endElement 事件处理将完成两件工作:
如果是从</tr>元素呼叫 endElement,就将第一和第二设为 false,,这样就不会有任何资料被写入
WBMP ,直到我们找到另一个 <tr> 结束组件。
将各自的 temp_x 和 temp_y 的值输出到数组arrays x-List
和y_List中。
分析运作的结果是我们得到两个数组 x_List 和 y_List ,保存了正确的资料顺序。我们现在可以呼叫
WirelessBitmap class 的 drawLine 子程序,然后将数据传入。这就是我们在 parser class 的drawGraph()
子程序所做的。DrawGraph 是一个简单的子程序,可以从 x-List 开始到 y_List 结束跑一个循环,在分析它到 WirelessBitmap
class 之前,使用 Integer class 去分析"String" 到"int"。
下一步是去设计一个 JSP 页面去调用在 清单5,中的 bean,生成WBMP 图象并将其内嵌到一个WML页面 ,并且传送到
WAP 使用者端。清单6告诉你作法。
清单6. A JSP page that prepares a WML deck and embeds WBMP
image into it
<%@ page
language="java"
contentType="text/vnd.wap.wml"
%>
<jsp:useBean id="todaysmenu"
scope="page"
class="com.xml.wbmp.parser">
</jsp:useBean>
<?xml version="1.0"?>
<!DOCTYPE wml
PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card
id="menu">
<p>
<%todaysmenu.parseFile();%>
<%todaysmenu.drawGraph();%>
<img
src="file:/g:/wirelessimages/graph.wbmp"
alt="image"/>
</p>
</card>
</wml>
清单6 是一个简单的 JSP页面,它从清单1中生成WML文件。这个WML文件只包含了一个组件,就是一个 WBMP
图象,再也没有其它的。在清单6接下来的几点是值得注意的:
ContentType 属性必须为"text/vnd.wap.wml"。
这jsp:useBean tag
被用来import com.xml.wbmp.parser class of 清单 5
一些改进和用户化的建议
我们已经展示了WBMP 格式和一个可以从XML资料产生
WBMP 文件的机制。这篇文章的内容有一般的用途。可重用的 beans 以及算法可被用来在分布式或标准的应用程序里来产生 WBMP 。
真实世界中的应用可以采取下面一些定制和改进:
我们使用Nokia WAP Tookkit 2 (参阅 参考资料) 和它们的蓝牙手机装置(Nokia 声称是符合WAP 1.2
标准的)来测试我们文章中的代码。 我们可以定制和增强这些代码来产生最优化的图象以针对不同屏幕的WAP兼容的蜂窝式移动手机。
在图形中没有文本。
用一个数组来表示WBMP数据,这使得您可以将文本字体存储在
一个与之相似的数据结构中,并可以将需要的文本从中拷贝到主数组中。
XML数据可以直接应用在制图函数中而不需要任何比例缩放。而要在WirelessBitmap类中加入一些“规格化”
的特性也并非难事,这使得我们可以在更高的抽象层次进行比例缩放。
我们将主数组初始化为0,然后在需要制图的地方,仅仅将这些象素设置为1。这样就可以在在黑色上用白色制图。
在本文中,我们在相关的class中将XML和WBMP文件硬编码了。在我们的实际应用中,XML流将可以从其他的程序中读入。
(大部分情况下是从DOM中)。参看JAXP教程 参考资料).同样,这些文件可以很好的从JSP 文件中获得。
感兴趣的读者可以尝试增加一个结构例外处理功能。
我们已经将清单5中画图函数的输出图象的风格硬编码了。我们可以增强这个功能从而可以从一个更高层次上来定制我们的图象风格。就像JSP的不同输出一样。
总结
如果一切顺利的话,你现在已经了解了WBMP
格式、算法以及如何运用它们画出WBMP图形。我们遵循将简单功能封装在一个 class
中,并且在一个较高的层次中使用它的惯例。这允许我们去设计一个JavaBean,跟 SAX 一起工作,读取 XML 资料,并且让 WBMP
绘图功能成为一个服务。我们也设计一个 JSP 页面去产生一个WML文件使它在手机上显示我们的WBMP图形。
参考资料
关于作者
Bilal Siddiqui
是XML方面的顾问。自1995年从拉合尔的工程技术大学电子工程专业毕业后,他开始从事工业控制系统方面的软件解决方案设计。后来他转向XML领域,运用
他在C++方面丰富的编程经验编写了一些Web-和基于WAP的XML处理工具,服务器端解析方案以及服务应用程序。可以通过wap_monster@yahoo.com于他联系。
如果您希望与本文章的作者或其所在机构,进一步交流,请联系:畅享网 姜小姐
jill.jiang@amt.com.cn | 021-51096826-112 |
在线联系