OK here is what I am doing to lock up.
New file no template imperial.
3 pices of text named
Text Note 1
Text Note 2
Text Note 3
Only difference is text 2 and 3 are red.
Fair warning:
Hope this helps.
The script I’ve created locks up when it runs but here it is. If I run it as a test it says it’s going to change the 2 font styles to
3/32 arial opaque white unboxed
and
3/32 arial opaque red unboxed
while merging .
text note 3
into the red style.
When it runs it locks the pc.
Blockquote
-- coding: utf-8 --
Standardize TextNoteTypes to one font while preserving color variants.
Renames final canonical types like: “3/32 arial opaque red box”
FINAL VERSION — NO DRY RUN
from future import print_function
import clr
Revit API
clr.AddReference(“RevitAPI”)
from Autodesk.Revit.DB import (
FilteredElementCollector, Transaction, BuiltInParameter,
TextNoteType, TextNote, ElementId,
FailureProcessingResult, IFailuresPreprocessor
)
RevitServices
clr.AddReference(“RevitServices”)
from RevitServices.Persistence import DocumentManager
--------------------------
CONFIG
--------------------------
TARGET_FONT = “Arial”
WIDTH_ROUND = 4
--------------------------
Revit doc
--------------------------
uiapp = revit
uidoc = uiapp.ActiveUIDocument
doc = uidoc.Document
if not uidoc:
raise Exception(“Open a project first.”)
--------------------------
Failures
--------------------------
class SwallowFailures(IFailuresPreprocessor):
def PreprocessFailures(self, fa):
return FailureProcessingResult.Continue
def start_tx(name):
tx = Transaction(doc, name)
tx.Start()
opts = tx.GetFailureHandlingOptions()
opts.SetFailuresPreprocessor(SwallowFailures())
tx.SetFailureHandlingOptions(opts)
return tx
--------------------------
Name accessor
--------------------------
def get_type_name(t):
try:
p = t.get_Parameter(BuiltInParameter.SYMBOL_NAME_PARAM)
return p.AsString() or “”
except:
return “”
--------------------------
Helpers
--------------------------
def pval(t, bip, kind):
p = t.get_Parameter(bip)
if not p: return None
try:
if kind == “str”: return (p.AsString() or “”).strip().lower()
if kind == “int”: return p.AsInteger()
if kind == “dbl”:
v = p.AsDouble()
return None if v is None else round(v, 8)
except:
return None
return None
gcd for fractional inches (IronPython-safe)
def _gcd(a, b):
a = abs(int(a)); b = abs(int(b))
while b:
a, b = b, a % b
return a if a else 1
def format_fractional_inches(size_ft):
if size_ft is None:
return “”
inches = float(size_ft) * 12.0
num = int(round(inches * 256))
den = 256
g = _gcd(num, den)
num //= g
den //= g
whole = num // den
rem = num % den
if whole and rem:
return “{} {}/{}”.format(whole, rem, den)
elif whole and not rem:
return str(whole)
else:
return “{}/{}”.format(rem, den)
decode 0x00BBGGRR into (r,g,b)
def decode_color_int(val):
if val is None:
return (0,0,0)
r = val & 0xFF
g = (val >> 8) & 0xFF
b = (val >> 16) & 0xFF
return (r,g,b)
def color_name_or_rgb(rgb):
r,g,b = rgb
known = {
(255, 0, 0): “red”,
(255, 255, 255): “white”,
(0, 0, 255): “blue”,
(0, 0, 0): “black”,
(0, 255, 0): “green”,
(128, 128, 128): “gray”,
}
return known.get((r,g,b), “rgb({},{},{})”.format(r,g,b)).lower()
Find proper frame visibility BIP
FRAME_BIP = getattr(BuiltInParameter, “TEXT_FRAME_VISIBLE”, None)
if FRAME_BIP is None:
FRAME_BIP = getattr(BuiltInParameter, “TEXT_BOX_VISIBLE”, None)
def width_value(t):
v = pval(t, BuiltInParameter.TEXT_WIDTH_SCALE, “dbl”)
return None if v is None else round(v, WIDTH_ROUND)
--------------------------
Signature (font excluded, color included)
--------------------------
def make_signature(t):
return (
pval(t, BuiltInParameter.TEXT_SIZE, “dbl”),
pval(t, BuiltInParameter.TEXT_BACKGROUND, “int”),
pval(t, BuiltInParameter.LINE_COLOR, “int”),
pval(t, FRAME_BIP, “int”),
pval(t, BuiltInParameter.LINE_PEN, “int”),
width_value(t),
)
--------------------------
Naming per your spec:
3/32 arial opaque red box
--------------------------
def name_from_type(t):
size_ft = pval(t, BuiltInParameter.TEXT_SIZE, “dbl”)
size_str = format_fractional_inches(size_ft)
font_raw = pval(t, BuiltInParameter.TEXT_FONT, "str")
font_str = (font_raw or TARGET_FONT).lower()
bg_val = pval(t, BuiltInParameter.TEXT_BACKGROUND, "int")
bg_str = "opaque" if bg_val == 0 else "transparent"
rgb = decode_color_int(pval(t, BuiltInParameter.LINE_COLOR, "int"))
color_str = color_name_or_rgb(rgb)
frame_val = pval(t, FRAME_BIP, "int")
box_str = "box" if frame_val == 1 else "no box"
return "{} {} {} {} {}".format(size_str, font_str, bg_str, color_str, box_str)
def safe_rename_type(t, desired_name):
base = desired_name
name = base
suffix = 1
while True:
try:
p = t.get_Parameter(BuiltInParameter.SYMBOL_NAME_PARAM)
if p and p.AsString() != name:
p.Set(name)
return name
except:
suffix += 1
name = “{} ({})”.format(base, suffix)
--------------------------
Collect types + notes once
--------------------------
ALL_TYPES = list(FilteredElementCollector(doc).OfClass(TextNoteType))
ALL_NOTES = list(FilteredElementCollector(doc).OfClass(TextNote))
--------------------------
MAIN
--------------------------
def merge_text_types():
# Group by font-free signature
groups = {}
for t in ALL_TYPES:
sig = make_signature(t)
groups.setdefault(sig, []).append(t)
plan = []
for sig, items in groups.items():
# Find existing canonical with TARGET_FONT
canonical = None
for t in items:
f = pval(t, BuiltInParameter.TEXT_FONT, "str")
if f == TARGET_FONT.lower():
canonical = t.Id
break
# Otherwise duplicate one
if not canonical:
base = items[0]
base_name = get_type_name(base) or "text"
try:
new_id = base.Duplicate(base_name + " (std)")
except:
new_id = base.Duplicate("std clone")
new_t = doc.GetElement(new_id)
pf = new_t.get_Parameter(BuiltInParameter.TEXT_FONT)
if pf:
pf.Set(TARGET_FONT)
canonical = new_id
# These are TRUE duplicates of same color group
dups = [t.Id for t in items if t.Id != canonical]
plan.append((sig, canonical, dups))
# APPLY CHANGES
tx = start_tx("Standardize Text Types (No DryRun)")
try:
# 1) Retype notes
dup_to_canon = {}
for _, canon, dlist in plan:
for d in dlist:
dup_to_canon[d.IntegerValue] = canon
for n in ALL_NOTES:
tid = n.GetTypeId().IntegerValue
if tid in dup_to_canon:
n.ChangeTypeId(dup_to_canon[tid])
# 2) Delete true duplicates
for _, _, dlist in plan:
for d in dlist:
try:
doc.Delete(d)
except:
pass
# 3) Rename canonical types
for _, canon, _ in plan:
t = doc.GetElement(canon)
desired = name_from_type(t)
safe_rename_type(t, desired)
tx.Commit()
print("✓ Complete: font standardized, color preserved, types renamed.")
except Exception as ex:
tx.RollBack()
print("ERROR:", ex)
raise
--------------------------
Entry (NO DRY RUN)
--------------------------
if name == “main”:
merge_text_types()
Blockquote