What's new

Modify Existing Script to Automate Production Process

Helioc

Member
Good afternoon,


Once again, I need your help. I have the attached script that exports thumbnails of all parts from the assembly and sub-assemblies, and then creates a list in Excel with the drawing number (*part), quantity, and the photo again. I would like to add the location of each *part and the respective columns for the core properties, where I have detailed information for each part. Can you adjust this script?

Thanks
1759409100321.png
1759409204191.png
 
import clr
import sys
import re
import os
from collections import defaultdict

# Add references for .NET interop with Excel
clr.AddReference("System")
clr.AddReference("Microsoft.Office.Interop.Excel")

from Microsoft.Office.Interop import Excel

# Minimal MsoTriState "enum" to avoid referencing Microsoft.Office.Core
class MsoTriState:
msoFalse = 0
msoTrue = -1

# STEP 1: Prompt user for inputs (thumbnail size + save folder)
Win = Windows() # Provided by your CAD/automation environment
Option = [
['Thumbnail Size', WindowsInputTypes.Real, 100],
['Save Folder', WindowsInputTypes.Folder, None],
]
Values = Win.OptionsDialog("Image from Assembly", Option, 100)

if Values is None:
sys.exit()

dimension_thumb = Values[0]
save_path = Values[1]

# STEP 2: Detect if we have an Assembly or a Part
def detect_type():
try:
if hasattr(CurrentAssembly(), 'Parts'):
obj = CurrentAssembly()
obj_type = 'Assembly'
else:
raise Exception("Invalid assembly")
except:
if hasattr(CurrentPart(), 'Name'):
obj = CurrentPart()
obj_type = 'Part'
else:
raise Exception("Invalid part")
return obj, obj_type

# STEP 3: Count Parts
def normalize_part_name(part_name):
return re.sub(r"<\d+>", "", part_name)

def clean_file_name(name):
invalid_chars = r'<>:"/\\|?*'
cleaned_name = re.sub('[{}]'.format(re.escape(invalid_chars)), '_', name)
return cleaned_name + ';'

def count_parts_in_assembly(assembly):
parts_count = defaultdict(int)

def process_assembly(asm):
for part in asm.Parts:
part_name = part.Name if hasattr(part, 'Name') else str(part)
normalized_name = normalize_part_name(part_name)
parts_count[normalized_name] += 1

for sub_asm in asm.SubAssemblies:
process_assembly(sub_asm)

process_assembly(assembly)
return parts_count

# STEP 4: Generate Thumbnails
def generate_thumbnails_with_quantities(assembly, parts_count, save_path):
saved_thumbnails = set()

def process_assembly(asm):
for part in asm.Parts:
part_name = part.Name if hasattr(part, 'Name') else str(part)
normalized_name = normalize_part_name(part_name)
cleaned_name = clean_file_name(normalized_name)
quantity = parts_count[normalized_name]
cleaned_name_with_quantity = "{}{}".format(cleaned_name, quantity)

geometry_hash = getattr(part, 'GeometryHash', id(part))
unique_identifier = (cleaned_name_with_quantity, geometry_hash)

if unique_identifier not in saved_thumbnails:
thumbnail_path = os.path.join(save_path, cleaned_name_with_quantity + '.jpg')
part.SaveThumbnail(thumbnail_path, dimension_thumb, dimension_thumb)
saved_thumbnails.add(unique_identifier)

for sub_asm in asm.SubAssemblies:
sub_asm_name = sub_asm.Name if hasattr(sub_asm, 'Name') else str(sub_asm)
normalized_name = normalize_part_name(sub_asm_name)
cleaned_name = clean_file_name(normalized_name)
quantity = parts_count[normalized_name]
cleaned_name_with_quantity = "{}{}".format(cleaned_name, quantity)

geometry_hash = getattr(sub_asm, 'GeometryHash', id(sub_asm))
unique_identifier = (cleaned_name_with_quantity, geometry_hash)

if unique_identifier not in saved_thumbnails:
thumbnail_path = os.path.join(save_path, cleaned_name_with_quantity + '.jpg')
sub_asm.SaveThumbnail(thumbnail_path, dimension_thumb, dimension_thumb)
saved_thumbnails.add(unique_identifier)

process_assembly(sub_asm)

process_assembly(assembly)

# STEP 5: Create Excel workbook and embed images with 300×300 cells
def GenerateExcelWithImagesNET(image_directory):
excel = Excel.ApplicationClass()
excel.Visible = False

workbook = excel.Workbooks.Add()
sheet = workbook.Worksheets[1]

sheet.Cells[1, 1].Value2 = "Part Name"
sheet.Cells[1, 2].Value2 = "Image"
sheet.Cells[1, 3].Value2 = "Quantity"

cell_size_points = 75
sheet.Columns("B").ColumnWidth = 15

row = 2
valid_extensions = ('.jpg', '.jpeg', '.png', '.bmp', '.gif')

for filename in os.listdir(image_directory):
if filename.lower().endswith(valid_extensions):
image_path = os.path.join(image_directory, filename)

# Extract the part of the filename before the semicolon
file_name_before_semicolon = filename.split(';')[0]

# Extract the part of the filename after the semicolon
part_after_semicolon = filename.split(';')[1]

# Remove the file extension from the part after the semicolon
numeric_value_str = os.path.splitext(part_after_semicolon)[0]

# Convert the numeric value to an integer
numeric_value = int(numeric_value_str)

# Write file name in column A
sheet.Cells[row, 1].Value2 = file_name_before_semicolon

# Write numeric value in column C (if needed)
sheet.Cells[row, 3].Value2 = numeric_value

# Set the row height to match 300 px (~225 points)
sheet.Rows[row].RowHeight = cell_size_points

# Calculate the cell's top-left in points
left = sheet.Cells[row, 2].Left
top = sheet.Cells[row, 2].Top

# Insert the image as a shape that fits ~300×300 px
picture = sheet.Shapes.AddPicture(
Filename=image_path,
LinkToFile=MsoTriState.msoFalse,
SaveWithDocument=MsoTriState.msoTrue,
Left=left,
Top=top,
Width=cell_size_points,
Height=cell_size_points
)

row += 1

sheet.Columns("A").AutoFit()

excel_file_path = os.path.join(image_directory, "Images_NET.xlsx")
workbook.SaveAs(excel_file_path)
workbook.Close(False)
excel.Quit()

print("\nExcel file with images created at: {}".format(excel_file_path))

# MAIN EXECUTION
def Main():
obj, obj_type = detect_type()

if obj_type == 'Part':
print("Current document is a Part; generating thumbnail.")
cleaned_name = clean_file_name(obj.Name)
obj.SaveThumbnail(os.path.join(save_path, cleaned_name + ';1.jpg'), dimension_thumb, dimension_thumb)
else:
print("Current document is an Assembly; counting parts.")
parts_count = count_parts_in_assembly(obj)

print("Generating thumbnails with quantities.")
generate_thumbnails_with_quantities(obj, parts_count, save_path)

GenerateExcelWithImagesNET(save_path)

Main()
 
Python:
import clr
import sys
import re
import os
clr.AddReference("System")
clr.AddReference("Microsoft.Office.Interop.Excel")
from Microsoft.Office.Interop import Excel
class MsoTriState:
    msoFalse = 0
    msoTrue = -1
Win = Windows()
Option = [
    ['Thumbnail Size', WindowsInputTypes.Real, 100],
    ['Save Folder', WindowsInputTypes.Folder, None],
]
Values = Win.OptionsDialog("Image from Assembly", Option, 100)
if Values is None:
    sys.exit()
dimension_thumb = Values[0]
save_path = Values[1]
def detect_type():
    try:
        if hasattr(CurrentAssembly(), 'Parts'):
            obj = CurrentAssembly()
            obj_type = 'Assembly'
        else:
            raise Exception("Invalid assembly")
    except:
        if hasattr(CurrentPart(), 'Name'):
            obj = CurrentPart()
            obj_type = 'Part'
        else:
            raise Exception("Invalid part")
    return obj, obj_type
def normalize_part_name(part_name):
    return re.sub(r"<\d+>", "", part_name)
def clean_file_name(name):
    invalid_chars = r'<>:"/\\|?*'
    cleaned_name = re.sub('[{}]'.format(re.escape(invalid_chars)), '_', name)
    return cleaned_name
def get_part_location(part):
    """Extract the file location using the FileName property from Alibre API"""
    try:
        if hasattr(part, 'FileName'):
            return part.FileName
        else:
            return "N/A"
    except:
        return "N/A"
def get_part_properties(part):
    """Extract specific properties from a part using Alibre API"""
    properties = {}
    property_names = [
        'Comment',
        'CostCenter',
        'CreatedBy',
        'CreatedDate',
        'CreatingApplication',
        'DocumentNumber',
        'EngineeringApprovedBy',
        'Keywords',
        'Material'
    ] 
    for prop_name in property_names:
        try:
            if hasattr(part, prop_name):
                prop_value = getattr(part, prop_name)
                if prop_value is not None:
                    properties[prop_name] = str(prop_value)
                else:
                    properties[prop_name] = ""
            else:
                properties[prop_name] = ""
        except:
            properties[prop_name] = ""
    return properties
def collect_all_instances(assembly):
    """Collect all part instances (each occurrence gets its own entry)"""
    all_instances = []
    def process_assembly(asm):
        for part in asm.Parts:
            part_name = part.Name if hasattr(part, 'Name') else str(part)
            normalized_name = normalize_part_name(part_name)         
            instance_data = {
                'name': normalized_name,
                'full_name': part_name,
                'location': get_part_location(part),
                'properties': get_part_properties(part),
                'thumbnail_name': clean_file_name(normalized_name) + '.jpg'
            }
            all_instances.append(instance_data)
        for sub_asm in asm.SubAssemblies:
            sub_asm_name = sub_asm.Name if hasattr(sub_asm, 'Name') else str(sub_asm)
            normalized_name = normalize_part_name(sub_asm_name)
            instance_data = {
                'name': normalized_name,
                'full_name': sub_asm_name,
                'location': get_part_location(sub_asm),
                'properties': get_part_properties(sub_asm),
                'thumbnail_name': clean_file_name(normalized_name) + '.jpg'
            }
            all_instances.append(instance_data)         
            process_assembly(sub_asm)
    process_assembly(assembly)
    return all_instances
def generate_thumbnails(assembly, save_path):
    saved_thumbnails = set()
    def process_assembly(asm):
        for part in asm.Parts:
            part_name = part.Name if hasattr(part, 'Name') else str(part)
            normalized_name = normalize_part_name(part_name)
            cleaned_name = clean_file_name(normalized_name)
            if cleaned_name not in saved_thumbnails:
                thumbnail_path = os.path.join(save_path, cleaned_name + '.jpg')
                part.SaveThumbnail(thumbnail_path, dimension_thumb, dimension_thumb)
                saved_thumbnails.add(cleaned_name)
        for sub_asm in asm.SubAssemblies:
            sub_asm_name = sub_asm.Name if hasattr(sub_asm, 'Name') else str(sub_asm)
            normalized_name = normalize_part_name(sub_asm_name)
            cleaned_name = clean_file_name(normalized_name)
            if cleaned_name not in saved_thumbnails:
                thumbnail_path = os.path.join(save_path, cleaned_name + '.jpg')
                sub_asm.SaveThumbnail(thumbnail_path, dimension_thumb, dimension_thumb)
                saved_thumbnails.add(cleaned_name)
            process_assembly(sub_asm)
    process_assembly(assembly)
def GenerateExcelWithImagesNET(image_directory, all_instances):
    excel = Excel.ApplicationClass()
    excel.Visible = False
    workbook = excel.Workbooks.Add()
    sheet = workbook.Worksheets[1]
    property_columns = [
        'Comment',
        'CostCenter',
        'CreatedBy',
        'CreatedDate',
        'CreatingApplication',
        'DocumentNumber',
        'EngineeringApprovedBy',
        'Keywords',
        'Material'
    ]
    sheet.Cells[1, 1].Value2 = "Part Name"
    sheet.Cells[1, 2].Value2 = "Image"
    sheet.Cells[1, 3].Value2 = "File Location"
    for idx, prop_name in enumerate(property_columns):
        sheet.Cells[1, 4 + idx].Value2 = prop_name
    header_range = sheet.Range[sheet.Cells[1, 1], sheet.Cells[1, 3 + len(property_columns)]]
    header_range.Font.Bold = True
    header_range.Interior.Color = 0xD3D3D3
    header_range.WrapText = False
    cell_size_points = 75
    sheet.Columns("B").ColumnWidth = 15
    row = 2
    for instance in all_instances:
        sheet.Cells[row, 1].Value2 = instance['name']

        sheet.Cells[row, 3].Value2 = instance['location'] if instance['location'] else "N/A"       
        properties = instance['properties']
        for idx, prop_name in enumerate(property_columns):
            prop_value = properties.get(prop_name, "")
            sheet.Cells[row, 4 + idx].Value2 = prop_value

        sheet.Rows[row].RowHeight = cell_size_points

        thumbnail_path = os.path.join(image_directory, instance['thumbnail_name'])
        if os.path.exists(thumbnail_path):
            left = sheet.Cells[row, 2].Left
            top = sheet.Cells[row, 2].Top
            picture = sheet.Shapes.AddPicture(
                Filename=thumbnail_path,
                LinkToFile=MsoTriState.msoFalse,
                SaveWithDocument=MsoTriState.msoTrue,
                Left=left,
                Top=top,
                Width=cell_size_points,
                Height=cell_size_points
            )
        row += 1
    sheet.Columns("A").AutoFit()
    sheet.Columns("C").AutoFit()
    for idx in range(len(property_columns)):
        sheet.Columns[4 + idx].AutoFit()
    excel_file_path = os.path.join(image_directory, "Images_NET.xlsx")
    workbook.SaveAs(excel_file_path)
    workbook.Close(False)
    excel.Quit()
    print("\nExcel file with images created at: {}".format(excel_file_path))
def Main():
    obj, obj_type = detect_type()
    if obj_type == 'Part':
        print("Current document is a Part; generating thumbnail.")
        cleaned_name = clean_file_name(obj.Name)
        obj.SaveThumbnail(os.path.join(save_path, cleaned_name + '.jpg'), dimension_thumb, dimension_thumb)
        all_instances = [{
            'name': obj.Name,
            'full_name': obj.Name,
            'location': get_part_location(obj),
            'properties': get_part_properties(obj),
            'thumbnail_name': cleaned_name + '.jpg'
        }]
        GenerateExcelWithImagesNET(save_path, all_instances)
    else:
        print("Current document is an Assembly; collecting all instances.")
        all_instances = collect_all_instances(obj)
        print("Generating thumbnails.")
        generate_thumbnails(obj, save_path)
        print("Creating Excel with {} instances.".format(len(all_instances)))
        GenerateExcelWithImagesNET(save_path, all_instances)
Main()
 
"The script worked beautifully ;) Thank you very much. However, in the previous script, there were columns with quantities, and duplicate parts did not appear. Now duplicate parts show up, and the quantities are missing. Could you add those columns back?"

Thanks
 

Attachments

  • imagem_2025-10-03_082633780.png
    imagem_2025-10-03_082633780.png
    14.9 KB · Views: 8
Instances will overwrite each other, the same part used more than once can have different values (configurations). You could use Excel itself to create the table you want, counting up the quantities.
Python:
import clr
import sys
import re
import os
from collections import defaultdict
clr.AddReference("System")
clr.AddReference("Microsoft.Office.Interop.Excel")
from Microsoft.Office.Interop import Excel
class MsoTriState:
    msoFalse = 0
    msoTrue = -1
Win = Windows()
Option = [
    ['Thumbnail Size', WindowsInputTypes.Real, 100],
    ['Save Folder', WindowsInputTypes.Folder, None],
]
Values = Win.OptionsDialog("Image from Assembly", Option, 100)
if Values is None:
    sys.exit()
dimension_thumb = Values[0]
save_path = Values[1]
def detect_type():
    try:
        if hasattr(CurrentAssembly(), 'Parts'):
            obj = CurrentAssembly()
            obj_type = 'Assembly'
        else:
            raise Exception("Invalid assembly")
    except:
        if hasattr(CurrentPart(), 'Name'):
            obj = CurrentPart()
            obj_type = 'Part'
        else:
            raise Exception("Invalid part")
    return obj, obj_type
def normalize_part_name(part_name):
    return re.sub(r"<\d+>", "", part_name)
def clean_file_name(name):
    invalid_chars = r'<>:"/\\|?*'
    cleaned_name = re.sub('[{}]'.format(re.escape(invalid_chars)), '_', name)
    return cleaned_name
def get_part_location(part):
    """Extract the file location using the FileName property from Alibre API"""
    try:
        if hasattr(part, 'FileName'):
            return part.FileName
        else:
            return "N/A"
    except:
        return "N/A"
def get_part_properties(part):
    """Extract specific properties from a part using Alibre API"""
    properties = {}
    property_names = [
        'Comment',
        'CostCenter',
        'CreatedBy',
        'CreatedDate',
        'CreatingApplication',
        'DocumentNumber',
        'EngineeringApprovedBy',
        'Keywords',
        'Material'
    ]
    for prop_name in property_names:
        try:
            if hasattr(part, prop_name):
                prop_value = getattr(part, prop_name)
                if prop_value is not None:
                    properties[prop_name] = str(prop_value)
                else:
                    properties[prop_name] = ""
            else:
                properties[prop_name] = ""
        except:
            properties[prop_name] = ""
    return properties
def count_parts_in_assembly(assembly):
    """Count parts and collect their metadata"""
    parts_data = defaultdict(lambda: {
        'count': 0,
        'location': None,
        'properties': {}
    })
    def process_assembly(asm):
        for part in asm.Parts:
            part_name = part.Name if hasattr(part, 'Name') else str(part)
            normalized_name = normalize_part_name(part_name)         
            parts_data[normalized_name]['count'] += 1
            if parts_data[normalized_name]['location'] is None:
                parts_data[normalized_name]['location'] = get_part_location(part)
                parts_data[normalized_name]['properties'] = get_part_properties(part)
        for sub_asm in asm.SubAssemblies:
            sub_asm_name = sub_asm.Name if hasattr(sub_asm, 'Name') else str(sub_asm)
            normalized_name = normalize_part_name(sub_asm_name)       
            parts_data[normalized_name]['count'] += 1       
            if parts_data[normalized_name]['location'] is None:
                parts_data[normalized_name]['location'] = get_part_location(sub_asm)
                parts_data[normalized_name]['properties'] = get_part_properties(sub_asm)       
            process_assembly(sub_asm)
    process_assembly(assembly)
    return parts_data
def generate_thumbnails(assembly, parts_data, save_path):
    saved_thumbnails = set()
    def process_assembly(asm):
        for part in asm.Parts:
            part_name = part.Name if hasattr(part, 'Name') else str(part)
            normalized_name = normalize_part_name(part_name)
            cleaned_name = clean_file_name(normalized_name)
            if cleaned_name not in saved_thumbnails:
                thumbnail_path = os.path.join(save_path, cleaned_name + '.jpg')
                part.SaveThumbnail(thumbnail_path, dimension_thumb, dimension_thumb)
                saved_thumbnails.add(cleaned_name)
        for sub_asm in asm.SubAssemblies:
            sub_asm_name = sub_asm.Name if hasattr(sub_asm, 'Name') else str(sub_asm)
            normalized_name = normalize_part_name(sub_asm_name)
            cleaned_name = clean_file_name(normalized_name)
            if cleaned_name not in saved_thumbnails:
                thumbnail_path = os.path.join(save_path, cleaned_name + '.jpg')
                sub_asm.SaveThumbnail(thumbnail_path, dimension_thumb, dimension_thumb)
                saved_thumbnails.add(cleaned_name)
            process_assembly(sub_asm)
    process_assembly(assembly)
def GenerateExcelWithImagesNET(image_directory, parts_data):
    excel = Excel.ApplicationClass()
    excel.Visible = False
    workbook = excel.Workbooks.Add()
    sheet = workbook.Worksheets[1]
    property_columns = [
        'Comment',
        'CostCenter',
        'CreatedBy',
        'CreatedDate',
        'CreatingApplication',
        'DocumentNumber',
        'EngineeringApprovedBy',
        'Keywords',
        'Material'
    ]
    sheet.Cells[1, 1].Value2 = "Part Name"
    sheet.Cells[1, 2].Value2 = "Image"
    sheet.Cells[1, 3].Value2 = "Quantity"
    sheet.Cells[1, 4].Value2 = "File Location"
    for idx, prop_name in enumerate(property_columns):
        sheet.Cells[1, 5 + idx].Value2 = prop_name
    header_range = sheet.Range[sheet.Cells[1, 1], sheet.Cells[1, 4 + len(property_columns)]]
    header_range.Font.Bold = True
    header_range.Interior.Color = 0xD3D3D3
    header_range.WrapText = False
    cell_size_points = 75
    sheet.Columns("B").ColumnWidth = 15
    row = 2
    for part_name, data in parts_data.items():
        cleaned_name = clean_file_name(part_name)
        thumbnail_path = os.path.join(image_directory, cleaned_name + '.jpg')
        sheet.Cells[row, 1].Value2 = part_name
        sheet.Cells[row, 3].Value2 = data['count']
        sheet.Cells[row, 4].Value2 = data['location'] if data['location'] else "N/A"
        properties = data['properties']
        for idx, prop_name in enumerate(property_columns):
            prop_value = properties.get(prop_name, "")
            sheet.Cells[row, 5 + idx].Value2 = prop_value
        sheet.Rows[row].RowHeight = cell_size_points
        if os.path.exists(thumbnail_path):
            left = sheet.Cells[row, 2].Left
            top = sheet.Cells[row, 2].Top
            picture = sheet.Shapes.AddPicture(
                Filename=thumbnail_path,
                LinkToFile=MsoTriState.msoFalse,
                SaveWithDocument=MsoTriState.msoTrue,
                Left=left,
                Top=top,
                Width=cell_size_points,
                Height=cell_size_points
            )
        row += 1
    sheet.Columns("A").AutoFit()
    sheet.Columns("C").AutoFit()
    sheet.Columns("D").AutoFit()
    for idx in range(len(property_columns)):
        sheet.Columns[5 + idx].AutoFit()
    excel_file_path = os.path.join(image_directory, "Images_NET.xlsx")
    workbook.SaveAs(excel_file_path)
    workbook.Close(False)
    excel.Quit()
    print("\nExcel file with images created at: {}".format(excel_file_path))
def Main():
    obj, obj_type = detect_type()
    if obj_type == 'Part':
        print("Current document is a Part; generating thumbnail.")
        cleaned_name = clean_file_name(obj.Name)
        obj.SaveThumbnail(os.path.join(save_path, cleaned_name + '.jpg'), dimension_thumb, dimension_thumb)
        parts_data = {
            obj.Name: {
                'count': 1,
                'location': get_part_location(obj),
                'properties': get_part_properties(obj)
            }
        }
        GenerateExcelWithImagesNET(save_path, parts_data)
    else:
        print("Current document is an Assembly; counting parts.")
        parts_data = count_parts_in_assembly(obj)
        print("Generating thumbnails.")
        generate_thumbnails(obj, parts_data, save_path)
        print("Creating Excel with {} unique parts.".format(len(parts_data)))
        GenerateExcelWithImagesNET(save_path, parts_data)
Main()
 
Last edited:
The script is generating rows for assemblies and subassemblies, but we only need the individual part files. Can you update? ;)

Thanks
 

Attachments

  • imagem_2025-10-03_142438223.png
    imagem_2025-10-03_142438223.png
    31.6 KB · Views: 7
The script is generating rows for assemblies and subassemblies, but we only need the individual part files. And if possible, please also export the *parts as *STEP files to the same folder as the thumbnails :)
 

You can just delete what's not needed or modify the script. I recommend building sheets from the output with your changes rather than trying to get the perfect output from Alibre. It's more flexible.
 
Last edited:
It’s looking perfect ;) however, the parts are still grouped together, meaning the assemblies are also showing up. I only need the individual parts (parts). Could you fix this? In summary, I just need the complete parts from all assemblies. I really appreciate all the help you’re giving me."
 
Hello stepalibre,

please excuse my poor englisch.

your skript is very perfekt and helps much. But when the assembly load from pdm Server, the export as stepfile works, but the thumbnails and excel doesn't work.

I could really use your skript for my work. Would you like helpü me to repair the skipt?

best regards and thanks al lot
 
Last edited:
Has anyone successfully used this script with Alibre Design V29 (with or without PDM)?

Hi everyone,

I'm trying to use a script that exports STEP files, generates thumbnails, and creates an Excel report from an assembly.

The STEP export works correctly, including for parts stored in PDM. However, when the script reaches the thumbnail generation stage, it fails with the following error:

Exception: Part must be saved before generating a thumbnail.

The error occurs when the script calls SaveThumbnail(). As a result, the thumbnail generation stops and the Excel report is never completed.

I'm using Alibre Design V29 and PDM.

I'd like to know:

Has anyone successfully used this script with Alibre Design V29?
Does it work for you with PDM?
Does it work for you without PDM?
Are thumbnails and the Excel report generated correctly?
Have there been any API changes in V29 that affect thumbnail generation?

Since STEP export works correctly, the issue seems to be specifically related to thumbnail generation rather than file access.

Any feedback or testing results would be greatly appreciated.

Thanks!
 
SaveThumbnail() may use the file system to create the image or isn't supported in PDM. The image may need to be saved to a folder and uploaded to PDM separately. I am working on similar issues for previewing content locally and upload them separately for library content. Because running multiple instances of Alibre was removed in V28, you cannot access PDM in certain context.
 
SaveThumbnail is AlibreScript, I'm not using it with PDM. Alibre could confirm if it is supported.

Uploading content, working with class, querying properties is working without problems.

Improvements.

1. Save Files To - toggle for Windows and PDM should be determined when saving. SolidWorks cloud version has a button for saving locally or to the cloud.

2. Parts catalog, toolbox and other resources are installed locally.

My solution is a process that you run, save files locally, closed Alibre, then upload everything to PDM. As we discussed, the Alibre API is not feature complete with Alibre Design. With missing features solutions often aren't ideal. I would love to know how users are tackling this. Alibre have any recommendations.

The addon screens and output.

1781340113977.png

1781340135066.png

1781340146498.png

1781340159017.png

1781340168522.png

1781340175876.png

1781340186146.png
1781340194733.png

1781340201897.png
1781340215776.png
 
Last edited:
I don't see SaveThumbnail in the current (freshly downloaded V29) API docs. Maybe it is depreciated? There is SaveCurrentViewSnapshot for opened sessions - which might be able to be used.
 
C:\Program Files\Alibre Design 29.0.0.29060\Program\Addons\AlibreScript\AlibreScript.chm
1781463560645.png
 
Last edited:
There is SaveCurrentViewSnapshot for opened sessions - which might be able to be used.
I only use SaveCurrentViewSnapshot in .NET. SaveThumbnail is for assembly
Exception: Part must be saved before generating a thumbnail.

The error occurs when the script calls SaveThumbnail(). As a result, the thumbnail generation stops and the Excel report is never completed.
I didn't question that. Was the part saved and it still failed, try saving. The doc, "Saves a thumbnail of the assembly", but the exception mentions part?
Another factor:
1781464344776.png
I haven't tried AlibreScript in each option, or AlibreScript much in latest V29. Assembly and PDM work, takes far too much time, the process of running and then reviewing output.
 
Last edited:
I don't see SaveThumbnail in the current (freshly downloaded V29) API docs. Maybe it is depreciated? There is SaveCurrentViewSnapshot for opened sessions - which might be able to be used.
Are you talking about the AlibreX? I think SaveThumbnail() is AlibreScript only, but unsure of complete history.
 
Back
Top