How to export icons of asset
-
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~
DunHouimport 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() -
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::InitWithVectorFileis 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 resource5159, 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 -
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 -
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.

Most commands, as for example an explicitly implemented
CommandDataplugin or theCommandDatawrapper created by Cinema 4D for aNodeDataplugin such asObjectDataorTagDataare 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
CallCommandthem. 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
NodeDataplugins ("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 -
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 -
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(orInitWithin Python), even when the asset uses an exotic URL such asc4d://[relative:///icon]/5159. Because Python binds toBaseBitmap::Initwhich expects acinema::Filenameas the first argument, which will be internally converted to amaxon::Urland the Maxon API should then just figure out what you mean withc4d://[relative:///icon]/5159and load the correct bitmap for you. In asset icons you might also encounter other exotic URL types such asramdiskurls, zipped urls and more. But in all cases, at least in theory, the unpacking into aBaseBitmapshould work from the Python API. For vector icons you will have to wait a bit.Cheers,
FerdinandPS: 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.