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

