{"id":106,"date":"2025-10-21T05:49:25","date_gmt":"2025-10-21T05:49:25","guid":{"rendered":"https:\/\/mywlca.altervista.org\/?p=106"},"modified":"2026-02-10T16:10:57","modified_gmt":"2026-02-10T16:10:57","slug":"batch-export-pdf-and-dwg-files-with-custom-names-on-dynamo","status":"publish","type":"post","link":"https:\/\/www.mywlca.blog\/?p=106","title":{"rendered":"Batch export PDF and DWG files with custom names on Dynamo"},"content":{"rendered":"\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"518\" data-id=\"126\" src=\"https:\/\/mywlca.wasmer.app\/wp-content\/uploads\/2025\/10\/01-general-scaled-1-1024x518.png\" alt=\"\" class=\"wp-image-126\" srcset=\"https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/01-general-scaled-1-1024x518.png 1024w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/01-general-scaled-1-300x152.png 300w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/01-general-scaled-1-768x389.png 768w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/01-general-scaled-1-1536x777.png 1536w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/01-general-scaled-1-2048x1036.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/figure>\n\n\n\n<p>When working with a Common Data Environment (CDE), the task of exporting multiple sheets from Autodesk\u202fRevit\u2014in both PDF and DWG formats\u2014can become a repetitive bottleneck. Add to that the requirement to adhere to precise file-naming conventions tied to sheet parameters, and the process becomes error-prone and inefficient.<br>Here, I present a streamlined workflow leveraging Dynamo (along with the custom nodes from the Crumple package) to automate the batch export of PDFs and DWGs with parameter-based filenames. The solution is scalable across projects, adaptable to varying conventions, and accessible to project teams.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Goal<\/h2>\n\n\n\n<p>The intent of this workflow is to <strong>automatically export<\/strong> both .PDF and .DWG versions of Revit sheets, while assigning <strong>custom\u2010formatted file names<\/strong> based on sheet parameters.<br>Key benefits:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Consistent naming aligned with CDE requirements<\/li>\n\n\n\n<li>Reduced manual intervention and risk of error<\/li>\n\n\n\n<li>A repeatable and project-agnostic routine usable by different teams within the organisation<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Preparation: PlanSet &amp; CSV List<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">PlanSet<\/h3>\n\n\n\n<p>Define and collect the set of sheets you intend to export. In Dynamo, the PlanSet will be decomposed into individual sheet elements for processing.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">CSV List<\/h3>\n\n\n\n<p>Before scripting, prepare a CSV file that lists the <strong>exact parameter names<\/strong> (including correct casing) that will be used for generating filenames. These parameters should already be filled in each sheet in the Revit project.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"154\" height=\"81\" src=\"https:\/\/mywlca.wasmer.app\/wp-content\/uploads\/2025\/10\/03-csv-1.png\" alt=\"\" class=\"wp-image-137\"\/><figcaption class=\"wp-element-caption\">CSV List of Parameters<\/figcaption><\/figure>\n\n\n\n<p>In Dynamo:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Import the PlanSet via the Crumple package, to isolate individual sheet elements<\/li>\n\n\n\n<li>Ensure you reference only sheets (not views) so that expected parameters exist and export nodes function correctly<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"461\" src=\"https:\/\/mywlca.wasmer.app\/wp-content\/uploads\/2025\/10\/02-planset-1024x461.png\" alt=\"\" class=\"wp-image-131\" srcset=\"https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/02-planset-1024x461.png 1024w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/02-planset-300x135.png 300w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/02-planset-768x346.png 768w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/02-planset.png 1240w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">PlanSet to Views<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Parameters: Defining &amp; Importing<\/h2>\n\n\n\n<p>Parameters may be either standard Revit parameters or Shared Parameters\u2014what matters is that the names in the CSV match exactly the parameter names in the model (case\u2010sensitive).<br>Workflow in Dynamo:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Import the CSV using <code>Data.ImportCSV<\/code>.<\/li>\n\n\n\n<li>Observe the resulting list structure: values may appear nested.<\/li>\n\n\n\n<li>Flatten the list (first level) so the parameter values align with the corresponding sheet elements.<\/li>\n<\/ol>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"356\" src=\"https:\/\/mywlca.wasmer.app\/wp-content\/uploads\/2025\/10\/04-listcreation-scaled-1-1024x356.png\" alt=\"\" class=\"wp-image-133\" srcset=\"https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/04-listcreation-scaled-1-1024x356.png 1024w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/04-listcreation-scaled-1-300x104.png 300w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/04-listcreation-scaled-1-768x267.png 768w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/04-listcreation-scaled-1-1536x534.png 1536w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/04-listcreation-scaled-1-2048x712.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Create Filenames<\/figcaption><\/figure>\n\n\n\n<p>This prepares the data for the next step: filename generation in Python.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Python: Filename Logic<\/h2>\n\n\n\n<p>In this script, we extract parameter values from each sheet element and assemble filenames using a chosen separator (such as <code>_<\/code> or <code>\u2013<\/code>). Many CDE systems rely on fixed separators to parse and categorise files, hence the explicit concatenation.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;no&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text\/x-python&quot;,&quot;theme&quot;:&quot;idea&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}\">import clr\n\n# Revit API &amp; Services\nclr.AddReference(&quot;RevitServices&quot;)\nfrom RevitServices.Persistence import DocumentManager\ndoc = DocumentManager.Instance.CurrentDBDocument\n\nclr.AddReference(&quot;RevitAPI&quot;)\nfrom Autodesk.Revit.DB import BuiltInParameter, StorageType\n\nclr.AddReference(&quot;RevitNodes&quot;)\nimport Revit\nclr.ImportExtensions(Revit.Elements)\n\n# --- INPUT ---\ninput_elements = IN[0]\n\n# Always unwrap\nif isinstance(input_elements, list):\n    elements = [UnwrapElement(el) for el in input_elements]\nelse:\n    elements = [UnwrapElement(input_elements)]\n\nparamRaw = IN[1]  # CSV list of parameter names\n\n# Clean CSV strings\nif not isinstance(paramRaw, list):\n    paramRaw = [paramRaw]\nparamNames = [str(x).strip().strip('&quot;') for x in paramRaw]\n\n# Built-in mapping\nbuiltin_map = {\n    &quot;Sheet Number&quot;: BuiltInParameter.SHEET_NUMBER,\n    &quot;Sheet Name&quot;: BuiltInParameter.SHEET_NAME,\n    &quot;Designed By&quot;: BuiltInParameter.SHEET_DESIGNED_BY\n}\n\nresults = []\n\nfor el in elements:\n    row = []\n    for name in paramNames:\n        val = None\n\n        # --- First try built-in ---\n        if name in builtin_map:\n            param = el.get_Parameter(builtin_map[name])\n            if param:\n                val = param.AsString()\n\n        # --- Then try shared\/project parameters ---\n        if val is None:\n            for p in el.Parameters:\n                try:\n                    if p.Definition.Name == name:\n                        st = p.StorageType\n                        if st == StorageType.String:\n                            val = p.AsString()\n                        elif st == StorageType.Double:\n                            val = p.AsValueString() or str(p.AsDouble())\n                        elif st == StorageType.Integer:\n                            val = p.AsValueString() or str(p.AsInteger())\n                        elif st == StorageType.ElementId:\n                            idVal = p.AsElementId()\n                            if idVal.IntegerValue &gt;= 0:\n                                elemRef = doc.GetElement(idVal)\n                                val = elemRef.Name if elemRef else str(idVal.IntegerValue)\n                            else:\n                                val = &quot;&quot;\n                        break\n                except Exception as e:\n                    val = &quot;Error: &quot; + str(e)\n\n        if val is None:\n            val = &quot;&quot;\n\n        row.append(val)\n    results.append(row)\n\nOUT = results\n<\/pre><\/div>\n\n\n\n<p><strong>Key checks<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Verify that the list of values is properly flattened (i.e., no nested lists).<\/li>\n\n\n\n<li>Confirm the correct order of parameters corresponds to your naming convention.<\/li>\n\n\n\n<li>Join the strings in the defined format to produce the final filename per sheet.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"548\" src=\"https:\/\/mywlca.wasmer.app\/wp-content\/uploads\/2025\/10\/05-flatten-1024x548.png\" alt=\"\" class=\"wp-image-134\" srcset=\"https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/05-flatten-1024x548.png 1024w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/05-flatten-300x161.png 300w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/05-flatten-768x411.png 768w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/05-flatten-1536x822.png 1536w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/05-flatten.png 1562w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Flatten Lists if needed<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Export: PDFs and DWGs via Crumple<\/h2>\n\n\n\n<p>Although Revit (from version 2022 onward) offers built-in batch export capabilities for PDF based on parameter naming, Dynamo lacks an out-of-the-box node for such functionality and DWG export is not natively supported. <\/p>\n\n\n\n<p>In the Export section of your script you will use:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>Revit.ExportToPdf<\/code><\/li>\n\n\n\n<li><code>Revit.ExportToDwg<\/code><\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"585\" src=\"https:\/\/mywlca.wasmer.app\/wp-content\/uploads\/2025\/10\/06-export-1024x585.png\" alt=\"\" class=\"wp-image-135\" srcset=\"https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/06-export-1024x585.png 1024w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/06-export-300x171.png 300w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/06-export-768x439.png 768w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/06-export-1536x878.png 1536w, https:\/\/www.mywlca.blog\/wp-content\/uploads\/2025\/10\/06-export.png 1998w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Export Setup with Crumple Nodes<\/figcaption><\/figure>\n\n\n\n<p>Ensure you supply:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The export output <strong>directory<\/strong><\/li>\n\n\n\n<li>The sheet <strong>elements <\/strong>(not just names)<\/li>\n\n\n\n<li>The <strong>custom filenames<\/strong> generated in Python<\/li>\n<\/ul>\n\n\n\n<p>If DWG export fails, check that the <code>Revit.ExportOptionsDwg<\/code> node is correctly connected and you have writing-permission for the directory.<\/p>\n\n\n\n<p>To enhance usability, especially for non-technical team members, include Boolean inputs (e.g., <strong>Export DWG?<\/strong>). This makes the graph friendly for Dynamo Player usage.<\/p>\n\n\n\n<p>By combining Dynamo, the Crumple package, parameter logic, and a CSV\u2010driven naming convention, this workflow automates a task that traditionally consumed considerable time and required careful manual oversight. The result is:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A <strong>consistent<\/strong> file\u2010naming pattern aligned with CDE requirements<\/li>\n\n\n\n<li>A <strong>scalable<\/strong> process that can be replicated across different projects<\/li>\n\n\n\n<li>Reduced manual effort and improved reliability of exports<\/li>\n<\/ul>\n\n\n\n<p>Short on time? Download and share the script from <a href=\"https:\/\/drive.google.com\/file\/d\/1zcxaNHaLCSPAjkKysJXVZn6QkmZ5CqV_\/view?usp=sharing\">Google Drive<\/a>!<\/p>\n\n\n\t<div id=\"respond\" class=\"comment-respond wp-block-post-comments-form\">\n\t\t<h3 id=\"reply-title\" class=\"comment-reply-title\">Leave a Reply <small><a rel=\"nofollow\" id=\"cancel-comment-reply-link\" href=\"\/index.php?rest_route=%2Fwp%2Fv2%2Fposts%2F106#respond\" style=\"display:none;\">Cancel reply<\/a><\/small><\/h3><form action=\"https:\/\/www.mywlca.blog\/wp-comments-post.php\" method=\"post\" id=\"commentform\" class=\"comment-form\"><p class=\"comment-notes\"><span id=\"email-notes\">Your email address will not be published.<\/span> <span class=\"required-field-message\">Required fields are marked <span class=\"required\">*<\/span><\/span><\/p><p class=\"comment-form-comment\"><label for=\"comment\">Comment <span class=\"required\">*<\/span><\/label> <textarea id=\"comment\" name=\"comment\" cols=\"45\" rows=\"8\" maxlength=\"65525\" required><\/textarea><\/p><p class=\"comment-form-author\"><label for=\"author\">Name <span class=\"required\">*<\/span><\/label> <input id=\"author\" name=\"author\" type=\"text\" value=\"\" size=\"30\" maxlength=\"245\" autocomplete=\"name\" required \/><\/p>\n<p class=\"comment-form-email\"><label for=\"email\">Email <span class=\"required\">*<\/span><\/label> <input id=\"email\" name=\"email\" type=\"email\" value=\"\" size=\"30\" maxlength=\"100\" aria-describedby=\"email-notes\" autocomplete=\"email\" required \/><\/p>\n<p class=\"comment-form-url\"><label for=\"url\">Website<\/label> <input id=\"url\" name=\"url\" type=\"url\" value=\"\" size=\"30\" maxlength=\"200\" autocomplete=\"url\" \/><\/p>\n<p class=\"comment-form-cookies-consent\"><input id=\"wp-comment-cookies-consent\" name=\"wp-comment-cookies-consent\" type=\"checkbox\" value=\"yes\" \/> <label for=\"wp-comment-cookies-consent\">Save my name, email, and website in this browser for the next time I comment.<\/label><\/p>\n<p class=\"form-submit wp-block-button\"><input name=\"submit\" type=\"submit\" id=\"submit\" class=\"wp-block-button__link wp-element-button\" value=\"Post Comment\" \/> <input type='hidden' name='comment_post_ID' value='106' id='comment_post_ID' \/>\n<input type='hidden' name='comment_parent' id='comment_parent' value='0' \/>\n<\/p><\/form>\t<\/div><!-- #respond -->\n\t","protected":false},"excerpt":{"rendered":"<p>Here, I present a streamlined workflow leveraging Dynamo (along with the custom nodes from the Crumple package) to automate the batch export of PDFs and DWGs with parameter-based filenames. The solution is scalable across projects, adaptable to varying conventions, and accessible to project teams.<\/p>\n","protected":false},"author":1,"featured_media":124,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,3],"tags":[],"class_list":["post-106","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-computational","category-dynamo"],"_links":{"self":[{"href":"https:\/\/www.mywlca.blog\/index.php?rest_route=\/wp\/v2\/posts\/106","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mywlca.blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mywlca.blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mywlca.blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mywlca.blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=106"}],"version-history":[{"count":0,"href":"https:\/\/www.mywlca.blog\/index.php?rest_route=\/wp\/v2\/posts\/106\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.mywlca.blog\/index.php?rest_route=\/wp\/v2\/media\/124"}],"wp:attachment":[{"href":"https:\/\/www.mywlca.blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=106"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mywlca.blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=106"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mywlca.blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=106"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}