Alvin wrote:
> Hello all,
> 
> Anyone know how to draw the widgets contained in a Fl_Scroll into an image 
> file?

...

> I have pasted my implementation so far at the bottom of this message.
> 
> My idea/hopes is to have a button that will capture the contents of the 
> Fl_Scroll and save a PNG image. I have the saving part implemented and test 
> independent of this problem.
> 
> When the button is pushed, the capture() method (see below) is called and 
> returns a Fl_RGB_Image. I then write the image data to a PNG file.
> 
> I think my biggest problem is that I don't fully understand the Fl_Offscreen 
> and its associated functions. I have searched the HTML doxygen docs, but 
> documentation for Fl_Offscreen, fl_begin_offscreen, etc. are missing.

Yes, I think that the best FLTK 1.x docs can be found here:

http://www.fltk.org/doc-1.1/drawing.html#offscreen

but they are very terse :-(

> The image I am getting in the end is a jumbled mess of the "Hello World" 
> string and random stuff from my desktop.
> 
> Any tips or direction to some archived threads would be greatly appreciated.

I'll try to comment and extend your code, but I'm not sure if you will
need everything I write.

> Fl_RGB_Image* Fl_Canvas::capture()

I assume that Fl_Canvas is derived from Fl_Scroll.

> {
>    if(children() <= 2)
>       return NULL;
> 
>    int xdim = child(0)->w();
>    int ydim = child(0)->h();

I don't know, what child(0) is, but guessing from your code,
this should be some "maximal" box of all widgets ?

>    window()->make_current();
> 
>    // setup the offscreen buffer
>    Fl_Offscreen offscr = fl_create_offscreen(xdim, ydim);

This *may* not be enough for drawing, because your widgets
would be drawn with their relative x/y coordinates added
to your offscreen, and their coordinates *may* be adjusted
by Fl_Canvas's scrolling position. One way would be to
position your Fl_Canvas temporary to (0,0) and set the
scrollbars to (0,0). Please add some code to save and restore the
positions yourself.

Add here:

        resize(0,0,w(),h());

or (maybe better?)

        resize(0,0,xdim,ydim);

If you don't want to resize here, you would probably need:

    Fl_Offscreen offscr = fl_create_offscreen(x()+xdim, y()+ydim);


Then, reset the srcolling position:

        scroll_to(0,0);         // FLTK 1.3
        position(0,0);          // FLTK 1.1

>    // force children to draw into the offscreen buffer
>    fl_begin_offscreen(offscr);
>       Fl_Widget *o = NULL;

To be compatible with FLTK's drawing, all widgets should be
drawn in "forward" order, if overlapping might be an issue,
but I leave this up to you.

>       for(int i = children()-1; i >= 0; --i)
>       {
>          o = child(i);
> 
>          if(o != &scrollbar && o != &hscrollbar)
>             o->draw();

It may depend on your widgets' draw() methods, but to prevent
partial drawing, you should call redraw() before draw() or
maybe damage(FL_DAMAGE_ALL):

            if(o != &scrollbar && o != &hscrollbar) {
               o->redraw();
               o->draw();
            }

>       }
>       
>       fl_rectf(10, 10, 150, 100, FL_BLACK);
>       fl_color(FL_WHITE);
>       fl_font(FL_TIMES, 15);
>       fl_draw("Hello, World!", 15, 10);

You must call fl_read_image() before fl_end_offscreen().
Otherwise you will get the pixels of your normal window.

Don't bother with allocating the image buffer, though, you
can leave this to fl_read_image. And if you repositioned
the Fl_Canvas to (0,0), you can use

       uchar *offscreenImage;
       offscreenImage =
          fl_read_image(offscreenImage, 0, 0, xdim, ydim, 255);

But, as Ian wrote, why would you want to use an alpha image?
You can use instead:

       offscreenImage =
          fl_read_image(offscreenImage, 0, 0, xdim, ydim);

This will give you RGB image data (only 3 bytes/pixel).

(If you didn't call resize(), as proposed, you would have
to use "x(),y()" instead of "0,0", however).

>    fl_end_offscreen();
> 
>    // copy??
>    fl_copy_offscreen(0, 0, xdim, ydim, offscr, 0, 0);

No, don't call fl_copy_offscreen. This would copy your
offscreen buffer to your current display device.

>    // copy the offscreen buffer into a RGBA buffer
>    uchar *offscreenImage = new uchar[xdim * ydim * 4];
>    memset(offscreenImage, 0, xdim * ydim * 4);
> 
>    fl_read_image(offscreenImage, x(), y(), xdim, ydim, 255);

See above.

>    // Pack a Fl_RGB_Image and force its dtor to do the cleanup
>    Fl_RGB_Image *rgb_img = new Fl_RGB_Image(offscreenImage, xdim, ydim, 4);

Also, as Ian wrote, you may not need to pack the image data in an
Fl_RGB_Image, but if you followed my suggestions, you would use only
3 instead of 4 bpp:

  Fl_RGB_Image *rgb_img = new Fl_RGB_Image(offscreenImage,xdim,ydim,3);

>    rgb_img->alloc_array = 1;

(???) I don't want to investigate, what this would do, but I wouldn't
call it.

Don't forget to restore the original position(s) here.

>    return rgb_img;
> }

HTH,

Albrecht
_______________________________________________
fltk mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk

Reply via email to