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
    • Recent
    • Tags
    • Users
    • Register
    • Login

    How to export icons of asset

    Scheduled Pinned Locked Moved Cinema 4D SDK
    python20262024
    6 Posts 2 Posters 19 Views 2 Watching
    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.
    • DunhouD Offline
      Dunhou
      last edited by

      Hey community,

      I want to get icon of assets like Redshift Nodes or OM capsule(Axis Center). but I can't export or download them, at least that's what @ferdinand said before. Do we have some way to get those icons?

      I want to match icons and asset ids, so I can use them in pipeline, but a bit outside the c4d system.

      Cheers~
      DunHou

      import c4d
      import maxon
      import shutil
      
      def GetAssetDescription(mid: maxon.Id = maxon.Id("net.maxon.pattern.node.twod.blur")) -> maxon.AssetDescription:
          repository = maxon.AssetInterface.GetUserPrefsRepository()
      
          assetDescription = repository.FindLatestAsset(
              maxon.AssetTypes.File(), mid, maxon.Id(), maxon.ASSET_FIND_MODE.LATEST)
          if assetDescription is None:
              raise RuntimeError("Could not find the asset.")
      
          return assetDescription
      
      def IterateAssetMetadata():
          assetDescription = GetAssetDescription()
          icon = maxon.AssetUtilitiesInterface.GetAssetIcon(assetDescription)
          print(icon.GetUrl())
      
      if __name__ == "__main__":
          IterateAssetMetadata()
      

      https://boghma.com
      https://github.com/DunHouGo

      ferdinandF 1 Reply Last reply Reply Quote 0
      • ferdinandF Offline
        ferdinand @Dunhou
        last edited by ferdinand

        Hey,

        I am not quite sure I understand the question. In case this is related to your vector file request, let me preface this that internally my merge request for BaseBitmap::InitWithVectorFile is already pending. There are some technical discussions still going on about details of the MR, but a feature like this will come in one form or another. I have implemented this in C++ and the ported it back to Python, so that both APIs have this feature. The feature is targeting the next non-hotfix release after the next non-hotfix release (i.e., it will roughly arrive in Q3, and as an MRD you will have access to as soon as we start publishing tester builds for this release).

        regarding your question, I am not really sure what you are asking for. Let me try to clarify some things about icons in asset databases:

        • Icons for assets can change dynamically, the Dots Preset Asset Example I wrote a long time ago is a good example for this. So, caching icons can lead to stale icons.
        • Icons do not have to be necessarily expressed in an URL scheme that makes much sense without the Maxon API, e.g., you could encounter URLs such as c4d://[relative:///icon]/5159, which would be an asset that is referencing the Cinema API icon resource 5159, i.e., c4d.Ocube.
        • Generally, the raw asset database file scheme, while somewhat human readable, is not meant to be parsed by external tools, and the format can change without much notice. The only way to reliably parse these files is to use the Cinema and Maxon API, which will abstract away from any file format changes.

        So, if you want to parse asset database resources for icon data, you will need to have access to the Cinema and Maxon API. And even then, this can be very much non-trivial.

        Cheers,
        Ferdinand

        MAXON SDK Specialist
        developers.maxon.net

        DunhouD 1 Reply Last reply Reply Quote 0
        • DunhouD Offline
          Dunhou @ferdinand
          last edited by

          Hey @ferdinand ,

          This is also related to SVG to some extent. My ultimate goal is to export the required commands and corresponding icons for use in my menu plugin. As it is not a traditional C4D API, it needs to be saved as a local image/svg. I am not sure if this is feasible.

          Cheers~
          DunHou

          https://boghma.com
          https://github.com/DunHouGo

          ferdinandF 1 Reply Last reply Reply Quote 0
          • ferdinandF Offline
            ferdinand @Dunhou
            last edited by ferdinand

            Hm,

            I still do not really understand what you want to do. I suppose you want to support assets dragged into palettes as I have done below with a texture? Because that is the only way how I can bring the terms "asset", "command", and "icon" into a meaningful context.

            40b5df15-7d82-49a6-bb74-bdae7cf90549-image.png

            Most commands, as for example an explicitly implemented CommandData plugin or the CommandData wrapper created by Cinema 4D for a NodeData plugin such as ObjectData or TagData are static, i.e., their ID will never change.

            But Cinema 4D also creates commands dynamically. The Script Manger does this for example (exposde via c4d.GetDynamicScriptID). This might be something you are aware of, and which might have let you to assume that the Asset Browser does the same. Which is unfortunately not the case. The Asset Browser is using a non-public mechanism to create "commands" in palettes which are not really commands. So, you cannot CallCommand them. This little script will walk all commands for you and dump their name, icon, and ID.

            import c4d
            
            doc: c4d.documents.BaseDocument  # The currently active document.
            op: c4d.BaseObject | None  # The primary selected object in `doc`. Can be `None`.
            
            def main() -> None:
                """Called by Cinema 4D when the script is being executed.
                """
                command: c4d.plugins.BasePlugin
                for command in c4d.plugins.FilterPluginList(c4d.PLUGINTYPE_COMMAND, True):
                    name: str = command.GetName()
                    if not name:
                        continue
            
                    cid: int = command.GetID()
                    icon: c4d.BaseBitmap | None = c4d.bitmaps.InitResourceBitmap(cid)
                    if icon is None:
                        print(f"Found command with name '{name}', id {cid}, and no icon.")
                    else:
                        print(f"Found command with name '{name}', id {cid}, and an icon {icon}.")
            
            
            if __name__ == '__main__':
                main()
            

            This will contain:

            • Natively implemented commands ("My Light Manger", "Move")
            • Command wrappers for NodeData plugins ("My Object", "Cube")
            • Command wrappers for scripts ("My Script", "untitled 2")

            But it will not contain asset "commands" as the Asset Browser does not create real commands for the assets dragged into palettes but uses a non-public mechanism to trigger the assets when clicking on them. You can of course also export asset icons to some degree, but these are (a) not commands and (b) there are the hurdles in the way as expressed in my previous post.

            The command IDs discovered in this manner will also contain dynamically created commands such as the ones created by the Script Manager. So, using such a data source for a running instance of Cinema 4D is fine, but you cannot 'cache' such data as the command ID of the "unitled 2" script wrapper will change every time you restart Cinema 4D.

            Cheers,
            Ferdinand

            MAXON SDK Specialist
            developers.maxon.net

            DunhouD 1 Reply Last reply Reply Quote 0
            • DunhouD Offline
              Dunhou @ferdinand
              last edited by

              Ha, If only in terms of usage, I hope to export capsule icons that can be dragged to OM, save to disk, which I can read through regular code, not just limited to C4D.

              For example, my custom menu plugin has a settings dialog that is not based on C4D SDK, but I want to UI/UX it closer to C4D, so I want to obtain icon data for drawing.

              I hope this makes sense for my purpose.

              Cheers~
              DunHou

              https://boghma.com
              https://github.com/DunHouGo

              1 Reply Last reply Reply Quote 0
              • ferdinandF Offline
                ferdinand
                last edited by ferdinand

                Hm, okay. So, the situation is, you have a Cinema app/plugin, but since you use a non-native GUI, you must bridge the gap to your GUI and Cinema native image data.

                Please understand that using external UI kits is out of scope of support. Not only because it is a third party library, and because we refuse support for them, but also because we generally do not like it when plugins use other UI tool kits than the native one.

                With that being said:

                The script I have shown you above would be at least a way to cache command icons. You would have to add a mechanism to avoid having to write all bitmaps to disk every time, and to delete unused ones, because as I explained above, not all commands are static.

                For assets I would have to check myself or see some actual code. My base assumption would be that at least bitmap icons of assets can be loaded via BaseBitmap::Init (or InitWith in Python), even when the asset uses an exotic URL such as c4d://[relative:///icon]/5159. Because Python binds to BaseBitmap::Init which expects a cinema::Filename as the first argument, which will be internally converted to a maxon::Url and the Maxon API should then just figure out what you mean with c4d://[relative:///icon]/5159 and load the correct bitmap for you. In asset icons you might also encounter other exotic URL types such as ramdisk urls, zipped urls and more. But in all cases, at least in theory, the unpacking into a BaseBitmap should work from the Python API. For vector icons you will have to wait a bit.

                Cheers,
                Ferdinand

                PS: I am also not sure if serializing to disk is the best way. In C++ it would be for sure not be faster to write everything to disk and then read it back, instead of just converting data in memory. In slow, slow, slow Python, it might actually be faster to write stuff to disk and load it back using the C++ backend, than copying data in Python in memory.

                I.e., I mean something like this. But I did it there in the other direction, our GUI wraps alien image data. And not an alien GUI wraps our image data.

                MAXON SDK Specialist
                developers.maxon.net

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