Community
Fusion API and Scripts
Got a new add-in to share? Need something specialized to be scripted? Ask questions or share what you’ve discovered with the community.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Accessing Appearance Thumbnails

4 REPLIES 4
Reply
Message 1 of 5
nnikbin
282 Views, 4 Replies

Accessing Appearance Thumbnails

I would like to fill a DropDownCommandInput whose DropDownStyle is LabeledIconDropDownStyle with the names and thumbnails of all appearances available in a library.

 

Iterating through appearances and filling the names is simple but the difficult part is accessing the thumbnails of appearances.

 

I know that adsklib files are zip archives and appearance thumbnails are inside them as png resources. For example the following picture shows part of the contents of an adsklib file whose extension has changed to zip:

 

58.png

Is there any simple way to access these thumbnails and use them in a DropDownCommandInput?

Labels (1)
4 REPLIES 4
Message 2 of 5
kandennti
in reply to: nnikbin

Hi @nnikbin .

 

The icon is created by extracting the png file from the zip file.

 

# Description - Material Thumbnail Test
# Fusion360API Python script

import adsk.core
import adsk.fusion
import adsk.cam
import traceback

import re
import io
import zipfile
import pathlib
import shutil
from PIL import Image

_app = None
_ui = None
_handlers = []


def getAdsklibPaths() -> list:
    app: adsk.core.Application = adsk.core.Application.get()

    materialPath = pathlib.Path(
        app.executeTextCommand(f'Materials.MaterialLibraryPath'))

    adsklibPaths = [p for p in materialPath.iterdir()
                    if p.is_file() and p.suffix == '.adsklib']

    return adsklibPaths


def createIcon(zipPath: str):

    iconPaths = []
    basePath = getTempFolder()

    with zipfile.ZipFile(zipPath) as myzip:
        # get png file path
        paths = [f for f in myzip.namelist() if re.search('._png', f) != None]

        for path in paths:
            # open Byte stream
            with myzip.open(path) as img_file:
                img_bin = io.BytesIO(img_file.read())
                img = Image.open(img_bin)

                # get  material id
                path = pathlib.Path(path)
                id = re.sub(r'[\\|/|:|?|.|"|<|>|\|]', '-', str(path.parts[2]))
                iconPath = basePath / id

                # resize
                for width, height in [(32, 32), (16, 16)]:
                    # create icon folder
                    iconPath.mkdir(parents=True, exist_ok=True)

                    savePath = iconPath / f'{width}x{height}.png'
                    clone = img.copy()
                    img_resize_lanczos = clone.resize(
                        (width, height), Image.LANCZOS)

                    # save png
                    img_resize_lanczos.save(str(savePath))

            iconPaths.append(str(iconPath))

    return iconPaths


def getTempFolder():

    folder = pathlib.Path(__file__).parent/'temp'
    try:
        shutil.rmtree(folder)
    except:
        pass
    finally:
        folder.mkdir(exist_ok=True)

    return folder


class MyCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()

    def notify(self, args):
        try:
            global _handlers
            cmd = adsk.core.Command.cast(args.command)
            inputs = cmd.commandInputs

            onDestroy = MyCommandDestroyHandler()
            cmd.destroy.add(onDestroy)
            _handlers.append(onDestroy)

            # get adsklib files
            adsklibPaths = getAdsklibPaths()

            # Change to the library of your choice.
            imagePaths = createIcon(adsklibPaths[-1])

            dropdownInput2 = inputs.addDropDownCommandInput(
                'dropdown1',
                'test',
                adsk.core.DropDownStyles.LabeledIconDropDownStyle
            )
            dropdown2Items = dropdownInput2.listItems
            for idx, path in enumerate(imagePaths):
                dropdown2Items.add(
                    f'image{idx}',
                    False,
                    path
                )

        except:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


class MyCommandDestroyHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()

    def notify(self, args):
        adsk.terminate()


def run(context):
    try:
        global _app, _ui
        _app = adsk.core.Application.get()
        _ui = _app.userInterface

        cmdDef = _ui.commandDefinitions.itemById('Test2')
        if not cmdDef:
            cmdDef = _ui.commandDefinitions.addButtonDefinition(
                'Test2', 'Test', 'Test')

        global _handlers
        onCommandCreated = MyCommandCreatedHandler()
        cmdDef.commandCreated.add(onCommandCreated)
        _handlers.append(onCommandCreated)

        cmdDef.execute()

        adsk.autoTerminate(False)

    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

 

 

Unfortunately, DropDownCommandInput is too small to tell the difference.

1.png

 

It was very difficult for me.

Message 3 of 5
nnikbin
in reply to: nnikbin

Hi @kandennti 

Thank you so much for providing this nice code.

 

Unfortunately I have not been able to execute your code yet, because when I run it I receive the following error in Fusion 360 (I have python 3.9.1 and I have installed Pillow using pip)

 

ModuleNotFoundError: No module named 'PIL'

 

And VS Code shows:

 59.png

In addition I do not know how can I associate thumbnails with their appearance names.

I hoped there would be a solution at higher level.

Message 4 of 5
kandennti
in reply to: nnikbin

Message 5 of 5
nnikbin
in reply to: kandennti

@kandennti , You are awesome!

It seems there isn't any direct method at API level for this task.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report