Create a bitmap and drawing in it?



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 27/04/2012 at 11:48, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   12 
    Platform:   Windows  ;   
    Language(s) :     C++  ;

    ---------
    Hey guys.
    I'm trying to learn how to create and paint images using the SDK. But I'm having a hard time getting started.

    This is what I have so far:

        MultipassBitmap *mbmp = MultipassBitmap::Alloc(1024, 1024, COLORMODE_RGBf); //Create a new bitmap  
      if (!mbmp) return FALSE;  
      
      mbmp->SetPen(1,1,1);            //Set the color to white  
      mbmp->Line(20,20,300,40);       //Draw a line  
      
      ShowBitmap(mbmp);               //Show the bitmap in the picture viewer  
      
      MultipassBitmap::Free(mbmp);    //Free the memory
    

    All I get is a black 1024x1024 image in the picture viewer.
    I can't get my line to show up in it.
    What am I doing wrong?

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 27/04/2012 at 13:22, xxxxxxxx wrote:

    mbmp->Init(1024L, 1024L);

    You'd be better off using a BaseBitmap though.  Not sure of the level of support for displaying a MultipassBitmap in the Picture Viewer.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 27/04/2012 at 13:40, xxxxxxxx wrote:

    Thanks Robert.
    But that creates a blank image where you just see the alpha checker board pattern in the viewer.
    I'm only using the viewer as a quick way to see what I'm drawing.

    My goal is to be able to create a bitmap->draw some lines in it->Then save the image.
    I tried using BaseBitmap. But I'm having a bit of trouble with writing the the Init() method.

    I also don't see a line size option. So I'm not sure the what the best way is to draw the lines with any amount of control.

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 27/04/2012 at 14:01, xxxxxxxx wrote:

    Yes, indeed.  It creates a blank image.  You need to use Clear() to set a background color.  I've only used SetPixel() for painting into a bitmap (besides simply loading an image into it).  You may need to write your own draw routines to do lines, circles, rectangles, etc. using SetPixel() as the atomic basis.

    A BaseDraw from a BaseView has much better draw support but then you cannot get a bitmap from it unfortunately.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 27/04/2012 at 15:25, xxxxxxxx wrote:

    Making some progress. But I have some questions.
    Here's an example that creates a red 1024x1024 image with a white stripe down the middle.

        BaseBitmap *mbmp = NULL;  
      mbmp = BaseBitmap::Alloc();  
      if (!mbmp) return FALSE;  
      
      mbmp->Init(1024L, 1024L, 24L);  
      mbmp->Clear(0,0,1023,1023,255,0,0);         //Why does the image turn black if I set the size values to 1024?  
      
      SReal *buffer = GeAllocType(SReal, 100);    //What exactly is this buffer thing doing?  
      if (!buffer) return FALSE;  
      
      //Crank up the line's brightness over 100% so the line is visible  
      for (LONG i=0; i<100; i++)  
          buffer[i] = 1.0;                      //Why can't I just set the color values normally(Not overcrank the brightness)?  
      
      for (LONG y=0; y<1024; y++)  
          if (!mbmp->SetPixelCnt(512, y, 50, (UCHAR* )buffer, 4, COLORMODE_RGBf, PIXELCNT_0)); //What the heck is buffer and inc doing here?  
      
      ShowBitmap(mbmp);                     //Shows the image in the picture viewer  
      
      BaseBitmap::Free(mbmp);
    

    I would like to advance into creating shapes now.
    But I'm still not clear on what this buffer and inc stuff is doing.

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 27/04/2012 at 17:04, xxxxxxxx wrote:

    You are trying to do too much without knowing what you are doing yet. ;)

    This works:

        BaseBitmap *mbmp = BaseBitmap::Alloc();  
      if (!mbmp) return FALSE;  
      
      mbmp->Init(1024L, 1024L, 24L);  
      mbmp->Clear(255,0,0);         // Don't need the size parameters to fill the entire bitmap  
      
      UCHAR *buffer = GeAllocType(UCHAR, 300);    // This represents a set of RGB values (3 per pixel)  
      if (!buffer) return FALSE;  
      
      //Crank up the line's brightness over 100% so the line is visible  
      for (LONG i=0; i < 300; i += 3)  
      {  
          buffer[i] = 255;                      // Don't use floating point RGB channels  
          buffer[i+1] = 255;  
          buffer[i+2] = 255;  
      }  
      
      for (LONG y=0; y<1024; y++)  
          if (!mbmp->SetPixelCnt(512, y, 50, (UCHAR* )buffer, 3, COLORMODE_RGB, PIXELCNT_0)) break; // inc increments the buffer for each pixel by the size of each pixel - in this case it should be 3 (3-bytes per pixel)  
      
      ShowBitmap(mbmp);                     //Shows the image in the picture viewer  
      
      BaseBitmap::Free(mbmp);
    


  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 27/04/2012 at 18:29, xxxxxxxx wrote:

    I'm still fuzzy on the buffer thing.
    Why did you pick the number 300?

    For example: Matthias chose this number in one of his examples:
    buffer = GeAllocType(SReal, 1024*3);

    AFAICT. It seems that the inc value is working with the buffer value.
    But I don't see how their mathematical relationship works. Since 3*300 doesn't equal 1024. I'm not seeing how the equation is working.
    I do see that if I change the numbers around. Then I get colored stripes in the result.
    But I'm not seeing the relevance of how the buffer number of 300. And the inc number of 3 produces the desired (stripe free ) clean results.

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 27/04/2012 at 19:28, xxxxxxxx wrote:

    It would be less confusing if you just ignored SetPixelCnt().  All it does is copy the color values stored in buffer into the x, y coordinate range.  I just used 300 because 100 pixels would be 3-bytes * 100 = 300.  50 is the number of pixels you are settings each pass.  Your buffer is set up to set 100 pixels but you are only using the first 50 (not that that matters).  You need the buffer to be big enough to set the number of pixels - which it is.  Note that you can set a region if the buffer wraps the image width - I would think that if you started at x = 1000 and set 50 pixels it will either wrap to the next line (y increments) or just do a clip.

    The only sane way to draw into the bitmap is by using SetPixel() which is why that is all that I use. :D



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 27/04/2012 at 19:37, xxxxxxxx wrote:

    Ok. I'll try SetPixel() next.

    Do you have any advice about controlling the line's thickness using that function to draw a line?
    That was the next thing I needed to figure out how to control.

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 28/04/2012 at 00:51, xxxxxxxx wrote:

    The SDK has the GeClipMap class providing more advanced drawing tools than BaseBitmap. (Can draw lines, rects, arcs, ellipses, texts etc.)



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 28/04/2012 at 05:59, xxxxxxxx wrote:

    Have forgotten all about the GeClipMap.  Looks like you initialize it with your BaseBitmap and away you go.  Aha! :)



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 28/04/2012 at 08:28, xxxxxxxx wrote:

    Doh!
    I'd like to try that. But I can't figure out how to write the Init() function for the GeClipMap class.
    I've looked through the archives. And none of the code posted works.

    Example:

         AutoAlloc<GeClipMap> gcm;  
       if(!cm) return FALSE;  
      
       gcm->Init(1024L, 1024L, 24); <---Does not work  
       gcm->BeginDraw(); 
    

    I've got my BaseBitmap allocated and initialized.
    And I've got my GeClipMap allocated.
    But when I try to initialize the GeClipMap with my BaseBitmap. It doesn't work:

       BaseBitmap *bmp = BaseBitmap::Alloc();  
      if (!bmp) return FALSE;  
      bmp->Init(1024L,1024L,24);  
      
      AutoAlloc<GeClipMap> gcm;  
      if(!gcm) return FALSE;  
      
      //Now how do I Init() the GeClipMap with my BaseBitmap?
    

    The SDK says to do it like this: **IMAGERESULT Init(BaseBitmap* bm); **
    But how the heck are we supposed to use this IMAGERESULT type?

    The thing that I have the most trouble figuring out in the C4D SDK is how to allocate and initialize the various classes. It's almost never documented.
    I hope that changes in the future.

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 28/04/2012 at 09:54, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    The SDK says to do it like this: **IMAGERESULT Init(BaseBitmap* bm); **
    But how the heck are we supposed to use this IMAGERESULT type?

    IMAGERESULT is the returned result type when you call Init().
    In the docs you can see below it that it can be one of the listed values : IMAGERESULT_OK, IMAGERESULT_NOTEXISTING, IMAGERESULT_WRONGTYPE etc.
    So to initialize the clipmap with your bitmap you should call:

    if (gcm->Init(bmp)==IMAGERESULT_OK)
    {
        gcm->BeginDraw();
      
        // Draw in the clipmap
      
        gcm->EndDraw();
    }
    

    But it's not necessary to init the clipmap with a just created bitmap, clipmap can do that if you call gcm->Init(1024L, 1024L, 24L). Why do you say that initializing the clipmap with this method doesn't work ?
    You can access at any time the clipmap bitmap with GetBitmap() method.

    Originally posted by xxxxxxxx

    The thing that I have the most trouble figuring out in the C4D SDK is how to allocate and initialize the various classes. It's almost never documented.
    I hope that changes in the future.

    In GeClipMap documentation, just at the end of the class description or header:
    "Has to be created with Alloc() and destroyed with Free(). You can use AutoAlloc to automate the allocation and destruction based on scope."
    So just what you're doing.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 28/04/2012 at 10:24, xxxxxxxx wrote:

    This is the error I get:

        AutoAlloc<GeClipMap> gcm;  
      if(!gcm) return FALSE;  
      
     gcm->Init(1024L, 1024L, 24L); //Error:Pointer to an incomplete class type is not allowed
    

    I'm using this code in the Command() method of a dialog plugin. Because it's just a plugin that I have already installed and handy. Could it be that this is causing a problem?
    Should I try this code in a different type of plugin?
    Does this code maybe require a virtual method() to be overwritten that I'm not using?

    -ScottA

    Update - Doh! My bad.
    Apparently. I was missing an include: #include lib_clipmap.h
    Normally when I'm missing an #include. VS gives me an "undefined error".
    I've never seen this type of error happen before.
    Sorry for being such a noob.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 28/04/2012 at 11:20, xxxxxxxx wrote:

    @ScottA: An incomplete Type is only forward declared and not implemented yet.  😉



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 28/04/2012 at 11:21, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Update - Doh! My bad.
    Apparently. I was missing an include: #include lib_clipmap.h
    Normally when I'm missing an #include. VS gives me an "undefined error".
    I've never seen this type of error happen before.
    Sorry for being such a noob.

    No problem, you're welcome 🙂. This is the kind of issues we all get when we begin coding in C++.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 28/04/2012 at 18:43, xxxxxxxx wrote:

    One last question.
    Because I've switched to GeClipMap. How do I save the changes I make to my image?
    Everything I'm seeing regarding saving revolves around BaseBitmap.

    Here's an example where I edit an image from a path:

        Filename fn = GeGetC4DPath(C4D_PATH_DESKTOP)+"myimage.jpg"; //Get the path to an image  
      Bool ismovie = FALSE;                      //Set if it's an image or a movie type image  
      
      AutoAlloc<GeClipMap> gcm;                 //Create an instance of the GeClipMap class  
      gcm->Init(fn, 0, &ismovie);               //Initialise it using the image in our path  
      
      LONG width = gcm->GetBw();                //Get the image's width  
      LONG height = gcm->GetBh();               //Get the image's height  
      GePrint("Width: " + LongToString(width) + ", Height: " + LongToString(height));  
      
      gcm->BeginDraw();   
      gcm->SetColor(1.0, 1.0,1.0);    //Set the color to white  
      gcm->FillRect(50,50,100,100);   //Create a filled rectangle area  
      gcm->EndDraw();  
      
      LONG getx=80, gety=80;                         //The pixel to get the color from  
      LONG getr=0, getg=0, getb=0, geta=0;           //Init the rgba values with the value of zero  
      gcm->GetPixelRGBA(getx, gety, &getr, &getg, &getb, &geta);  //Get the Pixel colors  
      
      GePrint("r: " + LongToString(getr) + ", g: " + LongToString(getg) + ", b: " + LongToString(getb) + ", a: " + LongToString(geta));  
      
      //This part is wrong  
      //How do I save my image after I've changed it using GeClipMap?  
      AutoAlloc<BaseBitmap> bmp;  
      bmp->Init(fn,0,&ismovie);  
      bmp->Save(Filename(fn),FILTER_JPG,NULL,SAVEBIT_32b**chANNELS|SAVEBIT_GREYSCALE|SAVEBIT_ALPHA);
    

    How do I save the image so it reflects the changes I've made to it using GeClipMap?

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 29/04/2012 at 08:35, xxxxxxxx wrote:

    Wouldn't you have to get the bitmap back out of GeClipMap? I seem to recall there's a 'GetBitmap()' function or something similar to retrieve the changed bitmap. Then you would save that.

    Steve



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 29/04/2012 at 11:17, xxxxxxxx wrote:

    I have no idea Steve. This is not obvious stuff. At least not to me it isn't.
    There's these two separate classes(BaseBitmap&GeClipmap). And each one has it's own strengths and limitations.
    And to make things more confusing...There's no clear documentation in the docs showing how to make these two classes work together. To edit or create images with them.

    Here's my latest attempt at loading an image. Then editing it with GeClipMap. Then saving it:

        Filename fn = GeGetC4DPath(C4D_PATH_DESKTOP)+"myimage.jpg"; //Get the path to an image  
      
      //Because we have to init first..Then get the image's info. We'll create a dummy BaseBitmap instance first  
      //This BaseBitmap instance will be used just to gather inforamtion about the file we've imported  
      AutoAlloc<BaseBitmap> file;                //Create a new BaseBitmap instance  
      file->Init(fn);                            //intialize it using the file path we used as the target image  
      LONG width = file->GetBw();                //Get the image's width  
      LONG height = file->GetBh();               //Get the image's height  
      LONG bitDepth = file->GetBt();             //Get the image's bitdepth  
      GePrint("Width: " + LongToString(width) + ", Height: " + LongToString(height) + ", BitDepth:  " + LongToString(bitDepth));  
      
      
      //Now we'll create another BaseBitmap...Based on the info we gathered from the previous BaseBitmap instance  
      //This is the one we'll edit and make changes to  
      AutoAlloc<BaseBitmap> bmp;           //Create a new image based on the file's info  
      bmp->Init(width, height,bitDepth);  
      file->CopyTo(bmp);                   //Copies the image's info over to this BaseBitmap instance  
      //bmp->Clear(255,255,255);           //Set the entire image to the color white if desired  
      bmp->SetPen(255,255,255);  
      bmp->Line(0,0,100,200);  
      
      AutoAlloc<GeClipMap> gcm;  
      if(!gcm) return FALSE;  
      gcm->Init(bmp);                       //Initialise the clip map using the BaseBitmap above so we can save it later on  
      gcm->BeginDraw();  
      gcm->SetColor(255, 0, 0);             //Sets the color of the text to red  
      gcm->FillRect(0,0,100,100);  
      gcm->EndDraw();  
      
      Filename newfn = GeGetC4DPath(C4D_PATH_DESKTOP)+"myimagenew.jpg"; //Create a path to save our new image  
      bmp->Save(Filename(newfn),FILTER_JPG,NULL,SAVEBIT_0);             //Save the new image
    

    The result is a copy of the source image. With a rectangle drawn with some weird missing strips. And the wrong color(green)
    But at least I'm getting  something as a result.
    I'm slowly getting there...But I'm doing a lot of fumbling around in the dark. 😂

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 30/04/2012 at 00:09, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    The result is a copy of the source image. With a rectangle drawn with some weird missing strips. And the wrong color(green)
    But at least I'm getting   something  as a result.
    I'm slowly getting there...But I'm doing a lot of fumbling around in the dark. LOL

    Yes because after drawing to the clipmap you need to get the modified bitmap with GetBitmap() (as said Steve above). The source bitmap isn't updated automatically.

      
      AutoAlloc<GeClipMap> gcm;  
      if(!gcm) return FALSE;  
      gcm->Init(bmp);                       //Initialise the clip map using the BaseBitmap above so we can save it later on  
      gcm->BeginDraw();  
      gcm->SetColor(255, 0, 0);             //Sets the color of the text to red  
      gcm->FillRect(0,0,100,100);  
      gcm->EndDraw();
      
        **BaseBitmap *clipBmp** _ **  = gcm->GetBitmap()    //Get modified bitmap from clipmap**_  
      
      Filename newfn = GeGetC4DPath(C4D_PATH_DESKTOP)+"myimagenew.jpg"; //Create a path to save our new image  
         clipBmp->Save(Filename(newfn),FILTER_JPG,NULL,SAVEBIT_0);             //Save the new image
    

    EDIT: Fixed code.


Log in to reply