Hello @dunhou,
Thank you for reaching out to us and pointing this out. There is a bug in the Python bindings of maxon.AssetInterface.GetAssetUrl
, there is nothing you can do about it. I have added bug report for it, it will be fixed in an upcoming release.
In the meantime, you can also use maxon.AssetDescriptionInterface.GetUrl()
as a workaround. See my example at the end of the post for details. I would also like to stress again, that there is no downloading to be done from your side. So, unless you want to use the texture asset in a material or read its pixel data, the URL will not be of much use to you. As the URLs provided by both methods will be in a scheme that only is understood by the Cinema 4D APIs, the ramdisk
and asset
schemes respectively.
Cheers,
Ferdinand
"""Demonstrates how to circumvent the Python API bug in AssetInterface.GetUrl by using
AssetDescriptionInterface.GetUrl as a temporary replacement.
The URLs returned by these two methods are NOT the same, AssetInterface returns the asset URL in the
asset scheme, while AssetDescriptionInterface returns the URL of the physical location of the asset.
Usually users should not be poking around with the physical/raw asset Url and instead use the
asset scheme abstraction of it, but for now this will fix this problem. See [1] for details on the
subject.
The raw asset URL will either be a file scheme or ramdisk scheme URL. The former would be something
like "file://C:/MyAssetDB/1/asset.png" while the latter is a specialized URL scheme from the asset
API which allows you to treat files that are still on some server on the internet as if they were
already on your machine. Cinema 4D will load the content as soon as one attempts to access it.
I already stated this in the last posting, but there is no "downloading" to be done from your side.
You just access stuff and do not really have to care about how.
References:
[1]: https://github.com/PluginCafe/cinema4d_cpp_sdk_extended/blob/master/plugins/example.assets/source/asset_api_examples/examples_metadata.cpp#:~:text=AccessAssetDescriptionData
"""
import c4d
import maxon
import itertools
doc: c4d.documents.BaseDocument # The active document.
def GetTextureInBrowser():
"""
"""
# The asset ID you did provide was not for a media (texture) asset, but some kind of c4d file
# based asset (I did not check what it was exactly).
# sourceId: maxon.Id = maxon.Id("file_d0a26639c950371a")
# The "A019.TIF" texture in the Textures/Surfaces/Brick Wall category.
assetId: maxon.Id = maxon.Id("file_d501e4ea3ca49737")
# This was all correct, I just condensed it a bit.
repository: maxon.AssetRepositoryRef = maxon.AssetInterface.GetUserPrefsRepository()
asset: maxon.AssetDescription = repository.FindLatestAsset(
maxon.AssetTypes.File(), assetId, maxon.Id(), maxon.ASSET_FIND_MODE.LATEST)
name: str = asset.GetMetaString(maxon.OBJECT.BASE.NAME, maxon.Resource.GetCurrentLanguage(), "")
# Because AssetInterface.GetUrl() is broken, we are using AssetDescriptionInterface.GetUrl() as
# a replacement. There is however a difference between these two, and the one we are retrieving
# here is the raw asset Url. This will work nonetheless in 99.9% of the cases, but you should
# only use this in this form until we fix the bug. See see [1] for details on the asset data
# model.
url: maxon.Url = asset.GetUrl()
fileName: str = url.GetUrl()
# Create a material, link the texture asset in the color channel of the material, and insert the
# material into the document.
material: c4d.BaseMaterial = c4d.BaseMaterial(c4d.Mmaterial)
shader: c4d.BaseShader = c4d.BaseShader(c4d.Xbitmap)
if None in (material, shader):
raise MemoryError("Could not allocated material or shader.")
material.InsertShader(shader)
doc.InsertMaterial(material)
shader[c4d.BITMAPSHADER_FILENAME] = fileName
material[c4d.MATERIAL_COLOR_SHADER] = shader
# Load the asset into a bitmap.
bitmap: c4d.bitmaps.BaseBitmap = c4d.bitmaps.BaseBitmap()
if bitmap.InitWith(fileName)[0] != c4d.IMAGERESULT_OK:
raise RuntimeError(f"Could not load bitmap from '{fileName}'.")
# Iterate over the top left corner 5x5 pixel grid in the bitmap to read the pixels.
rangeFive: tuple = tuple(range(5))
for x, y in itertools.product(rangeFive, rangeFive):
print (f"Pixel at {(x, y)} = {bitmap[x, y]}")
# Load the image into the Picture viewer.
c4d.bitmaps.ShowBitmap(bitmap)
# Push and update event to Cinema 4D.
c4d.EventAdd()
if __name__ == '__main__':
GetTextureInBrowser()