stepalibre
Alibre Super User
The program processes what's included in the assembly. You can try GenAI with the current script, I can help later today if that doesn't work. Having a well thought-out features/requirements list goes a long way.
# ------------------------------------------------------------
# Assembly and Part Thumbnail Generator (IronPython 2.7)
# ------------------------------------------------------------
# This script:
# 1. Prompts the user for thumbnail size and output folder.
# 2. Detects whether the current document is an Assembly or Part.
# 3. Explores the assembly/subassemblies to:
# - Count identical parts (group by normalized name).
# - Save part/subassembly thumbnails as .jpg (unique only).
# 4. Creates an Excel workbook (Images_NET.xlsx) that embeds
# all images found in the chosen folder, placing each image
# inside a cell sized 300×300 pixels (approx).
# ------------------------------------------------------------
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():
"""
Detect if the object is an assembly or a part based on common attributes.
"""
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: Generate thumbnails for each Part/Subassembly
# ------------------------------------------------------------
def normalize_part_name(part_name):
"""
Remove unique identifiers like <1>, <2>, etc. from part names.
"""
return re.sub(r"<\d+>", "", part_name)
def clean_file_name(name):
"""
Remove invalid characters for Windows file names.
"""
invalid_chars = r'<>:"/\\|?*'
return re.sub('[{}]'.format(re.escape(invalid_chars)), '_', name)
def ListPartsInAssembly(assembly, save_path):
"""
Explore the assembly (and subassemblies), group identical parts,
count quantities, and save unique thumbnails for parts/subassemblies.
"""
parts_count = defaultdict(int)
saved_thumbnails = set() # Track saved thumbnails to avoid duplicates
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)
# Ensure thumbnails are unique by combining normalized name and geometry hash
geometry_hash = getattr(part, 'GeometryHash', id(part)) # Use a hash if available
unique_identifier = (cleaned_name, geometry_hash)
if unique_identifier 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(unique_identifier)
parts_count[normalized_name] += 1
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)
# Ensure thumbnails are unique by combining normalized name and geometry hash
geometry_hash = getattr(sub_asm, 'GeometryHash', id(sub_asm)) # Use a hash if available
unique_identifier = (cleaned_name, geometry_hash)
if unique_identifier 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(unique_identifier)
# Recurse into subassembly
process_assembly(sub_asm)
process_assembly(assembly)
# Print consolidated part list
print("\nConsolidated Part List:")
for part, quantity in parts_count.items():
print("- {}: {}".format(part, quantity))
# ------------------------------------------------------------
# STEP 4: Create Excel workbook and embed images with 300×300 cells
# ------------------------------------------------------------
def GenerateExcelWithImagesNET(image_directory):
"""
Creates an Excel workbook that lists all images in `image_directory`
in two columns:
1. Image Name
2. Embedded Image (300×300 px, approx)
"""
# Start Excel
excel = Excel.ApplicationClass()
excel.Visible = False # Change to True if you want to see Excel UI
# Create a new Workbook (which has one blank worksheet by default)
workbook = excel.Workbooks.Add()
sheet = workbook.Worksheets[1]
# Header cells
sheet.Cells[1, 1].Value2 = "Image Name"
sheet.Cells[1, 2].Value2 = "Image"
# Convert 300 px to points (approx: 1 px ≈ 0.75 pt at 96 DPI)
cell_size_points = 225
# Set entire column B's width so it can hold ~300 px
sheet.Columns("B").ColumnWidth = 42.5
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)
# Write file name in column A
sheet.Cells[row, 1].Value2 = filename
# 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, # Do not link to file
SaveWithDocument=MsoTriState.msoTrue, # Embed in the workbook
Left=left,
Top=top,
Width=cell_size_points,
Height=cell_size_points
)
row += 1
# Auto-fit Column A for better readability
sheet.Columns("A").AutoFit()
# Save workbook in the same folder
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':
# Generate a single thumbnail for this 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
)
else:
# Treat it as an Assembly
print("Current document is an Assembly; generating thumbnails.")
ListPartsInAssembly(obj, save_path)
# Finally, create the Excel workbook with 300×300 embedded images
GenerateExcelWithImagesNET(save_path)
Main()
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()
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):
global Assembly_Name
global Assembly_DNum
Assembly_Name = asm.Name
Assembly_DNum = asm.DocumentNumber
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"
sheet.Cells[1, 4].Value2 = "Purchased"
sheet.Cells[1, 5].Value2 = "Ready"
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, "{} {}.xlsx".format(Assembly_DNum, Assembly_Name))
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()
I'll see what I can do. I have a backlog growing, after ChatGPT Tasks released.So I've modified the above code so that the excel file name is 'Document Number' 'Assembly Name'.xlsx eg "H-2172 Counter Assembly.xlsx"
But I've reached my limit. I want to pull the drawing number for each part and attach it to the thumbnail name and then strip it out later to add into the excel file.
I can do the strip out bit but I can't work out where in the code to store the info and then retrieve it when the thumbnail is created.
Any help would be appreciated.
It may also need a default value if an empty field is not acceptable as fasteners, bearings, etc most likely won't have a drawing number.
drawing_number = asm.DocumentNumber
Current Code:
Python: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): global Assembly_Name global Assembly_DNum Assembly_Name = asm.Name Assembly_DNum = asm.DocumentNumber 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" sheet.Cells[1, 4].Value2 = "Purchased" sheet.Cells[1, 5].Value2 = "Ready" 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, "{} {}.xlsx".format(Assembly_DNum, Assembly_Name)) 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()
Exactly why I asked for a detailed requirement/feature list. My tools (GPTs in general) follow instructions. There are many things I suspect aren't covered since they aren't in the instructions. It's essentially a rules engine.Also FYI these scripts include suppressed parts and subassemblies instead of ignoring them and the thumbnails for those are broke.
I agree. It's a good proof of concept but there are many loose ends (if it is even the intended direction)Exactly why I asked for a detailed requirement/feature list. My tools (GPTs in general) follow instructions. There are many things I suspect aren't covered since they aren't in the instructions. It's essentially a rules engine.
I understand what you mean, but I don't know how to do it. My programming ability is fairly limited, I just did what came to mind.@albie0803 I'm confused why you need to store that info into the filename of the image just to try and retrieve it later. Just store it all info into a variable, return the variable from the function and pass the variable into the next function.
Also FYI these scripts include suppressed parts and subassemblies instead of ignoring them and the thumbnails for those are broke.
I'm trying to build a system to generate code for IronPython and C# for Alibre Script advanced API scripting.AFAIK it's not possible to check if occurrences are suppressed using stock Alibre Script. It will have to use the Alibre API functions for that.