[Solved]How does Picture.image load memory bitmap

General help with the Ecere Cross Platform GUI toolkit: Window, common controls, events, etc.
Help with the 2D Graphics library: Surface, Display, Bitmap, Font and others.
Post Reply
samsam598
Posts: 212
Joined: Thu Apr 14, 2011 9:44 pm

[Solved]How does Picture.image load memory bitmap

Post by samsam598 »

Given below code based on sdk/examples,I can show the screen shot in a picture control.As you can see we capture the screen shot and hold in a memory bitmap,then we save the bitmap to a png file.Finally we read the file and assign to picture control's image field.

My question is how can I just use the memory bitmap to initialize the picture control's image field other than save it into a png file first?The line I marked as q1 is what I want to do but it does not work.Please help.Thanks.

Code: Select all

 
 
import "ecere"
 
class Form1 : Window
{
   text = "Form1";
   background = activeBorder;
   borderStyle = sizable;
   hasMaximize = true;
   hasMinimize = true;
   hasClose = true;
   size = { 648, 512 };
   anchor = { horz = -39, vert = -45 };
   icon = { "C:\\person\\CodeLite\\images\\cubes.png" };
   nativeDecorations = true;
 
   Picture picture1 { this, text = "picture1", anchor = { left = 0, top = 0, right = 0, bottom = 0 } };
}
 
class App:GuiApplication
{
   bool Init()
   {  
      Form1 form1{};
      Bitmap bitmap{};
      SwitchMode(false,null,0,0,0,null,false);
      desktop.Grab(bitmap,null,false);
 
 
      bitmap.Save("screen.png",null,null);
      form1.picture1.image={"screen.png"}; 
      // form1.picture1.image.bitmap=bitmap; !!!q1
      delete bitmap;
      return true;
   }
}
 
Last edited by samsam598 on Thu Sep 08, 2011 12:28 am, edited 1 time in total.
jerome
Site Admin
Posts: 608
Joined: Sat Jan 16, 2010 11:16 pm

Re: How does Picture.image load memory bitmap

Post by jerome »

Hi Sam,

The 'Picture' common control is meant to be a simple way to insert a static picture inside a form. It's not meant for advanced bitmap manipulation. Same is true of the BitmapResource class, which provides an easy way to make use of bitmaps in your application. Both the Picture control and the BitmapResource class it works with (The data type of the 'image' property) work with files only.

For more advanced image manipulation, you are supposed to use the Bitmap class directly, and handle the loading/unloading of graphics through the OnLoadGraphics/OnUnloadGraphics virtual methods of the Window class. The BitmapResource class does this automatically (that is why when using a BitmapResource inside a Window, you specify the window to attach the resource to your window). Ecere supports dynamic mode switching of applications, e.g. if the user changes his graphics mode from 16 bit to 32 while your application is running, or can even switch between GDI, OpenGL, Direct3D. This is why you need to think of needing to load graphics or unload graphics at any time, separate from window creation/destruction.

There are two possible solutions to your problem. I'll start with the original way to do this, we'll make a BitmapPicture control that will work exactly the way you wanted. The second way is because I've hit myself to the same problem a year or two ago and I came up with a nice hack: a virtual file in memory.

Solution #1: A new class of Picture control
So we'll start with the BitmapPicture control, here's the code for the class:

Code: Select all

class BitmapPicture : Window
{
   Bitmap bitmap;
   Bitmap ddBitmap { };
 
   public property Bitmap image
   {
      set
      {
         delete bitmap;
         bitmap = value;
         incref bitmap;
         if(created)
         {
            OnUnloadGraphics();
            OnLoadGraphics();
         }
      }
      get { return bitmap; }
   }
   ~BitmapPicture()
   {
      delete bitmap;
   }
 
   void OnRedraw(Surface surface)
   {
     surface.Stretch /*Filter*/(ddBitmap, 0, 0, 0, 0, clientSize.w, clientSize.h, ddBitmap.width, ddBitmap.height);
   }
 
   bool OnLoadGraphics()
   {
      ddBitmap.Copy(bitmap);
      ddBitmap.MakeDD(displaySystem);
      return true;
   }
 
   void OnUnloadGraphics()
   {
      ddBitmap.Free();
   }
}
You see how we define a bitmap property. We take a reference on it, and we'll delete it when the control is destroyed. If the window is already created when we set the bitmap, we manually reload the graphics because the system isn't aware the bitmap needs to be reloaded.

Inside OnLoadGraphics, we make a a Device-Dependent copy of the bitmap in another Bitmap object, 'ddBitmap'. This is going to be in the format most appropriate for the current display driver and mode, for optimal display performance, e.g. a texture loaded on the graphics card in OpenGL or Direct3D mode. We do this by using Copy() to make a copy, and then MakeDD() to turn it into a device dependent bitmap. Finally, in OnUnloadGraphics() we free the bitmap with Free().

We could skip the whole OnLoadGraphics/OnUnloadGraphics/ddBitmap part, and just draw bitmap, but we would lose drawing performance. If we were making an image manipulation program we probably wouldn't do this because the bitmap keeps changing anyways.

We use Surface::Stretch for drawing the bitmap to the control. Filter is a bilinear filtering version of Stretch, it would look nicer but comes with a significant performance cost, especially in GDI mode (Ecere does it in software in that case). At the moment there's no difference between Filter and Stretch in OpenGL/Direct3D mode, Ecere always turns on bilinear filtering for those functions.

Then 'form1.picture1.image=bitmap;' should work.

Solution #2: A Virtual File
To get a virtual File going, we'll need a TempFile object, and we'll use special filename that Ecere understands as being a TempFile, starting with the prefix "File://" followed by the address of the TempFile object in hexadecimal. We'll use sprintf with '%p' (for pointer) to prepare our filename. We can either add a .png extension to our filename, or specify a 'type' when we use the Bitmap::Save method, so that it knows what format to save in. Here is the code:

Code: Select all

class App:GuiApplication
{
   TempFile file { };
   bool Init()
   {  
      Form1 form1{};
      Bitmap bitmap{};
      char fileName[100];
      sprintf(fileName, "File://%p.png", file);
      desktop.Grab(bitmap,null,false);
      bitmap.Save(fileName,null,null);
      delete bitmap;
      form1.picture1.image={fileName}; 
      return true;
   }
}
Hope this helps :D

Regards,

Jerome
Post Reply