| 文章索引 |
|---|
| 客户端与服务器端的SVG |
| 服务器端的SVG |
| 所有页面 |
服务器端
首先,我们需要在 Graphics2D环境中绘制实际图像的Java代码,读者可以参阅Artist.java的资料(http://www.xml.com/2002/02/27/examples/Artist.java),里边没有什么特别的,它只是一些draw和fill调用。唯一需要注意的是constructor,它要求一个宽、高、调色板(其值可能是BRIGHT或PASTEL)参数:
现在再回到servlet上,我们将在doPost方法中完成所有的工作。我们首先发送头部信息,以阻止结果被缓冲:
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
Artist mondrian = null;
try
{
response.setHeader("Cache-Control",
"no-cache, no-store, must-revalidate");
response.setHeader("Cache-Control",
"post-check=0, pre-check=0");
String agent =
request.getHeader("User-Agent").toLowerCase();
/* netscape chokes on Pragma no-cache so only
send it to explorer */
if (agent.indexOf("explorer") > -1){
response.setHeader("Pragma", "no-cache");
}
response.setHeader("Expires",
"Thu, 01 Dec 1994 16:00:00 GMT");
String colorScheme = request.getParameter( "scheme" );
String imgType = request.getParameter( "imgType" );
Artist mondrian = null;
int width;
int height;
int palette;
if (picType.equals("landscape"))
{
width = 400;
height = 300;
}
else if (picType.equals("portrait"))
{
width = 200;
height = 300;
}
else
{
width = 250;
height = 250;
}
palette = (colorScheme.equals("bright")) ?
Artist.BRIGHT : Artist.PASTEL;
mondrian = new Artist( width, height, palette );
一旦这些设定完成后,我们需要创建一个SVG文档和SVG图形环境。由于每个解析器的实现有其自身的一套存储对象的方法,我们必须请求 SVGDOMImplementation类给出详细情况。一旦知道了详细资料,我们就可以请求解析器实现创建一个带有合适名字空间的文档。 createDocument的第三个参数是为文档定义的一系列实体的引用。由于在本例没有为文档定义的实体,因此这一参数为 NULL。
SVGDOMImplementation.getDOMImplementation();
String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
Document document =
domImpl.createDocument(svgNS, "svg", null);
接下来我们创建SVGGraphics2D对象,并将它与它将创建创建的文档进行关联,然后将图象环境设置为期望的宽、高值和填充的像素。
svgGraphicsEnvironment.setSVGCanvasSize(
new Dimension( width + 10, height + 10 )
);
OK,现在所有的准备工作都已经完成,可以让艺术家在图形环境中开始绘制图画了,系统会自动地建立相应的SVG文档。
现在的文档仍然是存储在内存中的,但仍然需要将它以文本的格式返回给客户端,我们可以通过对文档进行串行化处理为一个 ByteArrayOutputStream对象,在初始化时它的大小为8192个字节,对于大多数的图画产生的文档而言,这一大小已经足够了。流式化的第二个参数被设置为"TRUE",这表示输出应当采用CSS样式而不是样式属性。
Writer svgOutput = new OutputStreamWriter( baos, "UTF-8" );
svgGraphicsEnvironment.stream( svgOutput, true );
现在我们决定是否需要返回一个返回一个SVG、JPEG或PNG格式的图像。客户端已经向我们表明它是否支持SVG,有关PNG支持的信息在HTTP请求的Accept头部中。我们获得SVG输出的字节矩阵,并将它转换为一个字符串,传递给一个合适的表达函数。
{
emitSVG( request, response, baos.toString() );
}
else
{
if (request.getHeader("Accept").indexOf("png") >= 0)
{
emitPNG( request, response, baos.toString() );
}
else
{
emitJPG( request, response, baos.toString() );
}
}
doPost方法的其余部分是错误捕捉功能,无论发生什么样的错误,我们都将向客户端发送一个带有错误信息的HTML网页。
{
PrintWriter out = response.getWriter();
response.setContentType("text/html");
out.println("<?xml version="1.0" encoding="utf-8"?>");
out.println("<!DOCTYPE");
out.println("html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"");
out.println("\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">");
out.println("<html><head><title>Error</title></head>");
out.println("<body>");
out.println("<p>Unable to create painting.</p>");
out.println("<pre>");
e.printStackTrace(out);
out.println("</pre>");
out.println("</body></html>");
}
发送的方法有三种,其中emitSVG比较简单。我们只需将带有适当的MIME类型的字符串发送回客户端即可:
HttpServletResponse response,
String svgString )
{
response.setContentType( "image/svg+xml" );
try {
response.getWriter().write( svgString );
response.getWriter().flush();
}
catch (Exception e)
{
e.printStackTrace();
}
}
译码
要向客户端发回一个JPEG或PNG文件,我们就必须使用Batik的transcoder,transcoder的输入可以是一个文档、流或一个阅读器,输出可以是一个URI、流或收书写器。对于JPEG译码器而言,我们可以通过调用addTranscodingHint方法来设置图像的质量。由于我们向客户端发送的是一连串的字节而不是一个字符串,因此我们的输出内容是输出到response.getOutputStream()而不是 response.getWriter()。
HttpServletResponse response, String svgString )
{
response.setContentType("image/jpeg");
JPEGTranscoder t = new JPEGTranscoder();
t.addTranscodingHint(JPEGTranscoder.KEY_QUALITY,
new Float(.8));
TranscoderInput input =
new TranscoderInput( new StringReader(svgString) );
try {
TranscoderOutput output =
new TranscoderOutput(response.getOutputStream());
t.transcode(input, output);
response.getOutputStream().close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
发送PNG输出的代码与此相似。如果想让透明的象素点转换为白色的象素,我们可以使用KEY_FORCE_TRANSPARENT_WHITE参数,对于不支持PNG格式的透明度的老浏览器而言,这一点十分有用。
HttpServletResponse response, String svgString )
{
response.setContentType("image/png");
PNGTranscoder t = new PNGTranscoder();
TranscoderInput input =
new TranscoderInput( new StringReader(svgString) );
try {
TranscoderOutput output =
new TranscoderOutput(response.getOutputStream());
t.transcode(input, output);
response.getOutputStream().close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
我们可以将整个servlet集成为一个文件。如果在一个合适的 servlet容器(例如Jakarta Tomcat)中安装Artist和Artmaker,就可以绘制如下所示的图像了。

总结
我们在本篇文章中没有讨论的其他Batik工具可以将TrueType字体转换为SVG格式,对SVG进行扩展,使其包括自定义的标记。如果读者需要一个能够开发浏览、建立、转换SVG文档的功能强大、跨平台的开发工具,那就非Batik莫属了。
(THE END)