Skip to main content
pixxxelschubser
Community Expert
Community Expert
December 23, 2021
Question

[JS] [Action] Split or break a dashed line into separate (real) lines by script

  • December 23, 2021
  • 33 replies
  • 11915 views

Illustrator does not offer a direct way to convert dashed lines (e.g. for cutting plotters or CNC engraving).

 

Please do not reply to suggest the way to set the outline thickness to a very small value e.g. 0.0001pt. This way still creates filled rectangles and not real lines and is therefore unsuitable.

 

I also know some existing scripts that try to redraw the dash line. Unfortunately, these scripts are not an option either, because the results sometimes differ from the originals.

 

For several years I have used the manual way to break up a dashed line into single (real) lines:
- select the dashed line
- (optionally) create a duplicate and turn off the visibility of the original
- draw a horizontal straight line (helper object)
- remove the dash line attribute from the straight line (helper object)
- create an artbrush from this line (option: Artbrush, no further options, usually just confirm twice)
- delete the line (helper object)
- assign the newly created brush to the original dashed line (or its duplicate)
- use the menu command Object --> Expand Appearance
- ungroup two times
- group the selection and name the group as desired
- delete the artbrush

 

Since this process is rare, but needs to be done over and over again, I wanted to create a script.

Unfortunately there is a problem. Adobe Extendscript cannot be used to create or delete a brush. But it is possible to create a brush with an action. This action can be included in a script. But this way always needs additional confirmations by the user:

- select the option: Artbrush
- confirmation of the selection with [OK]
- confirming the options dialog with [OK] (usually without further settings)

 

 

Question: Does anyone know a way to create an art brush via script or action without additional user interaction (and delete it afterwards)?

 

-------------------------------------------------------------------------------------------

For those interested, here is an example action to create a brush in text form:

 

/version 3
/name [ 16
	63726561746544756d6d794272757368
]
/isOpen 1
/actionCount 1
/action-1 {
	/name [ 16
		63726561746544756d6d794272757368
	]
	/keyIndex 0
	/colorIndex 0
	/isOpen 1
	/eventCount 1
	/event-1 {
		/useRulersIn1stQuadrant 0
		/internalName (ai_plugin_brush)
		/localizedName [ 6
			50696e73656c
		]
		/isOpen 1
		/isOn 1
		/hasDialog 0
		/parameterCount 1
		/parameter-1 {
			/key 1835363957
			/showInPalette -1
			/type (enumerated)
			/name [ 12
				4e657565722050696e73656c
			]
			/value 1
		}
	}
}

 

Many thanks in advance.

 

This topic has been closed for replies.

33 replies

Kurt Gold
Community Expert
Community Expert
January 24, 2022

Your second version is a very good improvement, sttk3.

 

The next level would be to find a way to allow multiple selected dashed paths with different stroke attributes. I have an action that can almost do it, but currently it is still not precise enough and it will alter the dash positions a bit.

 

It's a challenging game.

 

Legend
January 23, 2022

Improved the appearance of rounded caps and projecting caps.

/**
  * @File expand a dashed stroke  
  * https://community.adobe.com/t5/illustrator-discussions/js-action-split-or-break-a-dashed-line-into-separate-real-lines-by-script/td-p/12614309
  * @version 1.0.1
  * @7111211 sttk3.com
  * @7340357 © 2022 sttk3.com
*/

//@target 'illustrator'

(function() {
  if(app.documents.length <= 0) {return ;}
  var doc = app.documents[0] ;

  // only one selection is allowed
  var sel = doc.selection ;
  var messageInvalidSelection = 'Select one dashed stroke and execute this script.' ;
  if(sel.length != 1) {
    alert(messageInvalidSelection) ;
    return ;
  }
  
  // terminate when selected item is not a path, not a dashed stroke, or has a fill
  var originalPath = sel[0] ;
  if(!/^PathItem$/.test(originalPath.constructor.name)) {
    alert(messageInvalidSelection) ;
    return ;
  }
  if(originalPath.strokeDashes.length <= 0) {
    alert(messageInvalidSelection) ;
    return ;
  }
  if(originalPath.filled) {
    alert('This script should be execute after the fill is removed.') ;
    return ;
  }

  // generate a unique color
  var tempSpot = doc.spots.add() ;
  var tempColor = new SpotColor() ;
  tempColor.spot = tempSpot ;
  tempColor.tint = 100 ;

  try {
    var pathfinderGroup = originalPath.layer.groupItems.add() ;
    pathfinderGroup.move(originalPath, ElementPlacement.PLACEBEFORE) ;
    var maskWidth = originalPath.strokeWidth + 1 ;

    // object to fill dash
    var dashPath = originalPath.duplicate(pathfinderGroup, ElementPlacement.PLACEATEND) ;
    dashPath.strokeWidth = maskWidth ;
    dashPath.strokeCap = StrokeCap.BUTTENDCAP ; // make the dash length unchangeable

    // object to fill gap
    var gapPath = originalPath.duplicate(pathfinderGroup, ElementPlacement.PLACEATEND) ;
    gapPath.strokeDashes = [] ;
    gapPath.strokeColor = tempColor ;

    // leave fill only at gaps
    doc.selection = [pathfinderGroup] ;
    app.executeMenuCommand('OffsetPath v22') ; // Outline Stroke
    app.executeMenuCommand('Live Pathfinder Subtract') ;
    app.executeMenuCommand('expandStyle') ; // Expand Appearance
    app.executeMenuCommand('compoundPath') ; // Compound Path Make
    
    // remove gaps of originalPath by live paint
    originalPath.strokeDashes = [] ;
    originalPath.selected = true ;
    app.executeMenuCommand('Make Planet X') ; //  Live Paint Make
    app.executeMenuCommand('Expand Planet X') ; //  Live Paint Expand
    app.executeMenuCommand('ungroup') ;
    app.redraw() ;
    
    // remove gapPath
    var tempGroups = doc.selection ;
    var itemColor ;
    for(var i = tempGroups.length - 1 ; i >= 0 ; i--) {
      itemColor = tempGroups[i].pathItems[0].fillColor ;
      if((itemColor.constructor.name == 'SpotColor') && (itemColor.spot == tempSpot)) {
        tempGroups[i].remove() ;
        break ;
      }
    }
  } catch(e) {
    alert(e) ;
  } finally {
    tempSpot.remove() ;
  }
})() ;
pixxxelschubser
Community Expert
Community Expert
January 23, 2022

 

… I'm curious about Mark's (m1b) approach.


By @Kurt Gold

 

Yes, me too.

😉

Kurt Gold
Community Expert
Community Expert
January 23, 2022

Pixxxelschubser,

 

my guess is that you are just overwhelmed by all the half-baked approaches so far. You may possibly consider to never use dashed paths again. 🙂

 

But I think one day someone will crack the nut. I have some other ideas, but currently they do not work as they are supposed to work.

 

I'm curious about Mark's (m1b) approach.

 

pixxxelschubser
Community Expert
Community Expert
January 23, 2022

I apologize for any inconvenience this may cause.
Unfortunately, I don't have time to give my topic the attention it deserves at the moment.

 

However, I thank you very much for all the solutions posted so far. Unfortunately, I have not yet been able to test the last two promising variants of @Kurt Gold  and @CarlosCanto  extensively.

 

A first test with @sttk3  very good script showed very good results with newly created stroke lines (much more precise than with an artbrush with deviations of less than 0.05 mm). However, the script does not cope well with rounded caps. There are indeed deviations there. At this point I unfortunately had to interrupt my tests. And thanks also to you for this great solution.

 

I will definitely not forget this topic. When I have enough time again, I will test all suggestions in detail and give accurate feedback.

Kurt Gold
Community Expert
Community Expert
January 23, 2022

A very good approach, sttk3.

 

Unfortunately, depending on the specific dashed line settings, it often changes the original appearance to a considerable degree.

 

But I'm sure it may be improved.

 

Legend
January 23, 2022

Hello pixxxelschubser,

 

I'll offer a solution other than art brushes: you can use Live Paint as a pathfinder for strokes.

/**
  * @File expand a dashed stroke  
  * https://community.adobe.com/t5/illustrator-discussions/js-action-split-or-break-a-dashed-line-into-separate-real-lines-by-script/td-p/12614309
  * @version 1.0.0
  * @7111211 sttk3.com
  * @7340357 © 2022 sttk3.com
*/

//@target 'illustrator'

(function() {
  if(app.documents.length <= 0) {return ;}
  var doc = app.documents[0] ;

  // only one selection is allowed
  var sel = doc.selection ;
  var messageInvalidSelection = 'Select one dashed stroke and execute this script.' ;
  if(sel.length != 1) {
    alert(messageInvalidSelection) ;
    return ;
  }
  
  // terminate when selected item is not a path, not a dashed stroke, or has a fill
  var originalPath = sel[0] ;
  if(!/^PathItem$/.test(originalPath.constructor.name)) {
    alert(messageInvalidSelection) ;
    return ;
  }
  if(originalPath.strokeDashes.length <= 0) {
    alert(messageInvalidSelection) ;
    return ;
  }
  if(originalPath.filled) {
    alert('This script should be execute after the fill is removed.') ;
    return ;
  }

  // generate a unique color
  var tempSpot = doc.spots.add() ;
  var tempColor = new SpotColor() ;
  tempColor.spot = tempSpot ;
  tempColor.tint = 100 ;

  try {
    var pathfinderGroup = originalPath.layer.groupItems.add() ;
    pathfinderGroup.move(originalPath, ElementPlacement.PLACEBEFORE) ;
    var maskWidth = originalPath.strokeWidth + 1 ;

    // object to fill dash
    var dashPath = originalPath.duplicate(pathfinderGroup, ElementPlacement.PLACEATEND) ;
    dashPath.strokeWidth = maskWidth ;

    // object to fill gap
    var gapPath = originalPath.duplicate(pathfinderGroup, ElementPlacement.PLACEATEND) ;
    gapPath.strokeWidth = maskWidth ;
    gapPath.strokeDashes = [] ;
    gapPath.strokeColor = tempColor ;

    // leave fill only at gaps
    doc.selection = [pathfinderGroup] ;
    app.executeMenuCommand('OffsetPath v22') ; // Outline Stroke
    app.executeMenuCommand('Live Pathfinder Subtract') ;
    app.executeMenuCommand('expandStyle') ; // Expand Appearance
    app.executeMenuCommand('compoundPath') ; // Compound Path Make
    
    // remove gaps of originalPath by live paint
    originalPath.strokeDashes = [] ;
    originalPath.selected = true ;
    app.executeMenuCommand('Make Planet X') ; //  Live Paint Make
    app.executeMenuCommand('Expand Planet X') ; //  Live Paint Expand
    app.executeMenuCommand('ungroup') ;
    app.redraw() ;
    
    // remove gapPath
    var tempGroups = doc.selection ;
    var itemColor ;
    for(var i = tempGroups.length - 1 ; i >= 0 ; i--) {
      itemColor = tempGroups[i].pathItems[0].fillColor ;
      if((itemColor.constructor.name == 'SpotColor') && (itemColor.spot == tempSpot)) {
        tempGroups[i].remove() ;
        break ;
      }
    }
  } catch(e) {
    alert(e) ;
  } finally {
    tempSpot.remove() ;
  }
})() ;

 

femkeblanco
Legend
January 23, 2022

Cool!

Kurt Gold
Community Expert
Community Expert
December 28, 2021

pixxxelschubser,

 

now I know the reason why you got (many) closed objects with curved dashed strokes. There is yet another Illustrator bug in the Actions palette. That is, the very first action step (adjusting the Pathfinder settings) is being ignored if the modal dialog for this step is turned off.

 

Unfortunately, one has to turn it on and then has to hit the Enter key one time while the action is running. Alternatively, you can manually adjust the Pathfinder settings once per Illustrator session and then turn the modal dialog off in the Actions palette.

 

Here you can download the modified and slightly improved action.

 

Dash Nipper 3

 

It also contains a sample Illustrator file with all kinds of dashed paths (artboard 1). On artboard 2 you can see the results I got after running the action.

 

As already mentioned in a previous post, due to an Illustrator rounding error bug when writing the Preferences files, it may be that the action won't work after quitting and restarting Illustrator. In that case, unfortunately, you will have to delete the action set in the Actions palette and then reimport it. After that, it should work again.

 

CarlosCanto
Community Expert
Community Expert
December 28, 2021

Hi pixxxel, on Windows we can use a jsx mixed with vbs to send clicks to Illustrator to dismiss the Brush Windows.

 

how to set up this excercise

 

- create a "createBrush" Action in a "test" Action Set

- select a path to create an Art brush from

 

- save this vbs script anywhere (your jsx could create and execute this vbs on the fly)

 

'Option Explicit

Dim Shell, WMI, wql, process, processes

Set Shell = CreateObject("WScript.Shell")
Set WMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")

wql = "SELECT ProcessId FROM Win32_Process WHERE Name = 'illustrator.exe'"

For Each process In WMI.ExecQuery(wql)
  Shell.AppActivate process.ProcessId

  Wscript.Sleep 3000
  Shell.SendKeys "{TAB}{TAB}"
  Wscript.Sleep 500
  Shell.SendKeys "%A" 
  Wscript.Sleep 500
  Shell.SendKeys "{ENTER}"
  Wscript.Sleep 500
  Shell.SendKeys "carlosBrush{ENTER}"

  exit for
  msgbox "after exit for" 'this never executes
Next

'msgbox "done"	

 

 

finally run the following jsx, adjust the path to point to your own vbs file

 

// creates an Art Brush via Action (with Dialogs), vbs will choose Art Brush and dismiss dialogs

var vbs = File("C:/Users/canto/Google Drive/Adobe Scripts/addBrush_sendKeys_test.vbs");
vbs.execute();
        
app.doScript("createBrush", "test");

 

 

have fun!

 

 

pixxxelschubser
Community Expert
Community Expert
December 28, 2021

 

… Ich … werde natürlich testen, ob die Bildpinsel-Methode dort keine "chunk objects" erzeugt. Glaube nicht daran, aber wer weiß ...

 

By @Kurt Gold

 

Nur noch zwei kleine Zwischenfragen:

  • Mac oder PC? (den Zip-Dateien nach wahrscheinlich Mac)
  • "deine eigene manuelle" Bildpinsel-Methode oder mein Test-Skript?
Kurt Gold
Community Expert
Community Expert
December 28, 2021

- Mac oder PC: Beides vorhanden und es wird immer auf beiden getestet.

 

- Natürlich beide Bildpinsel-Methoden. Zusätzlich die vom Raben. Das kommt ja alles nur von ihm.

 

Gute Nacht