JS Replacing Paragraph Text Item Getting Bad Width & Height

Explorer ,
Apr 04, 2022 Apr 04, 2022

Copy link to clipboard

Copied

Hi, I have some code here that I'm using to replace a paragraph text item.

 

We're doing some funky stuff to get the text size and angle because it needs to handle broken or tranformed items. Also normalizing some values like text scaling and baseline.

 

But I've been trying to figure out why this results in an inaccurate width and height, since I'm grabbing the original height and width and applying those to the end result. Any help would be greatly appreciated!

 

nickcombs_0-1649115025908.png 

nickcombs_1-1649115167929.png

 

var log = []

ProcessUserText( activeDocument.activeLayer )

alert( log.join('\n') )



function ProcessUserText( lyr ) { try {

  var prev_units = SetUnits( 'pixels' )

  var txt = lyr.textItem
  txt.kind = TextType.PARAGRAPHTEXT
  var txtPos = txt.position
  // var resFix = activeDocument.resolution / 72
  // var bW = BdsW( lyr.bounds )
  // var bH = BdsH( lyr.bounds )
  var w = txt.width, h = txt.height
  log.push( 'starting w & h: ' + [w,h] )

  // fixes some broken textItem issues
  txt.kind = TextType.POINTTEXT

  var lyr2 = lyr.parent.artLayers.add()
  lyr2.kind = LayerKind.TEXT
  txt2 = lyr2.textItem
  txt2.contents = txt.contents
  txt2.font = txt.font

  var ang = TextAngle( lyr )
  RotateLayer( -ang, lyr )

  // ps bug: https://community.adobe.com/t5/photoshop-ecosystem-discussions/read-font-size-with-script/td-p/10697934
  txt2.size = txt.size
  TextSizeWorkaround( lyr2, lyr )

  RotateLayer( ang, lyr2 )

  // try { txt2.color = txt.color }
  // catch(e) { txt2.color = TextColorFromSample( txt ) }

  // var rgb = RoundTextRgb( txt2 )

  // if( ! RgbInList( rgb ) ) LogWarn( 'text color '+ rgb +' not found in list' )

  txt2.useAutoLeading = true
  txt2.autoKerning = AutoKernType.MANUAL
  txt2.tracking = 0
  txt2.verticalScale = 100
  txt2.horizontalScale = 100
  txt2.baselineShift = 0
  txt2.justification = txt.justification

  txt2.kind = TextType.PARAGRAPHTEXT
  SetUnits( 'pixels' )
  txt2.position = txtPos
  log.push( 'txt2.kind: '+ txt2.kind )
  // var bdsFix = BdsW( lyr2.bounds ) / bW
  // LogDev( 'bounds new-over-old : '+ bdsFix )
  txt2.width = w
  txt2.height = h
  log.push( 'final w & h: ' + [txt2.width, txt2.height] )

  var n = lyr.name
  lyr2.move( lyr, ElementPlacement.PLACEBEFORE )
  lyr.remove()
  lyr2.name = n

  log.push( 'xy:'+ Number( txt2.position[0] ).toFixed(0)
      +','+ Number( txt2.position[1] ).toFixed(0) )
  log.push( 'deg:'+ ang )
  log.push( 'pt:'+Number( txt2.size ).toFixed(1) )
  log.push( 'font:'+ txt2.font )
  log.push( 'encoded:'+ encodeURI( txt2.contents ) )

  SetUnits( prev_units ) }
catch(e) { log.push( 'ProcessUserText '+ e ) }
return lyr2 } // ProcessUserText



function SetUnits( input ) { try {
  var rUnit, tUnit
  if( input instanceof Object ) {
    rUnit = input.ruler
    tUnit = input.type }
  else if( IsString( input ) )
    rUnit = tUnit = input
  var prev_units = { ruler: preferences.rulerUnits,
    type: preferences.typeUnits }
  switch( rUnit ) {
    case 'points': case 'pt':
      preferences.rulerUnits = Units.POINTS
      break;
    case 'inches': case 'in':
      preferences.rulerUnits = Units.INCHES
      break;
    case 'centimeters': case 'cm':
      preferences.rulerUnits = Units.CENTIMETERS
      break;
    default:
      preferences.rulerUnits = Units.PIXELS
      break }
  switch( tUnit ) {
    case 'pixels': case 'px':
      preferences.typeUnits = TypeUnits.PIXELS
      break;
    case 'inches': case 'in':
      preferences.typeUnits = TypeUnits.INCHES
      break;
    case 'centimeters': case 'cm':
      preferences.typeUnits = TypeUnits.CENTIMETERS
      break;
    default:
      preferences.typeUnits = TypeUnits.POINTS
      break }
  log.push( 'units set: '+ preferences.rulerUnits +', '+ preferences.typeUnits )
  return prev_units }
catch(e) { log.push( 'SetUnits '+ e ) }
} // SetUnits



function IsString( input ) {
  return typeof input === 'string' || input instanceof String
} // IsString



function EditAsSmartObject( lyr ) {
  ConvertSmartLayer( lyr )
  runMenuItem( stID( 'placedLayerEditContents' ) )
  return activeDocument.activeLayer
} // EditAsSmartObject



function ConvertSmartLayer( lyr ) { try {
  SelectLayer( lyr )
  if( IsSmartObj( lyr )) return lyr
  var desc = new ActionDescriptor()
  desc.putInteger( chID( "DocI" ), 219 )
  desc.putInteger( chID( "Idnt" ), 230 )
  desc.putString( chID( "Nm  " ), """Convert to Smart Object""" )
  desc.putBoolean( stID( "hasEnglish" ), true )
  desc.putInteger( chID( "ItmI" ), 3 )
  executeAction( stID( "newPlacedLayer" ), undefined, DialogModes.NO )
  lyr = activeDocument.activeLayer // layer is now a different object
  log.push( lyr.name +' converted to smart object' )
  return lyr }
catch(e) { log.push( 'ConvertSmaartLayer '+ e ) }
} // ConvertSmartLayer



function TextAngle( lyr ) { try {
  // Normalizes text copy to a period(.) and
  // uses baselineShift to create a vector
  var doc = activeDocument
  var prev_state = doc.activeHistoryState
  var angLyr = lyr.duplicate()
  var angTxt = angLyr.textItem
  angTxt.contents = '.'
  angTxt.font = 'MyriadPro-Regular'
  angTxt.size = 3
  angTxt.baselineShift = 0
  var soLyr1 = EditAsSmartObject( angLyr )
  var soDoc = soLyr1.parent
  soDoc.resizeCanvas( 250, 250, AnchorPosition.MIDDLECENTER )
  var soLyr2 = soLyr1.duplicate()
  soLyr2.textItem.baselineShift = 100
  var ang = GetAngle(
    RoundEach( BdsMid( soLyr1 ) ),
    RoundEach( BdsMid( soLyr2 ) ) )
  soDoc.close( SaveOptions.DONOTSAVECHANGES )
  doc.activeHistoryState = prev_state
  log.push( lyr.name +' angle: '+ ang )
  return ang }
catch(e) { log.push( 'TextAngle '+ e ) }
} // TextAngle



function GetAngle( xy1, xy2 ) {
  var ang = 0 - Math.atan( ( xy1[0] - xy2[0] ) / ( xy1[1] - xy2[1] ) ) * 180.0 / Math.PI
  log.push( [xy1,xy2] +' angle: '+ ang )
  return ang
} // GetAngle



function RoundEach( nums ) {
  var it = []
  for( var i=0; i<nums.length; i++ ) {
    it[i] = Math.round( nums[i] ) }
  return it
} // RoundEach



function BdsMid( lyr ) {
  var b = lyr.bounds
  var mid = Midpoint( [ b[0], b[1] ], [ b[2], b[3] ] )
  log.push( lyr.name +' midpoint: '+ mid )
  return mid
} // BdsMid



function Midpoint( xy1, xy2 ) {
  return [ ( xy1[0] + xy2[0] ) / 2, ( xy1[1] + xy2[1] ) / 2 ]
} // Midpoint



function RotateLayer( deg, lyr ) { try {
  lyr = lyr || activeDocument.activeLayer
  if( deg && deg !== 0 ) {
    lyr.rotate( deg )
    log.push( lyr.name +' rotated '+ deg ) } }
catch(e) { log.push( 'RotateLayer '+ e ) }
} // RotateLayer



function TextSizeWorkaround( resizeLayer, targetLayer ) { try {
  var prev_units = SetUnits( 'points' )
  var resizeTxt = resizeLayer.textItem
  var startSize = resizeTxt.size
  log.push( 'startSize: '+ startSize )
  var delta0 = BdsH( targetLayer ) - BdsH( resizeLayer )
  var limit = 5
  while( limit-- && Math.abs( delta0 ) >= 1 ) {
    if( resizeTxt.size < 6 ) return resizeTxt.size = 6
    var upDown = 1
    if( delta0 < 0 ) {
      resizeTxt.size--
      upDown = -1
      delta0 = Math.abs( delta0 ) }
    else resizeTxt.size++
    log.push( 'delta0: '+ delta0 )
    log.push( 'upDown: '+ upDown )
    var delta1 = Math.abs( BdsH( targetLayer ) - BdsH( resizeLayer ) )
    log.push( 'delta1: '+ delta1 )
    var remainingDelta = upDown * delta1 /( delta0 - delta1 )
    log.push( 'remainingDelta: '+ remainingDelta )
    resizeTxt.size = Math.round( resizeTxt.size + remainingDelta )
    log.push( 'resizeTxt.size: '+ resizeTxt.size )
    delta0 = BdsH( targetLayer ) - BdsH( resizeLayer ) }
  SetUnits( prev_units )
  return resizeTxt.size }
catch(e) { log.push( 'TextSizeWorkaround '+ e ) }
} // TextSizeWorkaround



function BdsH( bdsOrLyr ) {
  if( bdsOrLyr instanceof ArtLayer ) bdsOrLyr = bdsOrLyr.bounds
  return Math.abs( bdsOrLyr[1] - bdsOrLyr[3] )
} // BdsH



function BdsW( bdsOrLyr ) {
  if( bdsOrLyr instanceof ArtLayer ) bdsOrLyr = bdsOrLyr.bounds
  return Math.abs( bdsOrLyr[0] - bdsOrLyr[2] )
} // BdsW



function chID( a ) { return charIDToTypeID( a )}
function stID( a ) { return stringIDToTypeID( a )}



function SelectLayer( lyr ) { try {
  if( typeof lyr === 'string' || lyr instanceof String ) lyr = GetLayer( lyr )
  activeDocument.activeLayer = lyr
  return activeDocument.activeLayer }
catch(e) { LogErr( 'SelectLayer: '+ e ) }
} // SelectLayer



function GetLayer( ptn ) { try {
  if( ptn instanceof ArtLayer ) return ptn
  var lyrs = activeDocument.layers
  var l, len = lyrs.length || 0
  for( l=0; l<len; l++ ) {
    if( RegExp( ptn ).test( lyrs[l].name )) return lyrs[l] } }
  catch(e) { LogErr( 'GetLayer: '+ e ) }
} // GetLayer



function IsSmartObj( lyr ) { return lyr.kind == LayerKind.SMARTOBJECT }

 

TOPICS
Actions and scripting

Views

144

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Explorer , Apr 18, 2022 Apr 18, 2022
Following up on my earlier comment, I have implemented a solution that fills the textItem with characters so that the layer.bounds will match what the textItem width and height properties should be returning. We're using a lot of very small characters to keep it accurate, but there is a trade-off in performance, expecially when large textItem boxes with small fonts are encountered. So I implemented a loop to hopefully prevent too many characters being added in these cases, at the cost of a littl...

Likes

Translate

Translate
Explorer ,
Apr 06, 2022 Apr 06, 2022

Copy link to clipboard

Copied

Okay, it looks like the textItem width & height properties are off based on existing transformations. I've done some digging on accessing the layer transformation data, and just to confirm... it's not actually available? If that's the case, the only workaround I can think of is to try and fill the box with characters and retrieve the bounds.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Apr 18, 2022 Apr 18, 2022

Copy link to clipboard

Copied

I posted a solution, but it has been flagged as spam (probably done automatically because it involves a large string of repeated characters). Hopefully we can get that reviewed and reinstated so that people can see the working code, but I'm not sure who to appeal to for this request.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Apr 18, 2022 Apr 18, 2022

Copy link to clipboard

Copied

Try again...

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Apr 18, 2022 Apr 18, 2022

Copy link to clipboard

Copied

Deja vu

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Apr 18, 2022 Apr 18, 2022

Copy link to clipboard

Copied

LATEST

Let's see if I can post the content of your post (I recieved for my E-Mail):

 

"Here is a diffchecker composite of a textItem before and after being processed by the script. Magenta indicates pixels that changed. You can see the layer edges in blue did not move at all in this case. In larger text boxes, you might see it shift by a few pixels.

 

I should also note that I've commented out the call to RgbInList() because that relies on a swatches.csv file that I won't be sharing here."

 

var log = [] displayDialogs = DialogModes.NO ProcessUserText( activeDocument.activeLayer ) displayDialogs = DialogModes.ERROR alert( log.join('\n') ) function ProcessUserText( lyr ) { try { log.push( lyr.name ) var prev_units = SetUnits( 'pixels' ) var txt = lyr.textItem try { var jstn = txt.justification } catch(e) { throw lyr.name +': unable to access text justification' } txt.kind = TextType.PARAGRAPHTEXT var ang = TextAngle( lyr ) RotateLayer( -ang, lyr ) var box = TextBoxDimsWorkaround( lyr ) // fixes some broken textItem issues txt.kind = TextType.POINTTEXT var lyr2 = lyr.parent.artLayers.add() lyr2.kind = LayerKind.TEXT txt2 = lyr2.textItem txt2.contents = txt.contents txt2.font = txt.font // ps bug: https://community.adobe.com/t5/photoshop-ecosystem-discussions/read-font-size-with-script/td-p/10697934 txt2.size = txt.size TextSizeWorkaround( lyr2, lyr ) try { txt2.color = txt.color } catch(e) { txt2.color = TextColorFromSample( txt ) } var rgb = RoundTextRgb( txt2 ) // if( ! RgbInList( rgb ) ) log.push( 'text color '+ rgb +' not found in list' ) // else log.push( 'rgb found: '+ rgb ) txt2.useAutoLeading = true txt2.autoKerning = AutoKernType.MANUAL txt2.tracking = 0 txt2.verticalScale = 100 txt2.horizontalScale = 100 txt2.baselineShift = 0 txt2.justification = txt.justification log.push( 'jstn: '+ jstn ) txt2.kind = TextType.PARAGRAPHTEXT SetUnits( 'pixels' ) txt2.position = box.position var resFix = activeDocument.resolution / 72 txt2.width = box.width / resFix txt2.height = box.height / resFix var adjX = lyr.bounds[0] - lyr2.bounds[0] var adjY = lyr.bounds[1] - lyr2.bounds[1] log.push( 'adjustments: '+ [adjX,adjY] ) txt2.width += adjX / resFix txt2.height += adjY / resFix log.push( 'final w & h: ' + [txt2.width, txt2.height] ) RotateLayer( ang, lyr2 ) var n = lyr.name lyr2.move( lyr, ElementPlacement.PLACEBEFORE ) lyr.remove() lyr2.name = n var tstats = [ 'xy:'+ Number( txt2.position[0] ).toFixed(0) +','+ Number( txt2.position[1] ).toFixed(0), 'deg:'+ang, 'pt:'+Number( txt2.size ).toFixed(1), 'font:'+ txt2.font, 'rgb:'+ rgb, 'encoded:'+ encodeURI( txt2.contents ) ].join(' ') log.push( lyr2.name +' rebuilt ' + tstats ) SetUnits( prev_units ) return lyr2 } catch(e) { log.push( 'ProcessUserText '+ e ) } } // ProcessUserText function IsString( input ) { return typeof input === 'string' || input instanceof String } // IsString function EditAsSmartObject( lyr ) { ConvertSmartLayer( lyr ) runMenuItem( stID( 'placedLayerEditContents' ) ) return activeDocument.activeLayer } // EditAsSmartObject function ConvertSmartLayer( lyr ) { try { SelectLayer( lyr ) if( IsSmartObj( lyr )) return lyr var desc = new ActionDescriptor() desc.putInteger( chID( "DocI" ), 219 ) desc.putInteger( chID( "Idnt" ), 230 ) desc.putString( chID( "Nm " ), """Convert to Smart Object""" ) desc.putBoolean( stID( "hasEnglish" ), true ) desc.putInteger( chID( "ItmI" ), 3 ) executeAction( stID( "newPlacedLayer" ), undefined, DialogModes.NO ) lyr = activeDocument.activeLayer // layer is now a different object log.push( lyr.name +' converted to smart object' ) return lyr } catch(e) { log.push( 'ConvertSmaartLayer '+ e ) } } // ConvertSmartLayer function TextAngle( lyr ) { try { // Normalizes text copy to a period(.) and // uses baselineShift to create a vector var doc = activeDocument var prev_state = doc.activeHistoryState var angLyr = lyr.duplicate() var angTxt = angLyr.textItem angTxt.contents = '.' angTxt.font = 'MyriadPro-Regular' angTxt.size = 3 angTxt.baselineShift = 0 var soLyr1 = EditAsSmartObject( angLyr ) var soDoc = soLyr1.parent soDoc.resizeCanvas( 250, 250, AnchorPosition.MIDDLECENTER ) var soLyr2 = soLyr1.duplicate() soLyr2.textItem.baselineShift = 100 var ang = GetAngle( RoundEach( BdsMid( soLyr1 ) ), RoundEach( BdsMid( soLyr2 ) ) ) soDoc.close( SaveOptions.DONOTSAVECHANGES ) doc.activeHistoryState = prev_state log.push( lyr.name +' angle: '+ ang ) return ang } catch(e) { log.push( 'TextAngle '+ e ) } } // TextAngle function GetAngle( xy1, xy2 ) { var ang = 0 - Math.atan( ( xy1[0] - xy2[0] ) / ( xy1[1] - xy2[1] ) ) * 180.0 / Math.PI log.push( [xy1,xy2] +' angle: '+ ang ) return ang } // GetAngle function RoundEach( nums ) { var it = [] for( var i=0; i<nums.length; i++ ) { it[i] = Math.round( nums[i] ) } return it } // RoundEach function BdsMid( lyr ) { var b = lyr.bounds var mid = Midpoint( [ b[0], b[1] ], [ b[2], b[3] ] ) log.push( lyr.name +' midpoint: '+ mid ) return mid } // BdsMid function Midpoint( xy1, xy2 ) { return [ ( xy1[0] + xy2[0] ) / 2, ( xy1[1] + xy2[1] ) / 2 ] } // Midpoint function RotateLayer( deg, lyr ) { try { lyr = lyr || activeDocument.activeLayer if( deg && deg !== 0 ) { lyr.rotate( deg ) log.push( lyr.name +' rotated '+ deg ) } } catch(e) { log.push( 'RotateLayer '+ e ) } } // RotateLayer function TextSizeWorkaround( resizeLayer, targetLayer ) { try { var prev_units = SetUnits( 'points' ) var resizeTxt = resizeLayer.textItem var startSize = resizeTxt.size log.push( 'startSize: '+ startSize ) var delta0 = BdsH( targetLayer ) - BdsH( resizeLayer ) var limit = 5 while( limit-- && Math.abs( delta0 ) >= 1 ) { if( resizeTxt.size < 6 ) return resizeTxt.size = 6 var upDown = 1 if( delta0 < 0 ) { resizeTxt.size-- upDown = -1 delta0 = Math.abs( delta0 ) } else resizeTxt.size++ log.push( 'delta0: '+ delta0 ) log.push( 'upDown: '+ upDown ) var delta1 = Math.abs( BdsH( targetLayer ) - BdsH( resizeLayer ) ) log.push( 'delta1: '+ delta1 ) var remainingDelta = upDown * delta1 /( delta0 - delta1 ) log.push( 'remainingDelta: '+ remainingDelta ) resizeTxt.size = Math.round( resizeTxt.size + remainingDelta ) log.push( 'resizeTxt.size: '+ resizeTxt.size ) delta0 = BdsH( targetLayer ) - BdsH( resizeLayer ) } SetUnits( prev_units ) return resizeTxt.size } catch(e) { log.push( 'TextSizeWorkaround '+ e ) } } // TextSizeWorkaround function BdsTL( bdsOrLyr ) { if( bdsOrLyr instanceof ArtLayer ) bdsOrLyr = bdsOrLyr.bounds return [ bdsOrLyr[0], bdsOrLyr[1] ] } // BdsTL function BdsH( bdsOrLyr ) { if( bdsOrLyr instanceof ArtLayer ) bdsOrLyr = bdsOrLyr.bounds return Math.abs( bdsOrLyr[1] - bdsOrLyr[3] ) } // BdsH function BdsW( bdsOrLyr ) { if( bdsOrLyr instanceof ArtLayer ) bdsOrLyr = bdsOrLyr.bounds return Math.abs( bdsOrLyr[0] - bdsOrLyr[2] ) } // BdsW function chID( a ) { return charIDToTypeID( a )} function stID( a ) { return stringIDToTypeID( a )} function SelectLayer( lyr ) { try { if( typeof lyr === 'string' || lyr instanceof String ) lyr = GetLayer( lyr ) activeDocument.activeLayer = lyr return activeDocument.activeLayer } catch(e) { log.push( 'SelectLayer: '+ e ) } } // SelectLayer function GetLayer( ptn ) { try { if( ptn instanceof ArtLayer ) return ptn var lyrs = activeDocument.layers var l, len = lyrs.length || 0 for( l=0; l<len; l++ ) { if( RegExp( ptn ).test( lyrs[l].name )) return lyrs[l] } } catch(e) { log.push( 'GetLayer: '+ e ) } } // GetLayer function IsSmartObj( lyr ) { return lyr.kind == LayerKind.SMARTOBJECT } function TextBoxDimsWorkaround( lyr ) { try { // ps bug: textItem width & height distorted by previous transformations // workaround fills area with text so that layer bounds matches textbox w & h var prev_state = activeDocument.activeHistoryState SetUnits( 'pixels' ) lyr.textItem.kind = TextType.PARAGRAPHTEXT var dup = lyr.duplicate() var duptxt = dup.textItem // set font size to 10% of capital character height // 1 pt would be the most accurate, but it's very cpu intensive // converting for resolution because txt.width & height are always in pts var dup2 = lyr.duplicate() dup2.textItem.contents = 'X' var bH = BdsH( dup2 ) * 72 / activeDocument.resolution duptxt.size = UnitValue( Math.max( 3, bH / 10 ), 'pt' ) log.push( 'size: '+ duptxt.size ) duptxt.useAutoLeading = true duptxt.autoLeadingAmount = 100 duptxt.font = 'MyriadPro-Regular' duptxt.baselineShift = 0 duptxt.fauxBold = false duptxt.fauxItalic = false duptxt.firstLineIndent = 0 duptxt.horizontalScale = 100 duptxt.verticalScale = 100 duptxt.contents = TextFiller() // for large textboxes that need more fill, we double it until it overflows // limit to 3 times because more can cause processing issues // we also 2x font size to lower cycles, at slight cost of accuracy var i = 0 while( i < 3 && TextOverflow( dup ) < 1 ) { if( i++ ) duptxt.size = UnitValue( duptxt.size.value * 2, 'pt' ) log.push( 'size: '+ duptxt.size ) duptxt.kind = TextType.PARAGRAPHTEXT duptxt.contents = duptxt.contents + duptxt.contents } // we can now use bounds as height & width because the box is filled // position is the text baseline origin var dims = { position: lyr.textItem.position, width: dup.bounds[2] - dup.bounds[0] - 1, height: dup.bounds[3] - dup.bounds[1] } // undo the mess we made because we now have our data activeDocument.activeHistoryState = prev_state log.push( 'dims.position: '+ dims.position ) log.push( 'dims.width: '+ dims.width ) log.push( 'dims.height: '+ dims.height ) return dims } catch(e) { log.push( 'TextBoxDimsWorkaround '+ e ) } } // TextBoxDimsWorkaround function TextOverflow( lyr ) { try { var prev_state = activeDocument.activeHistoryState var dup = lyr.duplicate() dup.textItem.kind = TextType.POINTTEXT var overlen = lyr.textItem.contents.length - dup.textItem.contents.length activeDocument.activeHistoryState = prev_state return overlen } catch(e) { log.push( 'TextOverflow '+ e ) } } // TextOverflow function SetUnits( input ) { try { var rUnit, tUnit if( input instanceof Object ) { rUnit = input.ruler tUnit = input.type } else if( IsString( input ) ) rUnit = tUnit = input var prev_units = { ruler: preferences.rulerUnits, type: preferences.typeUnits } switch( rUnit ) { case 'points': case 'pt': preferences.rulerUnits = Units.POINTS break; case 'inches': case 'in': preferences.rulerUnits = Units.INCHES break; case 'centimeters': case 'cm': preferences.rulerUnits = Units.CENTIMETERS break; default: preferences.rulerUnits = Units.PIXELS break } switch( tUnit ) { case 'pixels': case 'px': preferences.typeUnits = TypeUnits.PIXELS break; case 'inches': case 'in': preferences.typeUnits = TypeUnits.INCHES break; case 'centimeters': case 'cm': preferences.typeUnits = TypeUnits.CENTIMETERS break; default: preferences.typeUnits = TypeUnits.POINTS break } log.push( 'SetUnits: '+ preferences.rulerUnits +', '+ preferences.typeUnits ) return prev_units } catch(e) { log.push( 'SetUnits '+ e ) } } // SetUnits function RoundTextRgb( text ) { try { var rgb = text.color.rgb rgb.red = Math.round( Number( rgb.red ) ) rgb.green = Math.round( Number( rgb.green ) ) rgb.blue = Math.round( Number( rgb.blue ) ) return [ rgb.red, rgb.green, rgb.blue ] } catch(e) { log.push( 'RoundTextRgb '+ e ) } } // RoundTextRgb function RgbInList( rgb ) { var inList = false var r = rgb[0], g = rgb[1], b = rgb[2] var limit = 5000, loop = 0, freq = 1000, start = new Date() // csv is sorted ascending by R, then G, then B var csv = File( File($.fileName).parent +'/swatches.csv' ) csv.open( 'r' ); try { var ln = csv.readln() ln = csv.readln() // skip header while( ln != 'end' && ! csv.eof && loop < limit ) { if( ++loop % freq == 0 && new Date() - start >= limit ) throw 'timed out' var rgb2 = ln.split( ',' ) ln = csv.readln() var r2 = Number( rgb2[0] ) if( r < r2 ) break; if( r > r2 ) continue; if( r == r2 ) { var g2 = Number( rgb2[1] ) if( g < g2 ) break; if( g > g2 ) continue; if( g == g2 ) { var b2 = Number( rgb2[2] ) if( b < b2 ) break; if( b > b2 ) continue; if( b == b2 ) inList = true; break; } } } } catch(e) {log.push( 'RgbInList '+ e )} csv.close() return inList } // RgbInList function FormatColor( color ) { try { switch( color.model ) { case ColorModel.GRAYSCALE: return color.gray.gray.toFixed(0) +'% gray' case ColorModel.RGB: return 'rgb '+ [ color.rgb.red.toFixed(0), color.rgb.green.toFixed(0), color.rgb.blue.toFixed(0) ] +' #'+ color.rgb.hexValue case ColorModel.NONE: case undefined: return 'none (full transparency)' default: return color.model +' needs support' } } catch(e) { log.push( 'FormatColor '+ e ) } } // FormatColor function TextFiller() { // can't believe we have to do this for TextBoxDimsWorkaround // performance is better with large fill and fewer cycles return '||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||' } // TextFiller

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Apr 18, 2022 Apr 18, 2022

Copy link to clipboard

Copied

Following up on my earlier comment, I have implemented a solution that fills the textItem with characters so that the layer.bounds will match what the textItem width and height properties should be returning. We're using a lot of very small characters to keep it accurate, but there is a trade-off in performance, expecially when large textItem boxes with small fonts are encountered. So I implemented a loop to hopefully prevent too many characters being added in these cases, at the cost of a little bit of accuracy.

 

Here is a diffchecker composite of a textItem before and after being processed by the script. Magenta indicates pixels that changed. You can see the layer edges in blue did not move at all in this case. In larger text boxes, you might see it shift by a few pixels.

nickcombs_0-1650311404886.png

I should also note that I've commented out the call to RgbInList() because that relies on a swatches.csv file that I won't be sharing here.

var log = []
displayDialogs = DialogModes.NO
ProcessUserText( activeDocument.activeLayer )
displayDialogs = DialogModes.ERROR
alert( log.join('\n') )



function ProcessUserText( lyr ) { try {

  log.push( lyr.name )
  var prev_units = SetUnits( 'pixels' )

  var txt = lyr.textItem
  try { var jstn = txt.justification }
  catch(e) { throw lyr.name +': unable to access text justification' }
  txt.kind = TextType.PARAGRAPHTEXT
  var ang = TextAngle( lyr )
  RotateLayer( -ang, lyr )
  var box = TextBoxDimsWorkaround( lyr )

  // fixes some broken textItem issues
  txt.kind = TextType.POINTTEXT

  var lyr2 = lyr.parent.artLayers.add()
  lyr2.kind = LayerKind.TEXT
  txt2 = lyr2.textItem
  txt2.contents = txt.contents
  txt2.font = txt.font


  // ps bug: https://community.adobe.com/t5/photoshop-ecosystem-discussions/read-font-size-with-script/td-p/10697934
  txt2.size = txt.size
  TextSizeWorkaround( lyr2, lyr )

  try { txt2.color = txt.color }
  catch(e) { txt2.color = TextColorFromSample( txt ) }
  
  var rgb = RoundTextRgb( txt2 )
  
  // if( ! RgbInList( rgb ) ) log.push( 'text color '+ rgb +' not found in list' )
  // else log.push( 'rgb found: '+ rgb )

  txt2.useAutoLeading = true
  txt2.autoKerning = AutoKernType.MANUAL
  txt2.tracking = 0
  txt2.verticalScale = 100
  txt2.horizontalScale = 100
  txt2.baselineShift = 0
  txt2.justification = txt.justification
  log.push( 'jstn: '+ jstn )

  txt2.kind = TextType.PARAGRAPHTEXT
  SetUnits( 'pixels' )
  txt2.position = box.position
  var resFix = activeDocument.resolution / 72
  txt2.width = box.width / resFix
  txt2.height = box.height / resFix
  var adjX = lyr.bounds[0] - lyr2.bounds[0]
  var adjY = lyr.bounds[1] - lyr2.bounds[1]
  log.push( 'adjustments: '+ [adjX,adjY] )
  txt2.width += adjX / resFix
  txt2.height += adjY / resFix
  log.push( 'final w & h: ' + [txt2.width, txt2.height] )

  RotateLayer( ang, lyr2 )

  var n = lyr.name
  lyr2.move( lyr, ElementPlacement.PLACEBEFORE )
  lyr.remove()
  lyr2.name = n

  var tstats = [
    'xy:'+ Number( txt2.position[0] ).toFixed(0)
      +','+ Number( txt2.position[1] ).toFixed(0),
    'deg:'+ang,
    'pt:'+Number( txt2.size ).toFixed(1),
    'font:'+ txt2.font,
    'rgb:'+ rgb,
    'encoded:'+ encodeURI( txt2.contents )
  ].join(' ')

  log.push( lyr2.name +' rebuilt ' + tstats )

  SetUnits( prev_units )
  return lyr2
}
catch(e) { log.push( 'ProcessUserText '+ e ) }

} // ProcessUserText



function IsString( input ) {
  return typeof input === 'string' || input instanceof String
} // IsString



function EditAsSmartObject( lyr ) {
  ConvertSmartLayer( lyr )
  runMenuItem( stID( 'placedLayerEditContents' ) )
  return activeDocument.activeLayer
} // EditAsSmartObject



function ConvertSmartLayer( lyr ) { try {
  SelectLayer( lyr )
  if( IsSmartObj( lyr )) return lyr
  var desc = new ActionDescriptor()
  desc.putInteger( chID( "DocI" ), 219 )
  desc.putInteger( chID( "Idnt" ), 230 )
  desc.putString( chID( "Nm  " ), """Convert to Smart Object""" )
  desc.putBoolean( stID( "hasEnglish" ), true )
  desc.putInteger( chID( "ItmI" ), 3 )
  executeAction( stID( "newPlacedLayer" ), undefined, DialogModes.NO )
  lyr = activeDocument.activeLayer // layer is now a different object
  log.push( lyr.name +' converted to smart object' )
  return lyr }
catch(e) { log.push( 'ConvertSmaartLayer '+ e ) }
} // ConvertSmartLayer



function TextAngle( lyr ) { try {
  // Normalizes text copy to a period(.) and
  // uses baselineShift to create a vector
  var doc = activeDocument
  var prev_state = doc.activeHistoryState
  var angLyr = lyr.duplicate()
  var angTxt = angLyr.textItem
  angTxt.contents = '.'
  angTxt.font = 'MyriadPro-Regular'
  angTxt.size = 3
  angTxt.baselineShift = 0
  var soLyr1 = EditAsSmartObject( angLyr )
  var soDoc = soLyr1.parent
  soDoc.resizeCanvas( 250, 250, AnchorPosition.MIDDLECENTER )
  var soLyr2 = soLyr1.duplicate()
  soLyr2.textItem.baselineShift = 100
  var ang = GetAngle(
    RoundEach( BdsMid( soLyr1 ) ),
    RoundEach( BdsMid( soLyr2 ) ) )
  soDoc.close( SaveOptions.DONOTSAVECHANGES )
  doc.activeHistoryState = prev_state
  log.push( lyr.name +' angle: '+ ang )
  return ang }
catch(e) { log.push( 'TextAngle '+ e ) }
} // TextAngle



function GetAngle( xy1, xy2 ) {
  var ang = 0 - Math.atan( ( xy1[0] - xy2[0] ) / ( xy1[1] - xy2[1] ) ) * 180.0 / Math.PI
  log.push( [xy1,xy2] +' angle: '+ ang )
  return ang
} // GetAngle



function RoundEach( nums ) {
  var it = []
  for( var i=0; i<nums.length; i++ ) {
    it[i] = Math.round( nums[i] ) }
  return it
} // RoundEach



function BdsMid( lyr ) {
  var b = lyr.bounds
  var mid = Midpoint( [ b[0], b[1] ], [ b[2], b[3] ] )
  log.push( lyr.name +' midpoint: '+ mid )
  return mid
} // BdsMid



function Midpoint( xy1, xy2 ) {
  return [ ( xy1[0] + xy2[0] ) / 2, ( xy1[1] + xy2[1] ) / 2 ]
} // Midpoint



function RotateLayer( deg, lyr ) { try {
  lyr = lyr || activeDocument.activeLayer
  if( deg && deg !== 0 ) {
    lyr.rotate( deg )
    log.push( lyr.name +' rotated '+ deg ) } }
catch(e) { log.push( 'RotateLayer '+ e ) }
} // RotateLayer



function TextSizeWorkaround( resizeLayer, targetLayer ) { try {
  var prev_units = SetUnits( 'points' )
  var resizeTxt = resizeLayer.textItem
  var startSize = resizeTxt.size
  log.push( 'startSize: '+ startSize )
  var delta0 = BdsH( targetLayer ) - BdsH( resizeLayer )
  var limit = 5
  while( limit-- && Math.abs( delta0 ) >= 1 ) {
    if( resizeTxt.size < 6 ) return resizeTxt.size = 6
    var upDown = 1
    if( delta0 < 0 ) {
      resizeTxt.size--
      upDown = -1
      delta0 = Math.abs( delta0 ) }
    else resizeTxt.size++
    log.push( 'delta0: '+ delta0 )
    log.push( 'upDown: '+ upDown )
    var delta1 = Math.abs( BdsH( targetLayer ) - BdsH( resizeLayer ) )
    log.push( 'delta1: '+ delta1 )
    var remainingDelta = upDown * delta1 /( delta0 - delta1 )
    log.push( 'remainingDelta: '+ remainingDelta )
    resizeTxt.size = Math.round( resizeTxt.size + remainingDelta )
    log.push( 'resizeTxt.size: '+ resizeTxt.size )
    delta0 = BdsH( targetLayer ) - BdsH( resizeLayer ) }
  SetUnits( prev_units )
  return resizeTxt.size }
catch(e) { log.push( 'TextSizeWorkaround '+ e ) }
} // TextSizeWorkaround



function BdsTL( bdsOrLyr ) {
  if( bdsOrLyr instanceof ArtLayer ) bdsOrLyr = bdsOrLyr.bounds
  return [ bdsOrLyr[0], bdsOrLyr[1] ]
} // BdsTL



function BdsH( bdsOrLyr ) {
  if( bdsOrLyr instanceof ArtLayer ) bdsOrLyr = bdsOrLyr.bounds
  return Math.abs( bdsOrLyr[1] - bdsOrLyr[3] )
} // BdsH



function BdsW( bdsOrLyr ) {
  if( bdsOrLyr instanceof ArtLayer ) bdsOrLyr = bdsOrLyr.bounds
  return Math.abs( bdsOrLyr[0] - bdsOrLyr[2] )
} // BdsW



function chID( a ) { return charIDToTypeID( a )}
function stID( a ) { return stringIDToTypeID( a )}



function SelectLayer( lyr ) { try {
  if( typeof lyr === 'string' || lyr instanceof String ) lyr = GetLayer( lyr )
  activeDocument.activeLayer = lyr
  return activeDocument.activeLayer }
catch(e) { log.push( 'SelectLayer: '+ e ) }
} // SelectLayer



function GetLayer( ptn ) { try {
  if( ptn instanceof ArtLayer ) return ptn
  var lyrs = activeDocument.layers
  var l, len = lyrs.length || 0
  for( l=0; l<len; l++ ) {
    if( RegExp( ptn ).test( lyrs[l].name )) return lyrs[l] } }
  catch(e) { log.push( 'GetLayer: '+ e ) }
} // GetLayer



function IsSmartObj( lyr ) { return lyr.kind == LayerKind.SMARTOBJECT }



function TextBoxDimsWorkaround( lyr ) { try {
  // ps bug: textItem width & height distorted by previous transformations
  // workaround fills area with text so that layer bounds matches textbox w & h

  var prev_state = activeDocument.activeHistoryState

  SetUnits( 'pixels' )
  lyr.textItem.kind = TextType.PARAGRAPHTEXT
  var dup = lyr.duplicate()
  var duptxt = dup.textItem

  // set font size to 10% of capital character height
  // 1 pt would be the most accurate, but it's very cpu intensive
  // converting for resolution because txt.width & height are always in pts
  var dup2 = lyr.duplicate()
  dup2.textItem.contents = 'X'
  var bH = BdsH( dup2 ) * 72 / activeDocument.resolution
  duptxt.size = UnitValue( Math.max( 3, bH / 10 ), 'pt' )
  log.push( 'size: '+ duptxt.size )

  duptxt.useAutoLeading = true
  duptxt.autoLeadingAmount = 100
  duptxt.font = 'MyriadPro-Regular'
  duptxt.baselineShift = 0
  duptxt.fauxBold = false
  duptxt.fauxItalic = false
  duptxt.firstLineIndent = 0
  duptxt.horizontalScale = 100
  duptxt.verticalScale = 100
  duptxt.contents = TextFiller()

  // for large textboxes that need more fill, we double it until it overflows
  // limit to 3 times because more can cause processing issues
  // we also 2x font size to lower cycles, at slight cost of accuracy
  var i = 0
  while( i < 3 && TextOverflow( dup ) < 1 ) {
    if( i++ ) duptxt.size = UnitValue( duptxt.size.value * 2, 'pt' )
    log.push( 'size: '+ duptxt.size )
    duptxt.kind = TextType.PARAGRAPHTEXT
    duptxt.contents = duptxt.contents + duptxt.contents }

  // we can now use bounds as height & width because the box is filled
  // position is the text baseline origin
  var dims = { position: lyr.textItem.position,
    width: dup.bounds[2] - dup.bounds[0] - 1,
    height: dup.bounds[3] - dup.bounds[1] }

  // undo the mess we made because we now have our data
  activeDocument.activeHistoryState = prev_state

  log.push( 'dims.position: '+ dims.position )
  log.push( 'dims.width: '+ dims.width )
  log.push( 'dims.height: '+ dims.height )
  return dims }
catch(e) { log.push( 'TextBoxDimsWorkaround '+ e ) }
} // TextBoxDimsWorkaround



function TextOverflow( lyr ) { try {
  var prev_state = activeDocument.activeHistoryState
  var dup = lyr.duplicate()
  dup.textItem.kind = TextType.POINTTEXT
  var overlen = lyr.textItem.contents.length - dup.textItem.contents.length
  activeDocument.activeHistoryState = prev_state
  return overlen }
catch(e) { log.push(  'TextOverflow '+ e ) }
} // TextOverflow



function SetUnits( input ) { try {
  var rUnit, tUnit
  if( input instanceof Object ) {
    rUnit = input.ruler
    tUnit = input.type }
  else if( IsString( input ) )
    rUnit = tUnit = input
  var prev_units = { ruler: preferences.rulerUnits,
    type: preferences.typeUnits }
  switch( rUnit ) {
    case 'points': case 'pt':
      preferences.rulerUnits = Units.POINTS
      break;
    case 'inches': case 'in':
      preferences.rulerUnits = Units.INCHES
      break;
    case 'centimeters': case 'cm':
      preferences.rulerUnits = Units.CENTIMETERS
      break;
    default:
      preferences.rulerUnits = Units.PIXELS
      break }
  switch( tUnit ) {
    case 'pixels': case 'px':
      preferences.typeUnits = TypeUnits.PIXELS
      break;
    case 'inches': case 'in':
      preferences.typeUnits = TypeUnits.INCHES
      break;
    case 'centimeters': case 'cm':
      preferences.typeUnits = TypeUnits.CENTIMETERS
      break;
    default:
      preferences.typeUnits = TypeUnits.POINTS
      break }
  log.push( 'SetUnits: '+ preferences.rulerUnits +', '+ preferences.typeUnits )
  return prev_units }
catch(e) { log.push( 'SetUnits '+ e ) }
} // SetUnits



function RoundTextRgb( text ) { try {
  var rgb = text.color.rgb
  rgb.red = Math.round( Number( rgb.red ) )
  rgb.green = Math.round( Number( rgb.green ) )
  rgb.blue = Math.round( Number( rgb.blue ) )
return [ rgb.red, rgb.green, rgb.blue ] }
catch(e) { log.push( 'RoundTextRgb '+ e ) }
} // RoundTextRgb



function RgbInList( rgb ) {
  var inList = false
  var r = rgb[0], g = rgb[1], b = rgb[2]
  var limit = 5000, loop = 0, freq = 1000, start = new Date()
  // csv is sorted ascending by R, then G, then B
  var csv = File( File($.fileName).parent +'/swatches.csv' )
  csv.open( 'r' ); try {
    var ln = csv.readln()
    ln = csv.readln() // skip header
    while( ln != 'end' && ! csv.eof && loop < limit ) {
      if( ++loop % freq == 0 && new Date() - start >= limit )
        throw 'timed out'
      var rgb2 = ln.split( ',' )
      ln = csv.readln()
      var r2 = Number( rgb2[0] )
      if( r < r2 ) break;
      if( r > r2 ) continue;
      if( r == r2 ) {
        var g2 = Number( rgb2[1] )
        if( g < g2 ) break;
        if( g > g2 ) continue;
        if( g == g2 ) {
          var b2 = Number( rgb2[2] )
          if( b < b2 ) break;
          if( b > b2 ) continue;
          if( b == b2 ) inList = true; break; } } } }
  catch(e) {log.push( 'RgbInList '+ e )}
  csv.close()
  return inList
} // RgbInList



function FormatColor( color ) { try {
  switch( color.model ) {
    case ColorModel.GRAYSCALE:
      return color.gray.gray.toFixed(0) +'% gray'
    case ColorModel.RGB:
      return 'rgb '+ [
        color.rgb.red.toFixed(0),
        color.rgb.green.toFixed(0),
        color.rgb.blue.toFixed(0) ]
      +' #'+ color.rgb.hexValue
    case ColorModel.NONE:
    case undefined:
      return 'none (full transparency)'
    default:
      return color.model +' needs support' } }
catch(e) { log.push( 'FormatColor '+ e ) }
} // FormatColor



function TextFiller() {
  // can't believe we have to do this for TextBoxDimsWorkaround
  // performance is better with large fill and fewer cycles
return '||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||'
} // TextFiller

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines