Loading a Doodle Bitmap



  • On 30/07/2014 at 02:05, xxxxxxxx wrote:

    I add a Doodle Object and then want to set the Bitmap (see "Load Bitmap").
    So, I use Doodle Object[c4d.DOODLEOBJECT_IMAGE] to set the image.
    But then I get "Error: __setitem__ expected c4d.BaseList2D, not c4d.bitmaps.BaseBitmap".

    Or am I mixing up an input field with a button?

    Or is there another way to do it?
    I do not want to use  c4d.CallButton(doodleObj, c4d.DOODLEOBJECT_LOAD_BITMAP), because I want to load the bitmap automatically without any user input.

    import c4d
    from c4d import gui, plugins, bitmaps
    #Welcome to the world of Python
      
    def main() :
        c4d.CallCommand(1022215) # Add Doodle Frame
        doodleObj = doc.SearchObject("Doodle Object")
      
        orig = bitmaps.BaseBitmap()
        path = "C:\doodle example.jpg"
        if orig.InitWith(path)[0] != c4d.IMAGERESULT_OK:
            gui.MessageDialog("Cannot load image \"" + path + "\".")
            return
                    
        #bitmaps.ShowBitmap(orig)
        
        doodleObj[c4d.DOODLEOBJECT_IMAGE] = orig            
        #Error: __setitem__ expected c4d.BaseList2D, not c4d.bitmaps.BaseBitmap
        
        c4d.EventAdd()
      
    if __name__=='__main__':
        main()
      
    
    


  • On 31/07/2014 at 10:53, xxxxxxxx wrote:

    doodleObj[c4d.DOODLEOBJECT_IMAGE] takes a doodleImageObject object. Not a bitmap.
    But unless it's been changed recently (which I doubt). We don't have access to that in the C++ or Python SDK's.
    https://plugincafe.maxon.net/topic/4090/3621_is-it-possible-doodle--plugin-&KW=Doodle&PID=14754#14754

    The only way to draw things on the screen like that is with a plugin using the Draw() method.

    -ScottA



  • On 01/08/2014 at 00:58, xxxxxxxx wrote:

    Thanks. Draw() sounds like a good option.
    Can I display image files using Draw and can I then set transparency of that image?

    -Pim



  • On 01/08/2014 at 08:51, xxxxxxxx wrote:

    I'm not sure about transparency. I've never tried it. But we can use Alphas.
    We have to set them up as copies of the images. And the code gets kind of long just to display a couple of images with Alpha's on them. But just displaying images without Alpha's is fairly simple.
    Their is also the Blit() method. Which is another image drawing method.
    That one might work better for image transparencies. But I'm not sure.

    I have a Python example on my plugin site called "DrawImageTagR13++" that draws images to the screen.
    https://sites.google.com/site/scottayersmedia/plugins
    But I didn't set up the Alpha code in it. I do most of my image drawing stuff in C++ and I basically just did a quick and dirty port of my C++ version. Without the Alpha code.
    There might be a discussion about it in the Python forum archives though. If I remember correctly. I think I had trouble with the Alphas. And there might be some code posted by Yannick about them.
    I seem to recall that he helped me with them.

    -ScottA

    *Edit:
    I just updated that plugin example so that the Alpha channel is used on the image if the object is at 0,0,0. And I left the the other image to not use an Alpha channel if the object is moved.
    That way you can see the difference between using, or not using, the Alpha option.



  • On 03/08/2014 at 12:38, xxxxxxxx wrote:

    Thanks, I love your example.



  • On 06/08/2014 at 01:43, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    *Edit:
    I just updated that plugin example so that the Alpha channel is used on the image if the object is at 0,0,0. And I left the the other image to not use an Alpha channel if the object is moved.
    That way you can see the difference between using, or not using, the Alpha option.

    I did some investigation and indeed you set the alpha channel value and not the transparency.
    You set the alpha using the code below, but is that needed if the image contains an alpha?
    Setting the alpha value did not seem to change the displayed image?

    for y in xrange(height) :
       for x in xrange(width) :
          r,g,b = bmp1.GetPixel(x, y)
          bmp1.SetAlphaPixel(self.alpha, x, y, r)	#using 0 or 255 does not change anything?	
    

    I also tried using bd.SetTransparency(-255), but as mentioned on this forum in other posts, transparency is not handled well.



  • On 06/08/2014 at 08:19, xxxxxxxx wrote:

    My Bad.
    I guess it turns out that if you are displaying an image that has an Alpha channel. Then you don't have to do that whole copy and for() looping stuff.

    When I started this drawing stuff in C++  I wanted to use the TextAt option that lets us display words on the screen. And that one does need to have the Alpha created with code like in my example. And I just assumed that images worked the same way.

    I've never attempted a fading effect. But alpha's probably won't work for that type of effect.
    If I get a change to investigate it. I'll let you know if I find a solution.

    -ScottA



  • On 06/08/2014 at 17:13, xxxxxxxx wrote:

    OK. I spent some time trying out the various bitmap and clipmap functions.
    And it looks like the transparency can be set using a new clipmap that get's the data from your source image.
    There's a strange bug in it though. For some reason once it hits 50% the image goes full transparent.😠
    I'm not sure it's this is bug. Or I'm trying to make it do something it wasn't designed to do.

    Here is the entire code for a tag plugin. Minus the other files (.res, .str, .etc)

      
    #This is an example of changing an image's pixel and alpha values  
    #We can use a new bitmap instance to change the color & alpha values separately  
    #Or...We can use a new clipmap to set the alpha value for the entire image  
    #In either case. We must create a new bitmap or clipmap because we can't change the source image without physically saving it  
    #Use the proper DrawTexture() function at the end of the Draw() method. Depending on which method you're using  
      
    import c4d,os  
    from c4d import plugins, bitmaps, documents  
      
    PLUGIN_ID = 1000003  #TESTING ID# Only!!!  
      
    #This variable sets the amount of transparency  
    #NOTE: for some reason if I go below 51 the image goes full transparent...BUG??  
    transAmount = 51  
      
    class DrawImage(plugins.TagData) :  
      
      bm1 = bitmaps.BaseBitmap()        #The source image  
      newbm = bitmaps.BaseBitmap()      #A new empty bitmap image we will construct from scratch using the source image data  
      newcm = c4d.bitmaps.GeClipMap()   #A new empty clipmap image we will construct from scratch using the source image data  
        
      def Init(self, tag) :  
          dir, file = os.path.split(__file__)  
          imgPath = os.path.join(dir, "res", "image1.psd")    #The path to the res folder and the image to use  
          self.bm1.InitWith(imgPath)   
      
          #Init the new bitmap using the source image dimensions   
          width =  self.bm1.GetBh()  
          height = self.bm1.GetBw()          
          self.newbm = c4d.bitmaps.BaseBitmap()  
          self.newbm.Init(width,height,32)  
            
          #Init the new clipMap using the source image dimensions  
          self.newcm.Init(width,height,32)   
        
          return True  
      
      def Draw(self, tag, op, bd, bh) :  
        
          doc = documents.GetActiveDocument()   
          bd.SetMatrix_Screen()  
        
          ##### This is a little trick to fix the Z depth bug #####  
          bd.DrawLine2D(c4d.Vector(0, 0, 0), c4d.Vector(0, 0, 0))     #Draw a line with a zero length<---This is our dummy object  
          bd.SetDepth(True)                                           #This fixes drawing problems when using 2D functions  
          #################################      
        
          #Get the source image's dimensions  
          width =  self.bm1.GetBh()  
          height = self.bm1.GetBw()      
      
          #Get the alpha channel for both the original image  
          bm1AlphaChannel = self.bm1.GetInternalChannel()  
            
          #Create an alpha channel for new bitmap image (it doesn't have one when we create one from scratch)  
          newbmAlphaChannel = self.newbm.GetInternalChannel()             #Get at the RGBA channels of the bitmap copy  
          newbmAlphaChannel = self.newbm.AddChannel(True, False)          #Add a channel and assign it to a variable so we can use it later on   
            
      
          #Get the color & alpha values from the bm1 bitmap  
          #And copy the values to the newbm bitmap  
          for y in xrange(height) :  
              for x in xrange(width) :              
                  #Copy the colors and alpha values to the new bitmap image  
                  r,g,b = self.bm1.GetPixel(x, y)            
                  alpha = self.bm1.GetAlphaPixel(bm1AlphaChannel, x, y)  
                  self.newbm.SetPixel(x,y, r,g,b)    
                  self.newbm.SetAlphaPixel(newbmAlphaChannel, x, y, alpha)                  
                    
                  #Change the colors and alpha values to the new bitmap image                 
                  self.newbm.SetPixel(x,y, r+0,g+0,b+0)  
                  self.newbm.SetAlphaPixel(newbmAlphaChannel, x, y, transAmount)  
                    
                  #Use the new clipMap SetPixelRGBA() function to set the transparency for the image  
                  self.newcm.BeginDraw()  
                  self.newcm.SetPixelRGBA(x,y, r,g,b, transAmount)  
                  self.newcm.EndDraw()  
      
      
          #Use these to move the image around in scene editor window  
          xpos = 20       #The X screen location of the left upper corner of the image  
          ypos = 50       #The Y screen location of the left upper corner of the image  
      
          #Set the actual vector positions for the four point plane object that holds the bitmap  
          padr = [  
          (c4d.Vector(xpos,ypos,0)),                          #upper left corner  
          (c4d.Vector(xpos+width,ypos,0)),                    #upper right corner  
          (c4d.Vector(xpos+width,ypos+height,0)),             #lower right corner  
          (c4d.Vector(xpos,ypos+height,0))                    #lower left corner  
          ]      
      
          cadr = [(c4d.Vector(1,1,1)),(c4d.Vector(1,1,1)),(c4d.Vector(1,1,1)),(c4d.Vector(1,1,1))]    #Array with color vectors   
          vnadr = [(c4d.Vector(0,0,1)),(c4d.Vector(0,0,1)),(c4d.Vector(0,0,1)),(c4d.Vector(0,0,1))]   #Array with normals of vertices   
          uvadr = [(c4d.Vector(0,0,0)),(c4d.Vector(1,0,0)),(c4d.Vector(1,1,0)),(c4d.Vector(0,1,0))]   #Array with texture UVs  
            
          #Use this version to draw the new image with the changed color & alpha values individually  
          #bd.DrawTexture(self.newbm,padr,cadr,vnadr,uvadr,4,c4d.DRAW_ALPHA_FROM_IMAGE,c4d.DRAW_TEXTUREFLAGS_0)  
            
          #Use this version to set the transparency value for the entire image  
          nb = self.newcm.GetBitmap()  
          bd.DrawTexture(nb,padr,cadr,vnadr,uvadr,4,c4d.DRAW_ALPHA_FROM_IMAGE,c4d.DRAW_TEXTUREFLAGS_0)  
            
          return True  
      
    if __name__ == "__main__":  
      path, file = os.path.split(__file__)  
      bmp = bitmaps.BaseBitmap()  
      bmp.InitWith(os.path.join(path, "res", "icon.tif"))  
      plugins.RegisterTagPlugin(id = PLUGIN_ID, str = "drawimg", g = DrawImage, description = "drawimg", icon = bmp, info = c4d.TAG_EXPRESSION|c4d.TAG_VISIBLE)
    

    -ScottA



  • On 07/08/2014 at 02:55, xxxxxxxx wrote:

    Again thanks for the answer and the example.
    I implemented it and started testing.

    - to remove issues with resource naming, etc. I change the RegisterTagPlugin call.
    I made description empty  (description = "").

        #plugins.RegisterTagPlugin(id = PLUGIN_ID, str = "drawimg", g = DrawImage, description = "drawimg", icon = bmp, info = c4d.TAG_EXPRESSION|c4d.TAG_VISIBLE)
        plugins.RegisterTagPlugin(id = PLUGIN_ID, str = "drawimg", description = "", g = DrawImage, icon = bmp, info = c4d.TAG_EXPRESSION|c4d.TAG_VISIBLE)  
    

    - I got an error when the tag code was "runned" again.
    It is a tag, so it is run very often.
    I now only create a new alpha when there is none.

            #Create an alpha channel for new bitmap image (it doesn't have one when we create one from scratch)
            newbmAlphaChannel = self.newbm.GetInternalChannel()             #Get at the RGBA channels of the bitmap copy
            
            if (newbmAlphaChannel == None) : 
                newbmAlphaChannel = self.newbm.AddChannel(True, False)          #Add a channel and assign it to a variable so we can use it later on
    

    - again, because it is a tag, it is running often.
    So when using a large image file (e.g. 400x400), the system gets very slow.
    I tried to test whether the image was already drawn, but I did not succeed.
    It looks like the image must be redrawn on every loop?

    - I also did some testing using the depth of the image file.
    In your case it is always 32.
    Using below code did not seem to do it, further study is required.

    It could be that bits is not the same as depth.

            bits = self.bm1.GetBt()
            self.newbm = c4d.bitmaps.BaseBitmap()
            #self.newbm.Init(width,height,32)
            self.newbm.Init(width,height,bits)
    

    - and like you said, transparency does not seem to be seamless.
    Have a look at the doodle option.

    If things are better in c++, let's switch over to c++.

    -Pim



  • On 07/08/2014 at 07:31, xxxxxxxx wrote:

    It shouldn't matter that it's a tag. The Draw() method is designed to draw continuously.
    But if it's running slow then that probably means that I've got some code in the wrong place.
    The only time I've seen Draw() slow C4D down is when something is being created(initialized) in it.
    So I've probably got something in the Draw() method that shouldn't be in there.

    Like I said. This is just a wild guess on my part.
    I've never tried to fade a drawn image like this. So the slowness and not able to set the transparency below 51 problem is probably something I'm doing incorrectly.

    The Doodle object is unfortunately not an option. Because we have no access to it.
    Not even in C++.

    Here's an example of me putting the code in the Draw() method that will probably slow it down.
    In my code example. Take the newbmAlphaChannel = self.newbm.AddChannel(True, False) code out of the Draw() method and put it in the Init() method.
    Like this:

        def Init(self, tag) :  
        
          #This variable sets the amount of transparency  
          #NOTE: for some reason if I go below 51 the image goes full transparent...BUG??      
          tag[10001] = 255  
        
          dir, file = os.path.split(__file__)  
          imgPath = os.path.join(dir, "res", "image1.psd")    #The path to the res folder and the image to use  
          self.bm1.InitWith(imgPath)   
      
          #Init the new bitmap using the source image dimensions   
          width =  self.bm1.GetBh()  
          height = self.bm1.GetBw()          
          self.newbm = c4d.bitmaps.BaseBitmap()  
          self.newbm.Init(width,height,32)          
          newbmAlphaChannel = self.newbm.AddChannel(True, False)          
            
          #Init the new clipMap using the source image dimensions  
          self.newcm.Init(width,height,32)  
            
          return True
    

    As you can see. It's very easy to put the wrong things in the Draw() method. Which will slow down C4D.
    Putting things in the Init() method so that they only get called once usually solves any slowness problems.

    -ScottA

    *Edit:
    The nested for() loops are what really slows the code down the most when using bigger images.
    Moving that code to the Init() is still slow when the scene is changed.
    Unfortunately. I don't know any other way to do this. This is the way Matthias and Yannick showed me how to do it. But clearly it's a resource hog with large images.
    Maybe someone else knows a better way?



  • On 07/08/2014 at 14:17, xxxxxxxx wrote:

    Ok, so draw() draws continuously. Sound logic to me when you think about it.
    I will try your suggestion and get back.

    PS Thanks a lot for your website with all the great examples.
    Especially the pyposelibrary!

    *Edit.
    No noticeable changes.
    An image of 32x32 is ok, but an image of 256x256 makes it very very slow.


Log in to reply