SOLVED ShowBitmap() from website URL

Hi! plugincafe~
I try to get an image from website, And ShowBitmap() in C4D python.
This is my simple code:

import c4d
from c4d import gui, bitmaps

def main():
    img = "https://images.pexels.com/photos/10204089/pexels-photo-10204089.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"
    bmp = bitmaps.BaseBitmap()
    a,b = bmp.InitWith(img)
    print(a,b)
    if a == c4d.IMAGERESULT_OK:
        bitmaps.ShowBitmap(bmp)
    bmp.FlushAll()
    
# Execute main()
if __name__=='__main__':
    main()

Sometimes it can ShowBitmap() correctly like this:
01.jpg

Sometimes it's can show bitmap but the image is not loaded correctly:
02.jpg

And sometimes it's faild! And the InitWith() result is -6
Is there have some right way to show an image from the URL?

Hello @gheyret,

Thank you for reaching out to us. The reason why this is failing for you is due to you not caching the content you want to put into the BaseBitmap or alternatively not using a high-level-enough interface.

You can download the content of the image at your URL into either a temporary cache file or an in-memory file or use LoadFile and let Cinema 4D handle the rest. Find a simple example for each approach at the end of my posting.

When you are still running into problems, you should first try to see if you can access the whole file in principle. For example, with urllib3 which I am using in the code below.

Cheers,
Ferdinand

The result:
fc64eb70-9aa6-4be7-b243-bacc3f047474-image.png

The code:

"""Simple example for displaying three different images, referenced by an HTTP 
scheme url each, in the Picture Viewer.
"""

import c4d
import urllib3

def main():
    """Shows three approaches for how to display an image in the picture
    viewer that has a http(s) url scheme.
    """

    # Your image url, make sure to escape paths properly or to use raw strings 
    # as I do here.
    url = (r"https://images.pexels.com/photos/10204089/pexels-photo" +
           r"-10204089.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500")

    # Your and my forum avatar as png images.
    urlGheyret = (r"https://plugincafe.maxon.net/assets/uploads/profile/" + 
                  r"256-profileavatar-1631789551927.png")
    urlFerdinand = (r"https://plugincafe.maxon.net/assets/uploads/profile/" + 
                    r"1024-profileavatar.png")


    # The interface to make requests with in urllib3.
    poolManger = urllib3.PoolManager()

    # Approach I:

    # Attempt to connect to the url.
    response = poolManger.request('GET', url)
    if response.status != 200:
        raise RuntimeError(
            f"Could not access {url} with the code: {response.status}.")

    # Write the image to a local file.
    tempFile = "e:\\cache.tmp"
    with open(tempFile,"wb") as f:
        f.write(response.data)

    # Load the file as a BaseBitmap into the PictureViewer.
    bmp = c4d.bitmaps.BaseBitmap()
    result, isMoviev = bmp.InitWith(tempFile)

    if result != c4d.IMAGERESULT_OK:
        raise RuntimeError(
            "Could not initialize BaseBitmap with downloaded content.")

    # Show the bitmap.
    c4d.bitmaps.ShowBitmap(bmp)

    # We do not need to flush any bitmaps here, since the bitmap is being 
    # deallocated by scope and #ShowBitmap() makes a copy anyways.

    # Approach II:

    # Get your forum avatar.
    response = poolManger.request('GET', urlGheyret)
    if response.status != 200:
        raise RuntimeError(
            f"Could not access {url} with the code: {response.status}.")

    # Load the data from the response into a MemoryFileStruct and try to
    # initialize a bitmap with it.
    byteArray = bytearray(response.data)
    memFile = c4d.storage.MemoryFileStruct()
    memFile.SetMemoryReadMode(byteArray, len(byteArray))

    bmp = c4d.bitmaps.BaseBitmap()
    result, isMoviev = bmp.InitWith(memFile)

    if result != c4d.IMAGERESULT_OK:
        raise RuntimeError(
            "Could not initialize BaseBitmap with downloaded content.")

    # Show the bitmap.
    c4d.bitmaps.ShowBitmap(bmp)

    # Approach III:

    # Approach is a bit of an overstatement here, but internally, i.e., in
    # C++, we use the maxon API for such stuff, specifically the maxon:Url
    # type, which hides most of these downloading shenanigans away. And
    # while maxon::UrlInterface has already been exposed to Python as
    # maxon.UrlInterface, some tidbits are still missing, to make a more
    # low-level use of it. But we can call a high-level interface with a
    # url string (or Filename in terms of the classic API) and let the 
    # core do its thing. In this case it simply means calling LoadFile(). This
    # will however not expose the BaseBitmap, and instead just load the image
    # into the picture viewer. You will also get GUI events in some cases, as 
    # for example when you attempt to load the same url twice, as Cinema 4D
    # will ask you then if you really want to do that.

    # Load the image at #urlFerdinand into Cinema 4D, which will reflect as
    # it being loaded into the Picture Viewer.
    c4d.documents.LoadFile(urlFerdinand)


if __name__ == '__main__':
    main()

@ferdinand
Wow! you perfectly solved my problem!
Thank you! 🍻