• Welcome to Vampyre Imaging Library Forum. Please login or sign up.
 

Screenshot from opengl

Started by mkoijn, 24 October 2010, 16:51:27

Previous topic - Next topic

mkoijn

24 October 2010, 16:51:27 Last Edit: 24 October 2010, 19:45:31 by mkoijn
Hi, I'm trying to use Vampyr to save a screenshot of an opengl window. I'm using Lazarus 0.9.28.2 on windows xp.

I'm using glreadpixels to get the rgba values from the opengl canvas and storing the values in a pointer. Then trying to load the data using LoadMultiImageFromMemory , however it returns an error. Here's my code so far. Any help would be great.

Eventually I would like to save animated gifs from the opengl window, is this possible with the Vampyr Imaging Library? and thanks for making the library available.

procedure TForm1.OpenGLControl1Paint(Sender: TObject);
var
Res: pbyte;
size:longint;
error:boolean;
FImage: Tdynimagedataarray;
begin
if Sender=nil then ;

  glClearColor(1.0, 1.0, 1.0, 1.0);
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  glEnable(GL_DEPTH_TEST);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45.0, double(width) / height, 0.1, 100.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  glpushmatrix();
  glTranslatef(0.0, 0.0,-6.0);
//               |
//               |
//      Here's code to build opengl picture 
//               |
//               |
   glpopmatrix();

   OpenGLControl1.SwapBuffers;

   Res:=getmem(openglcontrol1.Height*openglcontrol1.Width*sizeof(byte)*4);
   glPixelStorei(GL_PACK_ALIGNMENT, 1);
   glReadPixels(0, 0, openglcontrol1.Width, openglcontrol1.Height, GL_RGBA, GL_UNSIGNED_BYTE, Res);

   error:=LoadMultiImageFromMemory (Res,openglcontrol1.Height*openglcontrol1.Width*sizeof(byte)*4,fimage);
   savemultiimagetofile('C:\test.gif',fimage);

   freemem(Res);
   freeimagesinarray(fimage);
end;                                             

Galfar

Hi,
if you have pixels already in memory there's no need to use LoadImageFromMemory - that's for loading images stored
in one of supported file formats (JPG, PNG, etc.).
Just copy part of memory with pixels, see this thread http://galfar.vevb.net/imaging/smf/index.php/topic,281.0.html


mkoijn

Thanks for that, much appreciated.
Just for reference, here's the code to save a screenshot from an opengl canvas.


   Res:=getmem(openglcontrol1.Height*openglcontrol1.Width*sizeof(byte)*3);
   glPixelStorei(GL_PACK_ALIGNMENT, 1);
   glReadPixels(0, 0, openglcontrol1.Width, openglcontrol1.Height, GL_RGB, GL_UNSIGNED_BYTE, Res);

   mimg:= Tsingleimage.Create ;
   mimg:=tsingleimage.CreateFromParams (openglcontrol1.Width,openglcontrol1.Height,ifr8G8b8) ;

   CopyMemory(mimg.Bits, @Res[0], mImg.Size);

   SwapChannels(mimg.ImageDataPointer^, ChannelRed, Channelblue);  // swap red and blue colours
   flipimage(mimg.ImageDataPointer^);   // flip image because opengl starts at bottom left, other formats top left
   mimg.SaveToFile ('test.png');

   mimg.free;
   freemem(res);         

Galfar

To create GIF with multiple images inside just use TMultiImage instead of TSingleImage in your code.
Just note that GIF can store only 256 colors for one image, so your screenshots
may look quite ugly when saved to GIF. Other multi image formats supported by Imaging that also support 24/32bit colors are MNG and APNG.

mkoijn

Hi,

I've been trying to convert the code to save the first 36 frames of an opengl window over the last couple of hours using TMultiImage, following examples in "high level interface" in the documentation. Has AddLevel been superceded by AddImage?
However I keep getting a SIGSEGV exception whenever I have the lines:    mimg.AddImage(simg) ;    mimg.SaveMultiToFile('test.gif');   or
mimg.free;   If I comment out all these lines it compiles and runs, but of course it doesn't save an image to disc. Here's what I have so far:

integer i is declared and initialised to 0 before the procedure is called.

Thanks for any help.


var
   simg: TSingleImage;
   mimg: TMultiImage;
   Res: pbyte;

Begin
            |
      opengl code
            |

   glpopmatrix();
   OpenGLControl1.SwapBuffers;
   if (i<=35) then begin
       Res:=getmem(openglcontrol1.Height*openglcontrol1.Width*sizeof(byte)*3);
       glPixelStorei(GL_PACK_ALIGNMENT, 1);
       glReadPixels(0, 0, openglcontrol1.Width, openglcontrol1.Height, GL_RGB, GL_UNSIGNED_BYTE, Res);

       simg:= TSingleImage.Create ;
       simg:=TSingleImage.CreateFromParams (openglcontrol1.Width,openglcontrol1.Height,ifr8G8b8) ;
       CopyMemory(simg.Bits, @Res[0], simg.Size);
       freemem(Res);

       SwapChannels(simg.ImageDataPointer^, ChannelRed, Channelblue);  // swap red and blue colours
       flipimage(simg.ImageDataPointer^);   // flip image because opengl starts at bottom left, other formats top left

       if (i=0) then begin
          mimg:= TMultiImage.Create;
          mimg.Assign(simg) ;
       end
       else if i>0 then begin
          mimg.AddImage(simg) ;
       end;

       simg.free;

       if i=35 then begin
         mimg.SaveMultiToFile('test.gif');
         mimg.free;
       end;

       i:= i+1;
   end;
end;                             


mkoijn

Ah, silly mistake, I forgot to declare Mimg outside the procedure. It works now.

Is there anyway to regulate the delay between frames in the saved gif?

Thanks a lot.

Galfar

This can be done with new metadata support in the latest versions in SVN
but I haven't uploaded GIF support yet (only APNG stores delays now).
I'll test it and upload it in a few days.

mkoijn

That's great. Would it also be possible to have an option for the gif to loop continuosly?

Many thanks again for a great library.

Galfar

I'v updated SVN reposiotory with these new GIF saving features.
Set metadata before saving the GIF like this:


// set loops for the whole animation
GlobalMetadata.AddMetaItemForSave(SMetaAnimationLoops, 3);

// delay for each frame in ms
GlobalMetadata.AddMetaItemForSave(SMetaFrameDelay, 300, ImageIndex);

mkoijn

Thanks for that. I'm having trouble getting that to work. The gifs animate once only no matter what integer I set in
GlobalMetadata.AddMetaItemForSave(SMetaAnimationLoops, 0 ); It should be that if it's set to zero it should animate indefinately?
Also do the GlobalMetadata.AddMetaItemForSave features work for both gif and png?

Thanks again.

Galfar

I uploaded a fix for infinite delays. Please test it.
AddMetaItemForSave for PNG only works for print resolution metadatas, not animations yet.
Hopefully I'll get to it ina few days.

Galfar

Support for frame delays and animation loop count was added finally.

Quick Reply

With Quick-Reply you can write a post when viewing a topic without loading a new page. You can still use bulletin board code and smileys as you would in a normal post.

Name:
Email:

Shortcuts: ALT+S save/post or ALT+P preview

SMF spam blocked by CleanTalk