logo资料库

AGG官网文档中文翻译.pdf

第1页 / 共78页
第2页 / 共78页
第3页 / 共78页
第4页 / 共78页
第5页 / 共78页
第6页 / 共78页
第7页 / 共78页
第8页 / 共78页
资料共78页,剩余部分请下载后查看
AGG 中文手册 1 渲染内存 Rendering Buffer 我们先从这里开始:在内存中开辟一块存储区,然后将它的内容以最简单的光栅格式写到文件中,也就 是 PPM(Portable Pixel Map)格式。虽然 Windows 对这种格式并没有原生的支持,但很多图像浏览器和 转换器都能使用这种格式,比如 IrfanView(www.irfanview.com)。所有 AGG 的控制台例子都使用了 P6 256 格式,也就是 RGB,每个字节代码一个颜色。现在假设我们将在下图所示的 RGB-buffer 内存区中工 作: 1.1 第一个简单例子 #include #include #include "agg_rendering_buffer.h" enum { frame_width = 320, frame_height = 200 }; // Writing the buffer to a .PPM file, assuming it has // RGB-structure, one byte per color component //-------------------------------------------------- bool write_ppm(const unsigned char* buf, unsigned width, unsigned height, const char* file_name) {
FILE* fd = fopen(file_name, "wb"); if(fd) { fprintf(fd, "P6 %d %d 255 ", width, height); fwrite(buf, 1, width * height * 3, fd); fclose(fd); return true; } return false; } // Draw a black frame around the rendering buffer, assuming it has // RGB-structure, one byte per color component //-------------------------------------------------- void draw_black_frame(agg::rendering_buffer& rbuf) { unsigned i; for(i = 0; i < rbuf.height(); ++i) { unsigned char* p = rbuf.row_ptr(i); *p++ = 0; *p++ = 0; *p++ = 0; p += (rbuf.width() - 2) * 3; *p++ = 0; *p++ = 0; *p++ = 0; } memset(rbuf.row_ptr(0), 0, rbuf.width() * 3); memset(rbuf.row_ptr(rbuf.height() - 1), 0, rbuf.width() * 3); } int main() { // In the first example we do the following: //-------------------- // Allocate the buffer. // Clear the buffer, for now "manually" // Create the rendering buffer object // Do something simple, draw a diagonal line // Write the buffer to agg_test.ppm // Free memory unsigned char* buffer = new unsigned char[frame_width * frame_height * 3]; memset(buffer, 255, frame_width * frame_height * 3);
agg::rendering_buffer rbuf(buffer, frame_width, frame_height, frame_width * 3); unsigned i; for(i = 0; i < rbuf.height()/2; ++i) { // Get the pointer to the beginning of the i-th row (Y-coordinate) // and shift it to the i-th position, that is, X-coordinate. //--------------- unsigned char* ptr = rbuf.row_ptr(i) + i * 3; // PutPixel, very sophisticated, huh? :) //------------- *ptr++ = 127; // R *ptr++ = 200; // G *ptr++ = 98; // B } draw_black_frame(rbuf); write_ppm(buffer, frame_width, frame_height, "agg_test.ppm"); delete [] buffer; return 0; } 在这个例子中,你甚至不需要链接任何的 AGG 的代码文件,你只需要在你的编译器命令行中设置好 AGG 的包含路径就行了。编译并运行它,你会看到现图所示的结果: 这个例子中几乎所有东西都“手工打制”的,使用的唯一一个现成的类是 rendering_buffer。这个类 本身并不知道关于内存中像素格式的任何信息,它只是保存了一个数组,数组中的元素分别指向每行(像
素的开头)。为申请和释放这块存储区是使用者的责任,你可以使用任何可行的方式来申请和释放内存, 比如使用系统提供的 API 函数,或是简单的用内存分配器(译注:应该是 new、delete、malloc、free 等), 甚至是直接使用一个静态数组。在上面这个例子中,因为每个像素要占用 3 个字节,所以我们申请了 width*height*3 字节的内存,在实际内存中是不存在“行”这种布局方式的,但这样做可以提高程序的性 能,而且有时候在使用 API 的时候需要。 1.2 Class rendering_buffer 包含文件: agg_rendering_buffer.h rendering_buffer 这个类保存了指向每一行像素的指针,基本上这个类做的事就是这些了。看起来 好像不是什么了不起的事,不过我们还是继续分析下去。这个类的接口和功能都很简单,它只是模板类 row_ptr_cache 的一个 typedef 而已: typedef row_ptr_cache rendering_buffer; row_prt_cache 这个类的接口的功能如下: template class row_ptr_cache { public: row_ptr_cache(); row_ptr_cache(T* buf, unsigned width, unsigned height, int stride); void attach(T* buf, unsigned width, unsigned height, int stride); T* buf(); const T* buf() const; unsigned width() const; unsigned height() const; int stride() const;
unsigned stride_abs() const; T* row_ptr(int, int y, unsigned); T* row_ptr(int y); const T* row_ptr(int y) const; row_data row (int y) const; T const* const* rows() const; template void copy_from(const RenBuf& src); void clear(T value) }; 这个类的实现里没有使用断言或是验证的措施,所以,使用者有责任在用这个类对象时正确地将它初 始化到实际的内存块中,这可以在构造函数中完成,也可以使用 attach() 函数。它们的参数解释如下:  buf — 指向内存块的指针。  width — 以像素为单位表示的图像宽度。rendering buffer(渲染内存区)并不知道像 素格式和每个像素在内存中大小等信息。这个值会直接存储在 m_width 这个成员变量中,使用 width() 函数就可以获取它的值。  height — 以像素为单位表示的图像高度(同样也是行数)  stride — Stride(大步幅,-_-; 不知道怎么翻了„„),也就是用类型 T 来度量的一 行的长度。 rendering_buffer 是一个 typedef,也就是 row_prt_cache,所以这个值是 以字节数来算的。Stride 决定内存中每一行的实现长度。如果这个值是负的,那么 Y 轴的方向就 是反过来的。也就是说 Y 等 0 的点是是内在块的最后一行的。Y == height - 1 则是第一行。 stride 的绝对值也很重要,因为它让你可以方便地操作内存中的“行”(就像 windows 中的 BMP)。另外,这个参数允许使用者可以像操作整个内存区块一样,操作其中任意一个“矩形”内 存区。 attach()函数会改变缓冲区或是它的参数,它自己会为“行指针”数组重新分配内存,所以你可以在任何 时候调用它。当(且仅当)新的 height 值比之前使用过的最大的 height 值还要大时,它才会重新申请内 存。 构造的这个对象的开销仅仅是初始化它的成员变量(设置为 0),attach()的开销则是分配 sizeof(ptr)*height 个字节的内存,然后将这些指针指向对应的“行”。
最常使用的函数是 row_prt(y),这个函数只是简单地返回指向第 y 函数指针,这个指针指向的位置已 经考虑到了 Y 轴的方向了。 注意: 渲染内存区(rendering buffer)并不管任何裁减或是边界检查的事,这是更高层的类的责任。 buf(), width(), height(), stride(), stride_abs() 这些函数的意义显而易见,就不解释了。 copy_from()函数会将其它内存的内容拷贝至“本”内存中。这个函数是安全的,如果(两者的)width 和 height 值不相同,那它会尽可能拷贝大一些的区域。一般来讲都用于拷贝相同大小区域。 1.3 Two Modifications of the Example 首先,在创建 rendering buffer 的对象时将 stride 取负值: agg::rendering_buffer rbuf(buffer, frame_width, frame_height, -frame_width * 3); 那么结果将变成这样: 然后,我们试下将 rendering buffer 附着(attach)到被分配的内存区的某部分。这个修改会使得 rendering buffer 两次附着在同一块内存区上,第一次是整个被分配的内存区域,第二次是其中的一部 分:
int main() { unsigned char* buffer = new unsigned char[frame_width * frame_height * 3]; memset(buffer, 255, frame_width * frame_height * 3); agg::rendering_buffer rbuf(buffer, frame_width, frame_height, frame_width * 3); // Draw the outer black frame //------------------------ draw_black_frame(rbuf); // Attach to the part of the buffer, // with 20 pixel margins at each side. rbuf.attach(buffer + frame_width * 3 * 20 + // initial Y-offset 3 * 20, // initial X-offset frame_width - 40, frame_height - 40, frame_width * 3 // Note that the stride // remains the same );
// Draw a diagonal line //------------------------ unsigned i; for(i = 0; i < rbuf.height()/2; ++i) { // Get the pointer to the beginning of the i-th row (Y-coordinate) // and shift it to the i-th position, that is, X-coordinate. //--------------- unsigned char* ptr = rbuf.row_ptr(i) + i * 3; // PutPixel, very sophisticated, huh? :) //------------- *ptr++ = 127; // R *ptr++ = 200; // G *ptr++ = 98; // B } // Draw the inner black frame //------------------------ draw_black_frame(rbuf); // Write to a file //------------------------ write_ppm(buffer, frame_width, frame_height, "agg_test.ppm"); delete [] buffer;
分享到:
收藏