graphics-libart.html

来自「linux下gnome编程」· HTML 代码 · 共 806 行 · 第 1/2 页

HTML
806
字号
><H2CLASS="SECT2"><ANAME="AEN854">Affine Transformations</A></H2><P>          Now that we have the basic building blocks of a vector          drawing kit, we need some way to move those vectors          around. At the very least, we should be able to move them          through space, or translate them. Another important feature          is scaling them to larger or smaller sizes, to simulate          zooming and unzooming.  Even more sophisticated is the          ability to rotate our lines and polygons. Finally, we might          like to be able to shear our vector paths-for example, to          turn a normal rectangle into a slanted parallelogram.        </P><P>          Libart implements these operations as affine transforms;          each transform is characterized by an array-or matrix-of six          floating-point numbers. To apply the affine transform on a          path, libart passes each coordinate pair through these two          operations, where x and y are the old coordinates, x' and y'          are the new coordinates, and affine0 through affine5 make up          the array of floating-point numbers:        </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">x' = affine0x + affine2y + affine4y' = affine1x + affine3y + affine5        </PRE></TD></TR></TABLE><P>          Surprisingly, these innocent-appearing little functions can          result in quite a number of dazzling effects, in particular          the four transforms already mentioned. By carefully          tweaking the affine matrix, we can invent many strange new          transforms. Of particular note is the simplicity of the          calculations. Affine transforms involve only multiplication          and addition, two fairly quick operations that are not          likely to bog down your rendering routines. You don't have          to worry about any complicated square roots or cubic          equations sneaking into your back-end algorithms.        </P><P>          The simplest transform of all is identity, which leaves all          points in the path unaltered. The identity looks like (1, 0,          0, 1, 0, 0) and simplifies to the following equations:        </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">x' = 1x + 0y + 0 = xy' = 0x + 1y + 0 = y        </PRE></TD></TR></TABLE><P>          A translation transform is a simple offset, which looks like          (1, 0, 0, 1, m, n), in which every point is moved m units          horizontally and n units vertically:        </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">x' = 1x + 0y + m = x + my' = 0x + 1y + n = y + n        </PRE></TD></TR></TABLE><P>          Scaling is similar to the identity transform, except it uses          values greater or less than 1 and looks like (m, 0, 0, n, 0,          0). Values greater than 1 will enlarge, or zoom in, and          values between 0 and 1 will shrink, or zoom out. Negative          values will flip the path to the opposite side of the axis,          which is not normally what you want, so you'll probably want          to keep your multipliers in the positive range:        </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">x' = mx + 0y + 0 = mxy' = Ox + ny + 0 = ny        </PRE></TD></TR></TABLE><P>          Rotation and shearing transforms are a little more complex,          and they usually involve some sort of trigonometry. To see          how they work, take a look at libart's implementation of          them. The source code is in the gnome-libs package in the          file gnome-libs/libart_lgpl/art_affine.c, located in the          art_affine_rotate( ) and art_affine_shear( ) functions. The          other mentioned transforms reside in art_affine_identity(          ), art_affine_translate( ), and art_affine_scale( ). You'll          find other interesting transforms in art_affine_invert( ),          art_affine_flip( ), and art_affine_point( ); you can compare          two transforms with art_affine_equal( ) and combine two          transforms with art_affine_multiply( ). If you use only one          thing in libart, it will most likely be the affine          transforms, so it's a good idea to figure out how they work.          They also pop up from time to time in the GNOME Canvas (see          Chapter 11).        </P><P>          Affine transformations have some very interesting properties          that make their simplicity even more attractive. First,          affines are linear, so they always transform straight lines          into straight lines; also, if two lines are parallel, they          will remain parallel after any number of transforms. Closed          paths will remain closed.        </P><P>          Another interesting property is that affine transforms are          cumulative. You can combine multiple transforms into a          single composite transform with art_affine_multiply( ), so          if you have a series of transformations that you always          perform in order, you can speed things up by combining them          into a single transform. The results will be exactly the          same. Note, however, that order is still important. If you          exchange steps 3 and 4 in a six-step series, you will very          likely come out with different results (depending on the          specifics of the transforms; obviously if steps 3 and 4 were          both identity transforms, it wouldn't matter).        </P><P>          Finally, affine transforms are mathematically          reversible. You can apply a transform, invert it with          art_affine_invert( ), and apply the inversion, and you will          end up with your original path (taking into account any          rounding errors).        </P></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN870">Pixel Buffers</A></H2><P>          One of the highlights of libart is its support for RGB and          RGBA (red-green-blue-alpha) pixel buffers, or pixbufs. All          of the various data constructs and algorithms come to          fruition in these buffers. You can draw lines and shapes on          the pixel buffer by creating an SVP (or by creating a vector          path and converting that into an SVP) and rendering it to          the pixbuf with a stroking operation. You can apply any          number of affine transforms on images to offset, scale, and          otherwise morph them. Libart also provides pixel buffer life          cycle management in the form of creation and destruction          functions.        </P><P>          Libart defines its own data structure, ArtPixBuf, to hold          the important elements:        </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">typedef struct _ArtPixBuf ArtPixBuf;struct _ArtPixBuf{  ArtPixFormat format;  int n_channels;  int has_alpha;  int bits_per_sample;  art_u8 *pixels;  int width;  int height;  int rowstride;  void *destroy_data;  ArtDestroyNotify destroy;};        </PRE></TD></TR></TABLE><P>          Most of the fields in ArtPixBuf should look familiar from          our discussions in the earlier parts of this chapter. Only a          few of them represent new concepts.        </P><P>          The format field holds the structural format of the pixel          buffer. For now, the ArtPixFormat enumeration allows only          one value, ART_PIX_RGB, signifying a three-or          four-channel RGB buffer. In the future, libart might support          other color formats, such as grayscale, CMYK          (cyan-magenta-yellow-black), and so on.        </P><P>          The n_channels field determines the number of color channels          the pixel buffer has. A three-color RGB buffer has three          channels; a three-color RGB pixel buffer with an alpha          channel has an n_channels of 4. All other values are invalid          for ART_PIX_RGB.        </P><P>          ArtPixBuf explicitly states whether or not one of its          channels is an alpha channel with the has_alpha          field. Although you can probably figure this out by looking          at n_channels, you should avoid doing so. Other pixbuf          formats may have a different number of base channels. For          example, grayscale might have one color channel and one          alpha channel, while CMYK might have four color channels and          one alpha channel. The has_alpha field is the only surefire          way to test for the presence of an alpha channel.        </P><P>          The bits_per_sample field is another way of expressing the          color depth of the pixel buffer. A sample is analogous to a          color channel, so we can calculate the bit depth of a buffer          by multiplying n_channels by bits_per_sample. Normally          this value stays at 8, implying 24-bit color depth for a          three-channel RGB pixbuf.        </P><P>          The next four fields describe the structure of the          buffer. The pixels field points to the actual buffer data,          which is simply an array of unsigned char (defined by          typedef to art_u8). The width, height, and rowstride fields          control how the pixels array is divided into rows and          columns, with potential padding bytes at the end of each          row, as indicated by rowstride.        </P><P>          The final two fields, destroy_data and destroy, are optional          fields that permit you to register a callback function that          libart will invoke just before it destroys the ArtPixBuf          instance. You don't need to register the destroy callback          unless you have data of your own that you'd like          automatically cleaned up when the owning ArtPixBuf instance          is destroyed. The ArtDestroyNotify function prototype looks          like this:        </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">typedef void (*ArtDestroyNotify) (void *func_data, void *data);        </PRE></TD></TR></TABLE><P>          Libart provides several functions to automatically fill in          these fields with the proper values. You use a different          function to create a three-channel pixel buffer than you do          to create a four-channel buffer, and yet another set of          functions if you want to register a destroy          callback. Here's a quick listing of the commonly used          ArtPixBuf creation and destruction functions:        </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">ArtPixBuf* art_pixbuf_new_rgb(art_u8 *pixels,    int width, int height, int rowstride);ArtPixBuf* art_pixbuf_new_rgba(art_u8 *pixels,    int width, int height, int rowstride);ArtPixBuf* art_pixbuf_new_rgb_dnotify(art_u8 *pixels,    int width, int height, int rowstride,    void *dfunc_data, ArtDestroyNotify dfunc);ArtPixBuf* art_pixbuf_new_rgba_dnotify(art_u8 *pixels,    int width, int height, int rowstride,    void *dfunc_data, ArtDestroyNotify dfunc);void art_pixbuf_free (ArtPixBuf *pixbuf);        </PRE></TD></TR></TABLE><P>          You may have noticed that ArtPixBuf has a lot of fields          similar to those found in the GdkRGB API. It even seems to          implement a fair amount of the same functionality. Although          at first this may seem like a duplication of effort,2 the          two APIs are kept separate for good reason. GdkRGB is          intimately tied to GDK, and by extension to GLib. Most of          GdkRGB's focus is on rendering pixel buffers to GDK          drawables, performing dithering, and managing color maps-all          operations that are very specific to windowing systems.        </P><P>          On the other hand, libart is very generic, with as few          external dependencies as possible. For this reason libart          can survive outside of GTK+ and GNOME; it doesn't even need          GLib. Libart is free from all windowing-system and GUI          constraints. In the true UNIX spirit, it does one thing and          it does it very well: pixel buffer manipulation. Thus if you          want to make use of libart, you will have to provide your          own code to transfer the contents of the ArtPixBuf          structures to a drawing widget of some sort. Usually the          easiest way is to transfer your pixel buffers to a          G+kDrawingArea widget, using GdkRGB.  The GNOME Canvas          implements a similar approach in its anti-aliased mode,          using GdkRGB and the Canvas widget (see Chapter 11).        </P></DIV></DIV><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLEWIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="graphics-gdkrgb.html">Prev</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="index.html">Home</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="graphics-gdk-pixbuf.html">Next</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">GdkRGB</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="graphics.html">Up</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">Gdk-pixbuf</TD></TR></TABLE></DIV></BODY></HTML>

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?