用AGG实现高质量图形输出(上)AGG是一个开源、高效的跨平台2D图形库。AGG的功能与GDI+的功能非常类似,但提供了比GDI+更灵活的编程接口,其产生的图形的质量也非常高(自称超过GDI+)使用前AGG的准备工作1.下载AGG库,它的家在,目前最高版本是AGG2.52.解压,后面以[AGG]表示AGG的解压目录.3.把[AGG]\include加入到include搜索目录中4.把[AGG]\src里所有cpp加入到项目中(或者用makefile一起编译)5.另外,AGG还有一些其它组件,用到时也要把它们(都是些.h和.cpp文件)加入项目:o如果要用AGG的控件和窗体,要加入[AGG]\src\ctrl\*.cpp和[AGG]\src\platform\OS\*.cpp,头文件在[AGG]\include\ctrl和[AGG]\include\platform里o如果要用到TrueType字体显示,要加入[AGG]\font_win32_tt目录下的源码和头文件。利用freetype库,则是[AGG]\font_freetype目录。o如果要用到GenericPolygonClipper库(一个区域剪裁计算库),加入[AGG]\gpc目录下的源码和头文件。AGG图形显示原理见下图:其中:1.VertexSource顶点源,里面存放了一堆2D顶点以及对应的命令,如MoveTo、LineTo等。2.Coordinateconversionpipeline坐标转换管道,它可以变换VertexSource中的顶点,比如矩阵变换,轮廓提取,转换为虚线等。3.ScanlineRasterizer把顶点数据(矢量数据)转换成一组水平扫描线,扫描线由一组线段(Span)组成,线段(Span)包含了起始位置、长度和覆盖率(可以理解为透明度)信息。AGG的抗锯齿(Anti-Aliasing)功能也是在这时引入的。4.Renderers渲染器,渲染扫描线(Scanline)中的线段(Span),最简单的就是为Span提供单一颜色,复杂的有多种颜色(如渐变)、使用图像数据、Pattern等。5.RenderingBuffer用于存放像素点阵数据的内存块,这里是最终形成的图像数据。要理解AGG的工作原理,先看一段代码:1.#includeagg_basics.h2.#includeagg_rendering_buffer.h3.#includeagg_rasterizer_scanline_aa.h4.#includeagg_scanline_u.h5.#includeagg_renderer_scanline.h6.#includeagg_pixfmt_rgb.h7.#includeplatform/agg_platform_support.h8.#includeagg_ellipse.h9.#includeagg_conv_contour.h10.#includeagg_conv_stroke.h11.12.classthe_application:publicagg::platform_support13.{14.public:15.the_application(agg::pix_format_eformat,boolflip_y):16.agg::platform_support(format,flip_y)17.{18.}19.20.virtualvoidon_draw()21.{22.//RenderingBuffer23.agg::rendering_buffer&rbuf=rbuf_window();24.agg::pixfmt_bgr24pixf(rbuf);25.26.//Renderers27.typedefagg::renderer_baseagg::pixfmt_bgr24renderer_base_type;28.renderer_base_typerenb(pixf);29.30.typedefagg::renderer_scanline_aa_solidrenderer_base_typerenderer_scanline_type;31.renderer_scanline_typerensl(renb);32.33.//VertexSource34.agg::ellipseell(100,100,50,50);35.36.//Coordinateconversionpipeline37.typedefagg::conv_contouragg::ellipseell_cc_type;38.ell_cc_typeccell(ell);39.40.typedefagg::conv_strokeell_cc_typeell_cc_cs_type;41.ell_cc_cs_typecsccell(ccell);42.43.//ScanlineRasterizer44.agg::rasterizer_scanline_aaras;45.agg::scanline_u8sl;46.47.//Draw48.renb.clear(agg::rgba8(255,255,255));49.for(inti=0;i5;i++)50.{51.ccell.width(i*20);52.ras.add_path(csccell);53.rensl.color(agg::rgba8(0,0,i*50));54.agg::render_scanlines(ras,sl,rensl);55.}56.}57.};58.59.intagg_main(intargc,char*argv[])60.{61.the_applicationapp(agg::pix_format_bgr24,false);62.app.caption(AGGExample.Anti-AliasingDemo);63.64.if(app.init(600,400,agg::window_resize))65.{66.returnapp.run();67.}68.return-1;69.}编译这段代码的方法是(以VC为例):1.新建空白GUI项目(就是有WinMain的项目)2.把[AGG]\src里所有*.cpp加入到项目中3.把[AGG]\src\platform\Win32\*.cpp加入到项目中4.Ctrl+C/Ctrl+V上面的代码5.编译!显示效果:我们先不管agg_main及agg::platform_support的问题,实际上agg::platform_support只是AGG给我们方便显示AGG图形用的,真正应用时几乎不会用到(后面会讲到怎样把AGG图形画到HDC上)。现在我们只需要知道这个框架可以生成一个窗体,当窗体重画时会调用virtualvoidon_draw()就行了。现在直接从on_draw()开始看1.通过rbuf_window()方法得到一个agg::rendering_buffer,它就是“RenderingBuffer”,是一块用于存放图像的内存块。通过pixfmt_bgr24包装,我们就可以以像素为单位存取图像。2.agg::renderer_base和agg::renderer_scanline_aa_solid都属于渲染器Renderer。renderer_base为底层渲染器,它支撑起所有的高层渲染器。这里的renderer_scanline_aa_solid就是一个高层渲染器。3.agg::ellipse是“顶点源VertexSource”,这个顶点源呈现的是一个圆形。4.agg::conv_contour和agg::conv_stroke作为“坐标转换管道Coordinateconversionpipeline”,conv_contour扩展轮廓线,conv_stroke只显示轮廓线(如果没有conv_stroke就会显示实心圆,可以去掉试试)。5.agg::rasterizer_scanline_aa就是“ScanlineRasterizer”啦。6.agg::render_scanlines函数执行这个AGG工作流程。用AGG实现高质量图形输出(二)本文上接《用AGG实现高质量图形输出(一)》,分别介绍了AGG显示流程中的各个环节。顶点源(VertexSource)顶点源是一种可以产生多边形所需要的“带命令的顶点”的对象。比如三角形顶点源,就应该会产生一个带“MoveTo”命令的点,另外二个带LineTo命令的点和最终闭合的“ClosePoly”命令。头文件#includeagg_path_storage.h//path_storage#includeagg_ellipse.h//ellipse#includeagg_arc.h//arc#includeagg_arrowhead.h//arrowhead#includeagg_curves.h//curve3,curve4#includeagg_gsv_text.h//gsv_text,gsv_text_outline#includeagg_rounded_rect.h//rounded_rect...类型自定义类所有实现了voidrewind(unsignedpath_id);和unsignedvertex(double*x,double*y);的类。ellipse圆,输入为中心点坐标和XY轴半径,本文所用的例子就使用了这个顶点源arc弧线,输入为中心点坐标和XY轴半径,以及起始和终止角(rad),顺时针/逆时针方向curve3贝塞尔曲线,输入为起点坐标、第一控制点坐标、终点点坐标curve4贝塞尔曲线,输入为起点坐标、第一控制点坐标、第二控制点坐标、终点坐标gsv_text使用AGG自带字模的文字输出(只支持ASCII码),使用start_point方法指定文字位置,text方法指定文字,flip指定是否上下倒转,size指定文字大小,适合与conv_stroke或gsv_text_outline配合。gsv_text_outline可变换文字,输入为gsv_text和变换矩阵(默认为trans_affine,后文会提到)。width方法设置文字宽度rounded_rect圆角方形,输入为左上角右下角坐标和圆角半径path_storage路径存储器,可以用join_path方法加入多个顶点源。而且path_storage本身支持move_to,line_to,curve和arc_to等画线功能arrowhead箭头,它是作为标记点来用的其中的arrowhead颇为特殊,它一般作为线段的标记点,具体用法是这样的:arrowheadah;ah.head(d1,d2,d3,d4);//定义箭头ah.tail(d1,d2,d3,d4);//定义箭尾VertexSourceVS;//其它顶点源//使用顶点转换器,并指定Markers类型为vcgen_markers_term//顶点转换器可以是conv_dash、conv_stroke或conv_marker_adaptor,见后文《坐标转换管道》//vcgen_markers_term:以端点作为标记点conv_strokeVertexSource,vcgen_markers_termcsVS(VS);...draw_term//用conv_marker指定ah作为线段marker点的标记conv_markervcgen_markers_term,arrowheadarrow(csVS.markers(),ah);ras.add_path(csVS);ras.add_path(arrow);//marker要紧随其后加入...renderah.head()和ah.tail()方法中的d1,d2,d3