Tuesday, April 16, 2013

Photoshop Scripting with Javascript

Photoshop has a couple of kinds of automation, and today I learned about scripting it with Javascript. You can also record actions into macros in the Actions toolbox/window; though these are somewhat limited, they can be assigned a hotkey from a short range of the function keys (F2, F3, etc.)

Here's the script I threw together from examples and experimenting. Its purpose is to visibly watermark a folder of images with one image. It prompts you to choose a folder of images that you want to modify, then an output folder, then the watermark image you want pasted onto the images from the folder. At each image, the script prompts you to specify which corner of the image you want the watermark on.

 /*   
 Description:  
 This script pastes one image to the chosen corner of each image in a folder.  
 */  
 // enable double clicking from the   
 // Macintosh Finder or the Windows Explorer  
 #target photoshop  
 ////////////////////////////////////  
 /// Options and Variables  
 ///  
 ////////////////////////////////////  
   
 //margin is the number of pixels you want to space the edge of the watermark  
 //from the edge of the image  
 var marginX = 5;   
 var marginY = 5;  
   
 //save a copy of the modified images to a jpeg file   
 var fileSaveOptions = new JPEGSaveOptions();  
 fileSaveOptions.embedColorProfile = true;  
 fileSaveOptions.formatOptions = FormatOptions.STANDARDBASELINE;  
 fileSaveOptions.matte = MatteType.NONE;  
 fileSaveOptions.quality = 10;  
   
 // Close the file without saving  
 var documentCloseOptions = SaveOptions.DONOTSAVECHANGES;  
                  
 // Make Photoshop the frontmost application  
 // in case we double clicked the file  
 app.bringToFront();  
   
 /////////////////////////  
 // SETUP  
 /////////////////////////  
   
 // A list of file extensions to skip, keep them lower case  
 gFilesToSkip = Array( "db", "xmp", "xcf", "thm", "txt", "doc", "md0", "tb0", "adobebridgedb", "adobebridgedbt", "bc", "bct" );  
   
 /////////////////////////  
 // MAIN  
 /////////////////////////  
   
 // Pops open a dialog for the user to  
 // choose the folder of documents to process  
 var inputFolder = Folder.selectDialog("Select a folder of documents to process");  
   
 // Pops open a dialog for the user to  
 // set the output folder  
 var outputFolder = Folder.selectDialog("Select a folder for the output files");  
   
 //choose the file to watermark with  
 var logoFile = File.openDialog ("Select the logo file", "*.png", false);  
 var logo = open(logoFile);  
 //select all of the watermark  
 logo.selection.selectAll();  
 //copy the watermark to the clipboard  
 logo.selection.copy();  
   
 // Open Folder of Images  
 OpenFolder();  
 /////////////////////////  
 // FUNCTIONS  
 /////////////////////////  
   
 // Given the a Folder of files, open them  
 function OpenFolder() {  
      var filesOpened = 0;  
      var fileList = inputFolder.getFiles();  
      for ( var i = 0; i < fileList.length; i++ ) {  
           // Make sure all the files in the folder are compatible with PS  
           if ( fileList[i] instanceof File && ! fileList[i].hidden && ! IsFileOneOfThese( fileList[i], gFilesToSkip )) {  
                var photo = open( fileList[i] );  
                filesOpened++;  
                  
                //add a new layer for the watermark  
                var pasteLayer = photo.artLayers.add();  
                //paste the watermark into the new layer  
                photo.paste();  
                //ask the user which corner the watermark should be in  
                var corner = prompt("Top Left = 1, Top Right = 2, \r\nBottom Left = 3, Bottom Right = 4, \r\n Quit = 5","1","Which corner?");  
                if(corner == 1)  
                     topLeft(pasteLayer);  
                else if(corner == 2)  
                     topRight(pasteLayer);  
                else if(corner == 3)  
                     bottomLeft(pasteLayer);  
                else if(corner == 4)  
                     bottomRight(pasteLayer);  
                else if(corner == 5)  
                     break; //stop the program  
   
                //Save a copy of the file  
                app.activeDocument.saveAs(outputFolder, fileSaveOptions, true, Extension.LOWERCASE);  
                //Close the modified file  
                app.activeDocument.close(documentCloseOptions);  
           }  
      }  
 }  
   
 // given a file name and a list of extensions  
 // determine if this file is in the list of extensions  
 function IsFileOneOfThese( inFileName, inArrayOfFileExtensions ) {  
      var lastDot = inFileName.toString().lastIndexOf( "." );  
      if ( lastDot == -1 ) {  
           return false;  
      }  
      var strLength = inFileName.toString().length;  
      var extension = inFileName.toString().substr( lastDot + 1, strLength - lastDot );  
      extension = extension.toLowerCase();  
      for (var i = 0; i < inArrayOfFileExtensions.length; i++ ) {  
           if ( extension == inArrayOfFileExtensions[i] ) {  
                return true;  
           }  
      }  
      return false;  
 }  
 function topLeft( layer ){// layerObject, Number, Number  
      // if can not move layer return  
   if(layer.iisBackgroundLayer||layer.positionLocked) return  
   // get the layer bounds  
   var layerBounds = layer.bounds;  
   // get top left position  
   var layerX = layerBounds[0].value;  
   var layerY = layerBounds[1].value;  
   // the difference between where layer needs to be and is now  
   var deltaX = marginX-layerX;  
   var deltaY = marginY-layerY;  
   // move the layer into position  
   layer.translate (deltaX, deltaY);  
 }  
 function topRight( layer ){  
      // if can not move layer return  
   if(layer.iisBackgroundLayer||layer.positionLocked) return  
   // get the layer bounds  
   var layerBounds = layer.bounds;  
   // get top left position  
   var layerX = layerBounds[0].value;  
   var layerY = layerBounds[1].value;  
   // the difference between where layer needs to be and is now  
   var deltaX = layerX-marginX;  
   var deltaY = marginY-layerY;  
   // move the layer into position  
   layer.translate (deltaX, deltaY);  
 }  
 function bottomRight( layer ){  
      // if can not move layer return  
   if(layer.iisBackgroundLayer||layer.positionLocked) return  
   // get the layer bounds  
   var layerBounds = layer.bounds;  
   // get top left position  
   var layerX = layerBounds[0].value;  
   var layerY = layerBounds[1].value;  
   // the difference between where layer needs to be and is now  
   var deltaX = layerX-marginX;  
   var deltaY = layerY-marginY;  
   // move the layer into position  
   layer.translate (deltaX, deltaY);  
 }  
 function bottomLeft( layer ){  
      // if can not move layer return  
   if(layer.iisBackgroundLayer||layer.positionLocked) return  
   // get the layer bounds  
   var layerBounds = layer.bounds;  
   // get top left position  
   var layerX = layerBounds[0].value;  
   var layerY = layerBounds[1].value;  
   // the difference between where layer needs to be and is now  
   var deltaX = marginX-layerX;  
   var deltaY = layerY-marginY;  
   // move the layer into position  
   layer.translate (deltaX, deltaY);  
 }  

My references and borrowed code:
http://www.tranberry.com/photoshop/photoshop_scripting/PS4GeeksOrlando/IntroScripts/openFolder.jsx
http://forums.adobe.com/message/4287129?tstart=0, reply number 3

Tuesday, April 2, 2013

Windows Domain Controller with Cisco Router DNS

You can install a Windows domain controller without DNS if you have another DNS server, such as a Cisco router with an IOS image that supports the `ip dns primary` configuration command.
Windows domain clients will need SRV records in the DNS in order to authenticate and join the domain. Here is an example of the DNS records you will need for a Windows 2008 R2 server to join a domain (the domain controller is also Win2008R2):
ip host ns.example.com 10.88.33.4  
ip host example.com ns ns.example.com  
ip host dc1.example.com 10.88.33.2  
ip host _ldap._tcp.example.com srv 0 0 389 dc1.example.com  
ip host _ldap._tcp.dc._msdcs.example.com srv 0 0 88 dc1.example.com 
ip host _kdc._tcp.example.com srv 0 0 88 dc1.example.com  
ip host WIN-IRQG06G53P6.example.com 10.88.33.2  
!  
interface GigabitEthernet0/0
 description WAN
 ip address 10.89.28.33 255.255.255.0
 ip nat outside
 ip dns view-group default
interface GigabitEthernet0/1
 description LAN
 ip address 10.88.33.4 255.255.255.0
 ip nat outside
 ip dns view-group default
!
ip dns view default
 logging
 domain name example.com
 domain name-server 10.88.33.4
 dns forwarder 8.8.8.8
 dns forwarder 8.8.4.4
 dns forwarding source-interface GigabitEthernet0/1
ip dns view-list default
 view default 5
!
ip dns server  
ip dns primary example.com soa ns.example.com admin@example.com 21600 900 7776000 86400
!

The line 'ip host WIN-IRQG06G53P6.example.com 10.88.33.2' is there to show that even though I set the dc1's hostname to "dc1" in Windows, this domain controller still responds to domain join requests using this name (and the client could not join the domain until this entry was here). If you have issues finding this, debug DNS on the Cisco router like this:
debug ip dns name-list
debug ip dns view
debug ip dns view-list
terminal monitor