AGG第四十三課 例子image1從橢圓到矩形替換問題

I am basing my code on the images1 example and I have changed

the image 'partner' shape from an ellipse to a rectangle.


The partner rectangle comes out at X,Y and scales and rotates,

but the top left-hand corner of the image is always stuck at

(x,y)=3D(0,0). Only the part of the image that overlaps the=20

rectangle is visible, but that part scales and rotates properly.=20

When there is no overlap, there is no image.


I do not understand much of the the image1 example, so I am

lost as to what might be.the cause. Code is attached.


Would be most grateful for help and/or example code.

void image ( HAGG * h , int x , int y , TCHAR * imgfilename )

   {

   if ( !loadimage ( h , imgfilename ) ) // sets image details in h

      {

      return ;

      }

   agg::rendering_buffer rbuf(h->pixels ,

                              h->frame_width ,=20

                              h->frame_height ,=20

                              -(h->frame_width * h->bytesperpixel) ) ;=20

   typedef agg::renderer_base<pixfmt>                     renderer_base;

   typedef agg::renderer_base<pixfmt_pre>                 =

renderer_base_pre;

   typedef agg::renderer_scanline_aa_solid<renderer_base> =

renderer_solid;

   pixfmt            pixf(rbuf);

   pixfmt_pre        pixf_pre(rbuf);

   renderer_base     rb(pixf);

   renderer_base_pre rb_pre(pixf_pre);

   renderer_solid    rs(rb);


   rb.clear(agg::rgba(1.0, 1.0, 1.0));


   agg::rasterizer_scanline_aa<> pf;

   agg::scanline_u8 sl;


   IMGINFO * i =3D &h->imgs [ 0 ] ;

   double imgwd =3D i->width ;       // image width

   double imght =3D i->height  ;     // image height


   agg::trans_affine src_mtx;

   src_mtx *=3D agg::trans_affine_translation(-x,-y);

   src_mtx *=3D agg::trans_affine_rotation(-h->t.angle);  // in radians

   src_mtx *=3D agg::trans_affine_scaling(h->t.scalex , h->t.scaley);

   src_mtx *=3D agg::trans_affine_translation(x,y);

   agg::trans_affine img_mtx;

   img_mtx *=3D agg::trans_affine_translation(-x,-y);

   img_mtx *=3D agg::trans_affine_rotation(-h->t.angle);

   img_mtx *=3D agg::trans_affine_scaling(h->t.scalex , h->t.scaley);

   img_mtx *=3D agg::trans_affine_translation(x,y);

   img_mtx.invert();


   typedef agg::span_allocator<color_type> span_alloc_type;

   span_alloc_type sa;

   typedef agg::span_interpolator_linear<> interpolator_type;

   interpolator_type interpolator(img_mtx);


   // "hardcoded" bilinear filter


   typedef agg::span_image_filter_rgb_bilinear<color_type, =

component_order,=20

                                               interpolator_type> =

span_gen_type;

   typedef agg::renderer_scanline_aa<renderer_base_pre, span_gen_type> =

renderer_type;


   agg::rendering_buffer rbuf_img(i->pixels ,

                                  (int)imgwd ,=20

                                  (int)imght ,=20

                                  -i->stride ) ;=20

   span_gen_type sg(sa,=20

                    rbuf_img,  // rendering buf with image pixels

                    agg::rgba_pre(0, 0.4, 0, 0.5),

                    interpolator);

   renderer_type ri(rb_pre, sg);

   agg::path_storage path; // partner rectangle

   path.move_to( x,y);

   path.line_to( x+imgwd, y );

   path.line_to( x+imgwd, y+imght);

   path.line_to( x, y+imght);

   path.close_polygon();

   agg::conv_transform<agg::path_storage> tr(path, src_mtx);

         =20

   pf.add_path(tr);

   agg::render_scanlines(pf, sl, ri);

   }

static void drawimage ( )

   {

   RECT rt ;

   GetClientRect(hwndmain, &rt);

   int width =3D rt.right - rt.left;

   int height =3D rt.bottom - rt.top;


   HAGG * h =3D gethandle ( mybuf , width , height , 4 ) ;


   settrans_scale ( h , scale ) ;

   settrans_rotate ( h , degrees ) ;

//   image ( h , 20,50 , "bmpeivor.bmp"  ) ; // does not work

   image ( h , 0,0 , "bmpeivor.bmp"  ) ;  // works


   display ( h , hwndmain ) ;  // on screen

   }

作者的回答:

Transforming images is tricky, especially proper calculation of the affine 

matrix.

But first, if you don't need to transform it you can directly copy or blend 

the image, it will work much faster. See renderer_base<>::copy_from(), 

blend_from().


For the transformer there's a simple way of calculating the matrix as a 

parallelogram, see image_perspective.cpp


// Note that we consruct an affine matrix that transforms

// a parallelogram to a rectangle, i.e., it's inverted.

// It's actually the same as:

// tr(0, 0, img_width, img_height, para); tr.invert();

agg::trans_affine tr(para, 0, 0, img_width, img_height);


Where "para" is double[6] that defines 3 point of the parallelogram.


困惑:

I have replaced


   agg::path_storage path; // partner rectangle

    path.move_to( x,y);

    path.line_to( x+imgwd, y );

    pathmline_to( x+imgwd, y+imght);

    path.line_to( x, y+imght);

    path.close_polygon();

    agg::conv_transform<agg::path_storage> tr(path, src_mtx);

    pf.add_path(tr);

    agg::render_scanlines(pf, sl, ri);


at the and of my image proc (code of the whole proc is at

the end of my original post (and at the end of this email))


by


   double para [ 6 ]

    = { 0,100 ,  0,0 , 100.0 } ; // 3 points (0,100) (0,0) and (100,0)

   agg::trans_affine tr(para, 0, 0, imgwd, imght);

   pf.add_path(tr);

   agg::render_scanlines(pf, sl, ri);


Q1.   is this the right way?


Q2.  what should the para points be expressed as functions of

        image top-left hand corner, image width and image height, i.e.

        x,y, imgwd, imght?


My test cases includes image (x,y)=(0,0), so I defined para points

(0,100), (0,0) and (100,0) just to see what would happen.


but got compilation errors:


..\agg23\include\agg_rasterizer_scanline_aa.h(465) : error C2039: 'rewind' :

is not a member of 'trans_affine'

  ..\agg23\include\agg_trans_affine.h(88) : see declaration of

'trans_affine'


and one more very similar:  'vertex' : is not a member of 'trans_affine'

作者的回答:


> double para [ 6 ] = { 0,100 ,  0,0 , 100,0 } ; // 3 points (0,100) (0,0) 

> and (100,0)

> agg::trans_affine mtx(para, 0, 0, imgwd, imght);

> agg::path_storage path; // partner rectangle

> path.move_to( x,y);

> path.line_to( x+imgwd, y );

> path.line_to( x+imgwd, y+imght);

> path.line_to( x, y+imght);

> path.close_polygon();

> agg::conv_transform<agg::path_storage, agg::trans_affine> trans(path, 

> mtx);

>

> pf.add_path(trans); // Note you add "trans"

>

> Then, if you want your image to fit exactly your parallelogram path (you 

> also may want to do differently!), you need to create a copy of the matrix 

> and invert it:

>

> agg::trans_affine img_mtx(mtx);

> img_mtx.invert();


I'm sorry, Ken, this is not correct; I have confused myself, so, please 

discard the code above. :)


So, suppose you have an image of imgwd, imght and a destination 

parallelogram. To define the parallelogram you need 3 points, x1,y1 - bottom 

left, x2,y2 - bottom right, x3,y3 - top right. The parallelogram can also 

define a 2D affine matrix: rotation, scaling, translation and skewing. You 

can rasterize your destination parallelogram directly:


agg::rasterizer_scanline_aa<> ras;

ras.move_to_d(x1,y1);

ras.line_to_d(x2,y2);

ras.line_to_d(x3,y3);

ras.line_to_d(x1 + x3 - x2, y1 + y3 - y2);

So that, you can draw a solid parallelogram (well, you can also use the 

path_storage if you want).

To map an image to it you need to create the matrix:


double para[6] = {x1,y1,x2,y2,x3,y3};

agg::trans_affine img_mtx(0, 0, imgwd, imght, para);

img_mtx.invert();


Or, which is the same:


double para[6] = {x1,y1,x2,y2,x3,y3};

agg::trans_affine img_mtx(para, 0, 0, imgwd, imght);


The first one construicts a matrix to transform a rectangle to a a 

parellelogram, the second one - parallelogram to rectangle. The image 

transformer requires namely inverse matrix, so that, you transform your 

parallelogram (destination) to rectangle (image).


Technically that's it. But you may want to apply additional transformations. 

To do that you will need two matrices:


agg::trans_affine master_mtx;

master_mtx *= agg::trans_affine_translation(. . .);

master_mtx *= agg::trans_affine_rotation(. . .);

. . .

agg::rasterizer_scanline_aa<> ras;

agg::path_storage path; // partner rectangle

path.move_to(x1,y1);

path.line_to(x2,y2);

path.line_to(x3,y3);

path.line_to(x1 + x3 - x2, y1 + y3 - y2);

path.close_polygon();

agg::conv_transform<agg::path_storage, agg::trans_affine> trans(path, 

master_mtx);


Then you prepare the image matrix:

double para[6] = {x1,y1,x2,y2,x3,y3};

agg::trans_affine img_mtx(0, 0, imgwd, imght, para);

img_mtx *= master_mtx; //!!!!!!!!!!!!! Integrate the master transforms

img_mtx.invert();


ras.add_path(trans);

. . .Render


Now, whatever transformations you use in the master_mtxà they will be 

synchronized with the image.

Sorry for the delay, I was kinda busy last time. and besides, I'm suffering 

from constant problems with the Internet (Verizon in NYC sucks, I'm 

switching to cable).


Well, I understand everyone is busy, but could someone else answer the 

questions too?


First, you need to understand that a path is the primary thing in AGG. 

Without path you can't draw anything. So that, to rotate an image you need 

to create a respective path as if you wanted to fill this area with a solid 

color. And then, you just substitute an image renderer for your solid fill. 

Obviously, to transform the whole image you need to create a parallelogram 

path (a rectangle in particular). You can do that calculating the points 

manually:

ras.move_to_d(x1, y1);

ras.line_to_d(x2, y2);

. . .

You you can use transformations.

Next, trans_affine doesn't have any "VertexSource" interface, it can't 

generate vertices. It can only transform them: affine.transform(&x, &y); To 

add affine transformer into your pipeline you also need conv_transform:


double para [ 6 ] = { 0,100 ,  0,0 , 100,0 } ; // 3 points (0,100) (0,0) and 

(100,0)

agg::trans_affine mtx(para, 0, 0, imgwd, imght);

agg::path_storage path; // partner rectangle

path.move_to( x,y);

path.line_to( x+imgwd, y );

path.line_to( x+imgwd, y+imght);

path.line_to( x, y+imght);

path.close_polygon();

agg::conv_transform<agg::path_storage, agg::trans_affine> trans(path, mtx);


pf.add_path(trans); // Note you add "trans"


Then, if you want your image to fit exactly your parallelogram path (you 

also may want to do differently!), you need to create a copy of the matrix 

and invert it:


agg::trans_affine img_mtx(mtx);

img_mtx.invert();


Well, I realize that it all is pretty confusing. But this kind of a design 

is most flexible.


摘自:http://sourceforge.net/p/vector-agg/mailman/vector-agg-general/?viewmonth=200511&page=0


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章