Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Bodypaint Layer Bitmap [SOLVED]

    Scheduled Pinned Locked Moved PYTHON Development
    8 Posts 0 Posters 1.2k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H Offline
      Helper
      last edited by

      On 04/12/2014 at 02:16, xxxxxxxx wrote:

      Hello,

      I hope someone can help me with this!
      I can´t find an easy way to get a Bitmap out of a Bodypaint layer.
      I want to show those Layers on an Userarea, how can I do this?
      Additionally it seems to me that some bodypaint features are not available in Python?
      (at the bottom of the thread)

      What I´ve found out so far:

      if there is an active BB texture;

        
        tex = bodypaint.PaintTexture.GetSelectedTexture()  
        texturename = tex.GetFilename()  
        actlay = tex.GetActive()  
      

      if one have to load a new BB texture;

        
        #loaddialog  
        texturename =  c4d.storage.LoadDialog(type= c4d.FILESELECTTYPE_IMAGES, title="Load Hdr", flags=c4d.FILESELECT_LOAD)  
          
        #pass it to BB and make itself and the first layer active  
        settings = c4d.BaseContainer()  
        settings.SetFilename(c4d.LOADTEXTURE_FILENAME, texturename)  
        tex = bodypaint.SendPainterCommand(c4d.PAINTER_LOADTEXTURE, doc=doc, tex=None, bc=settings)  
        if not tex:return  
        lay = tex.GetFirstLayer()  
        tex.SetActiveLayer(lay, activatetexture=True, show=True)  
          
        #get the active layer  
        actlay = tex.GetActive()  
        print actlay, "layer"  
          
        #read layerdimensions  
        res =  actlay.GetBoundingBox()  
        xres = res['x2']   
        yres = res['y2']  
          
          
        #check attributes  
        print actlay[c4d.ID_BASELIST_NAME]  
        print actlay[c4d.ID_PAINTBITMAP_PREVIEW]  
        print actlay[c4d.ID_PAINTLAYER_BLEND]  
        print actlay[c4d.ID_PAINTLAYER_OPACITY]  
        print actlay[c4d.ID_PAINTLAYER_SHOW]  
          
        #add a new layer  
        print tex.AddLayerBmp(insertafter=ActLay, useundo=True, activate=True)  
          
        ######################################################################  
        #save the whole texture and pass it to the userarea is not what I want  
        ######################################################################  
        
        #orig = bitmaps.BaseBitmap()  
        #orig.InitWith(texturename)  
        #bitmaps.ShowBitmap(orig)  
        ######################################################################  
      

      -How to add a new layer on top of the last one? Why only insertafter?
      -[c4d.ID_PAINTBITMAP_PREVIEW]is always None?

      Thanks in advance
      Martin

      1 Reply Last reply Reply Quote 0
      • H Offline
        Helper
        last edited by

        On 04/12/2014 at 06:26, xxxxxxxx wrote:

        Hello,

        to get the raw content of a bitmap layer use GetPixelCnt()[URL-REMOVED]. Then you can copy this data into a BaseBitmap with SetPixelCnt()[URL-REMOVED]. You find examples how to use this functions in the painting examples in the C++ and Python SDK like SculptPaintBrush[URL-REMOVED].

          
          if actlay.IsInstanceOf(c4d.OBJECT_PAINTLAYERBMP) == True:  
                
              bmp = actlay.ToPaintLayerBmp()  
                    
              xres = bmp.GetBw()  
              yres = bmp.GetBh()  
              size = xres * yres  
                
              if size == 0:  
                  return  
                   
              colorMode = bmp.GetColorMode()     
                   
              # prepare storage  
              sq = storage.ByteSeq(None, size*c4d.COLORBYTES_RGB)  
                
              inc = 3  
                
              # read data  
              for row in xrange(yres) :  
                  offset = sq.GetOffset(row*(xres*inc))  
                  bmp.GetPixelCnt(0, row, xres, offset, colorMode, c4d.PIXELCNT_0)   
            
              # prepare bitmap  
              baseBitmap = bitmaps.BaseBitmap()  
              baseBitmap.Init(xres,yres,)  
            
              # write data  
              for row in xrange(yres) :  
                  offset = sq.GetOffset(row*(xres*inc))   
                  baseBitmap.SetPixelCnt(0, row, xres, offset, inc,colorMode, c4d.PIXELCNT_0)   
                
              # save  
              filename = c4d.storage.SaveDialog(title="Save preview")  
              baseBitmap.Save(filename,c4d.FILTER_TIF)  
        

        AddLayerBmp()[URL-REMOVED] should accept None as an argument for "insertafter". This is a bug. ID_PAINTBITMAP_PREVIEW returns a CUSTOMDATATYPE_BITMAPBUTTON[URL-REMOVED] which is currently not supported in Python.

        Best wishes,
        Sebastian


        [URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.

        1 Reply Last reply Reply Quote 0
        • H Offline
          Helper
          last edited by

          On 04/12/2014 at 07:00, xxxxxxxx wrote:

          Hello Sebastian,

          Thank you very much! Tremendous help as always!
          Just two hours ago I started with storage and bytesequence, but could´nt get it to work.
          I tried it with the new R16 function
          PaintLayerBmp.GetPixelCnt[URL-REMOVED]

            
            sq = storage.ByteSeq(None, xres*yres*inc)  
            ActLay.GetPixelCnt(0, 0, cnt, sq , dstmode= c4d.COLORMODE_RGB, flags= c4d.PIXELCNT_0)  
          

          But no luck! Do you have a working example ?

          AddLayerBmp() does not accept None.
          the resulting errormessage:
          TypeError: argument 1 must be c4d.modules.bodypaint.PaintLayer, not None
          Could you please give it a try?

          Thanks again
          Martin


          [URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.

          1 Reply Last reply Reply Quote 0
          • H Offline
            Helper
            last edited by

            On 04/12/2014 at 07:43, xxxxxxxx wrote:

            Hi Martin,

            Here a script that read a bitmap file, converts it to spherical and writes it back.

              
            import c4d, math
            from c4d import bitmaps, gui, storage
            from c4d import plugins
              
            #
            # spherical projection
            # y=y, x=x*cos(y)
            #
              
            BUTTON_ID_SELECT = 1001 
            MY_PATH = 1003
            MY_FILEDIMENSIONS = 1007
            MY_GOBUTTON = 100014
            MY_LINKBOX = 100015
              
            #global variables
            width = 0
            height = 0
            orig = 0   
            path = None
              
            Tolerance = 0.0000001
            masterRadius = 1
            derivedRadius = math.pi/2
                
            class YourDialog(gui.GeDialog) :
              
                def CreateLayout(self) : 
                   
                    self.SetTitle("Spherical Projection.")
              
                    self.GroupBegin(id=8000, flags=c4d.BFH_LEFT, cols=2)     #, rows=1)
                    self.GroupBorderSpace(10, 10, 10, 20)
                    
                    self.AddButton(BUTTON_ID_SELECT, flags=c4d.BFH_LEFT, initw=145, inith=30, name="Select Input file")
                    self.element = self.AddStaticText(id=MY_PATH, flags=c4d.BFH_MASK, initw=600, name="   ", borderstyle=c4d.BORDER_NONE)
                    self.element = self.AddStaticText(id=11004, flags=c4d.BFH_MASK, name="File Dimensions   ", borderstyle=c4d.BORDER_NONE)
                    self.element = self.AddStaticText(id=MY_FILEDIMENSIONS, flags=c4d.BFH_MASK, initw=600, name="   ", borderstyle=c4d.BORDER_NONE)
                    
                    self.AddSeparatorH(inith=80)
                    self.AddSeparatorH(inith=80)
              
                    self.AddButton(MY_GOBUTTON, c4d.BFV_MASK, initw=145, name="Go!")
              
                    self.GroupEnd()    
                        
              
                    return True
              
                def Command(self, id, msg) :
                
                    global width, height, orig, path, copy
                    
                    if (id == BUTTON_ID_SELECT) : 
                        path = storage.LoadDialog(type=c4d.FILESELECTTYPE_IMAGES, title="Please Choose a 32-bit Image:")
                        print "Path: ", path
                        
                        if (path != None) :
              
                            # Create and initialize selected image
                            orig = bitmaps.BaseBitmap()
                            if orig.InitWith(path)[0] != c4d.IMAGERESULT_OK:
                                gui.MessageDialog("Cannot load image \"" + path + "\".")
                                return
                            
                            # Get selected image infos
                            width, height = orig.GetSize()
                            #print "w+h: ", width, " - ", height
                            
                            bits = orig.GetBt()
                            #print "bt: ", bits
                        
                            self.SetString(MY_PATH, path)
                            self.SetString(MY_FILEDIMENSIONS, str(width)+"X"+str(height)+ "  Bits: "+str(bits))
             
                        # Create the copy and initialize it
                        copy = bitmaps.BaseBitmap()
                        copy.Init(width, height, bits)
              
                    #return True
                        
                    if (id == MY_GOBUTTON) : 
                        #c4d.EventAdd()
                        #self.Close()
              
                        #print "Gobutton path: ", path
                        if (path == None) :
                            gui.MessageDialog ("No Input File selected!")
                            return -1   
                        
                        ret = SphericalProjection(self.GetString(MY_PATH))
              
                        #print "Showbitmaps orig + copy"
                        bitmaps.ShowBitmap(orig)
                        bitmaps.ShowBitmap(copy)    
                        
                    return True
              
                def DestroyWindow(self) :        #Use this method to toggle the switch back to it's original off state
                    #obj[c4d.ID_USERDATA, 1]=0
                    c4d.EventAdd() 
              
            def SphericalProjection(path) :
              
                global width,height,orig
                
                c4d.gui.SetMousePointer(c4d.MOUSE_BUSY)
              
                if not path: return
                 
                height2 = height / 2
                width2 = width / 2
              
                
                for ix in range(width) :  
                    for iy in range(height) :
                        ycos = math.sin(math.radians(90.0/height2)*iy)
                        x = width2 + (width2-ix)*ycos
                        r,g,b = orig.GetPixel(int(x), iy)
                        copy.SetPixel(width-ix, iy, r, g, b) 
              
                return True
             
            if __name__=='__main__':
                
                dlg = YourDialog()
                dlg.Open(dlgtype= c4d.DLG_TYPE_ASYNC, defaultw=400)       #, xpos=600, ypos=500, defaultw=200, defaulth=200)
              
            
            
            1 Reply Last reply Reply Quote 0
            • H Offline
              Helper
              last edited by

              On 04/12/2014 at 08:53, xxxxxxxx wrote:

              Hello Martin,

              do you have any questions about the above example or the linked examples?

              As stated above, it is a bug that AddLayerBmp() does not accept None.

              Best wishes,
              Sebastian

              1 Reply Last reply Reply Quote 0
              • H Offline
                Helper
                last edited by

                On 04/12/2014 at 09:27, xxxxxxxx wrote:

                @Sebastian
                ahh,
                I see, I assigned the bug statement to the bitmapbutton for whatever reason.Thanks.

                The example is pretty clear.
                You just used the new GetPixelCnt method?
                Thanks!

                For the Limit list on support site, should I write an email that it´s not possible in Python, or will this restrictions registered automatically?

                @Pim
                Thanks!

                Best wishes
                Martin

                1 Reply Last reply Reply Quote 0
                • H Offline
                  Helper
                  last edited by

                  On 05/12/2014 at 01:50, xxxxxxxx wrote:

                  Hello,

                  just in case someone needs to know.
                  To avoid the layer insertion point bug, one can use GeListNode class commands like:

                    
                    #add a new layer  
                    newlayer = tex.AddLayerBmp(insertafter=actlay, useundo=True, activate=True)  
                    # as (insertafter= None) does not work a workaround to paste the new layer on top of the list  
                    newlayer.InsertBefore(tex.GetFirstLayer())  
                    #to avoid problems with previous loaded textures, set the first layer activ  
                    first = tex.GetFirstLayer()  
                    tex.SetActiveLayer(first, activatetexture=True, show=True)  
                  

                  @Sebastian
                  could you please explain what´s the difference between GetPixelCnt with a Bitmap and a BodyPaint layer?
                  I didn´t get it.

                  Thanks in advance
                  Martin

                  1 Reply Last reply Reply Quote 0
                  • H Offline
                    Helper
                    last edited by

                    On 05/12/2014 at 05:42, xxxxxxxx wrote:

                    Hello,

                    PaintLayerBmp.GetPixelCnt()[URL-REMOVED] and BaseBitmap.GetPixelCnt()[URL-REMOVED] are two different methods of two different classes. They are used pretty much the same way; the only difference is that BaseBitmap.GetPixelCnt() allows you to define a byte increment per pixel for the output buffer.

                    best wishes,
                    Sebastian


                    [URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.

                    1 Reply Last reply Reply Quote 0
                    • First post
                      Last post