home *** CD-ROM | disk | FTP | other *** search
/ PC Extra 07 & 08 / pca1507.iso / Software / psp8 / Data1.cab / GridMaker.PspScript < prev    next >
Encoding:
Text File  |  2003-04-22  |  14.9 KB  |  359 lines

  1. from JascApp import *
  2. from Tkinter import *
  3. import tkMessageBox
  4. import JascUtils
  5. import string
  6. import sys
  7.  
  8. #This script brings up a dialog that prompts the user for the x/y spacing of
  9. #the grid (in pixels).  The grid will be drawn using the paintbrush, using
  10. #whatever foreground material is set on the materials palette.
  11. #
  12. #When the script completes the grid will be saved in the patterns directory
  13. #so it can be used at any time in the future without having to run the script.
  14. #
  15. #The sequence is:
  16. #    - prompt the user for the grid settings
  17. #    - call the NameFromMaterial method in JascUtils to a name that
  18. #      describes the foreground material.
  19. #    - call the CreateGrid function to make a new image containing exactly
  20. #      one repetition of the pattern.  It does this by creating an image that
  21. #      is as big as the pattern, and drawing lines down the right and bottom
  22. #      edges.
  23. #    - call SavePatternFile to save the pattern image as a file in the patterns
  24. #      directory.  Since PSP maintains a cache of all the patterns, before
  25. #      we can use it we have to notify the cache that we have made a change.
  26. #      That is done with a call to EventNotify.
  27. #    - Finally we make a new layer, and flood fill it with the pattern we
  28. #      just created.  As the pattern is tiled it creates the grid we want.
  29.  
  30. def ScriptProperties():
  31.     return {
  32.         'Author': 'Joe Fromm',
  33.         'Copyright': 'Copyright (C) 2002-2003, Jasc Software Inc., All Rights Reserved. Permission to create derivate works of this script is granted provided this copyright notice is included',
  34.         'Description': 'Add a layer to the image with a grid defined by the user.',
  35.         'Host': 'Paint Shop Pro',
  36.         'Host Version': '8.00'
  37.         }
  38.  
  39. class GridMakerDialog(Frame):
  40.     ''' define the dialog used to prompt the user for grid information'''
  41.     def __init__( self, parent, title ):
  42.         Frame.__init__(self)    # init our parent
  43.  
  44.         # if we exit with OK this will be set to 1.  A zero means we pressed cancel
  45.         self.OKPressed = 0
  46.         
  47.         # define all the variables attached to the controls
  48.         self.XSpacing = IntVar()
  49.         self.XSpacing.set( 50 )
  50.  
  51.         self.YSpacing = IntVar()
  52.         self.YSpacing.set( 50 )
  53.         
  54.         # define the basics of the window
  55.         self.pack(expand=YES, fill=BOTH)
  56.         self.master.title('Define Grid')
  57.        
  58.         # put some explanatory text on the window
  59.         Label( self, text = 'This will add a new layer to your image '
  60.                             'and draw a grid at the pixel spacing you '
  61.                             'specify.\nThe color of the grid will be the '
  62.                             'foreground material of the application',
  63.                justify=LEFT ).pack(expand=YES, fill=BOTH, side=TOP)
  64.  
  65.         # make a subframe to hold the horizontal size controls
  66.         XFrame = Frame( self )
  67.         XLabel = Label( XFrame, text='Horizontal spacing (pixels):', width=30 )
  68.         XLabel.pack( expand=YES, fill=BOTH, side=LEFT )
  69.         self.XEntry = Entry( XFrame, textvariable=self.XSpacing )
  70.         self.XEntry.pack( expand=YES, fill=BOTH, side=RIGHT )
  71.         XFrame.pack(side=TOP)
  72.         
  73.         # do the same thing for the vertical size controls
  74.         YFrame = Frame( self )
  75.         YLabel = Label( YFrame, text='Vertical spacing (pixels):', width=30 )
  76.         YLabel.pack( expand=YES, fill=BOTH, side=LEFT )
  77.         self.YEntry = Entry( YFrame, textvariable=self.YSpacing )
  78.         self.YEntry.pack( expand=YES, fill=BOTH, side=RIGHT )
  79.         YFrame.pack(side=TOP)
  80.         
  81.         # put OK/Cancel buttons on the dialog - parts of this lifted from TkSimpleDialog
  82.         ButtonFrame = Frame(self)
  83.         OKButton = Button( ButtonFrame, text="OK", width=10,
  84.                            command=self.OnOK, default=ACTIVE )
  85.         OKButton.pack(side=LEFT, padx=5, pady=5)
  86.         CancelButton = Button( ButtonFrame, text="Cancel", width=10,
  87.                                command=self.OnCancel )
  88.         CancelButton.pack(side=LEFT, padx=5, pady=5)
  89.         ButtonFrame.pack()
  90.         
  91.         self.bind("<Return>", self.OnOK)
  92.         self.bind("<Escape>", self.OnCancel)
  93.        
  94.  
  95.     def OnOK(self, event=None):
  96.         ''' called by pressing the OK button - validates data, and if no error
  97.             sets a good return code and dismisses the dialog by calling OnCancel
  98.         '''
  99.         try:
  100.             X = self.XSpacing.get()
  101.         except ValueError:
  102.             X = 0
  103.  
  104.         try:            
  105.             Y = self.YSpacing.get()
  106.         except ValueError:
  107.             Y = 0
  108.         
  109.         if X < 2 or X > 1000:
  110.             tkMessageBox.showerror( 'Horizontal Spacing invalid',
  111.                                     'The horizontal spacing value must be between 2 and 1000' )
  112.             return 
  113.         elif Y < 2 or Y > 1000:
  114.             tkMessageBox.showerror( 'Vertical Spacing invalid',
  115.                                     'The vertical spacing value must be between 2 and 1000' )
  116.             return
  117.  
  118.         # if we got here we passed validation
  119.         self.OKPressed = 1
  120.         
  121.         # finish by pressing the Cancel button
  122.         self.OnCancel()
  123.  
  124.     def OnCancel(self, event=None):
  125.         # on cancel we simply terminate the message loop
  126.         self.quit()
  127.  
  128.  
  129. def CreateGrid( Environment, XSpacing, YSpacing ):
  130.     ''' Create a grid that can be used as a pattern fill.  We do this by
  131.         creating a new document of the size desired, and then drawing down
  132.         the right hand and bottom edges.  When tiled, this results in a grid
  133.         of the proper dimensions.
  134.  
  135.         The current foreground material is used for the paint stroke.
  136.  
  137.         returns the document created        
  138.     '''
  139.     # first create a new image
  140.     App.Do( Environment, 'NewFile', {
  141.             'Width': XSpacing, 
  142.             'Height': YSpacing, 
  143.             'ColorDepth': App.Constants.Colordepth.SixteenMillionColor, 
  144.             'DimensionUnits': App.Constants.DimensionType.Pixels, 
  145.             'ResolutionUnits': App.Constants.ResolutionUnits.PixelsPerIn, 
  146.             'Resolution': 300, 
  147.             'FillMaterial': {
  148.                 'Color': (0,0,0), 
  149.                 'Pattern': None, 
  150.                 'Gradient': None, 
  151.                 'Texture': None
  152.                 }, 
  153.             'Transparent': App.Constants.Boolean.true, 
  154.             'VectorBackground': App.Constants.Boolean.false, 
  155.             'GeneralSettings': {
  156.                 'ExecutionMode': App.Constants.ExecutionMode.Silent, 
  157.                 'AutoActionMode': App.Constants.AutoActionMode.Match
  158.                 }
  159.             })
  160.  
  161.     TargetDoc = App.ActiveDocument    
  162.  
  163.     # now draw on it at the right and bottom edges using the foreground material
  164.     App.Do( Environment, 'PaintBrush', {
  165.             'BrushTip': {
  166.                 'BrushVariance': {
  167.                     'SizeVariance': App.Constants.VarianceMethod.None, 
  168.                     'SizeJitter': 0, 
  169.                     'OpacityVariance': App.Constants.VarianceMethod.None, 
  170.                     'OpacityJitter': 0, 
  171.                     'DensityVariance': App.Constants.VarianceMethod.None, 
  172.                     'DensityJitter': 0, 
  173.                     'RotationVariance': App.Constants.VarianceMethod.None, 
  174.                     'RotationJitter': 0, 
  175.                     'ThicknessVariance': App.Constants.VarianceMethod.None, 
  176.                     'ThicknessJitter': 0, 
  177.                     'FadeRate': 100, 
  178.                     'ColorBlendVariance': App.Constants.VarianceMethod.None, 
  179.                     'ColorBlendJitter': 0, 
  180.                     'PositionJitter': 0, 
  181.                     'UseScaledPositionJitter': App.Constants.Boolean.false, 
  182.                     'ImpressionsPerStep': 1
  183.                     }, 
  184.                 'Shape': App.Constants.BrushShape.Round, 
  185.                 'CustomBrush': None, 
  186.                 'Size': 1, 
  187.                 'Hardness': 100, 
  188.                 'Density': 100, 
  189.                 'Rotation': 0, 
  190.                 'Thickness': 100, 
  191.                 'Step': 25
  192.                 }, 
  193.             'Brush': {
  194.                 'Opacity': 100, 
  195.                 'ContinuousPaint': App.Constants.Boolean.false, 
  196.                 'WetLookPaint': App.Constants.Boolean.false, 
  197.                 'BlendMode': App.Constants.BlendMode.Normal
  198.                 }, 
  199.             'PrimaryMaterial': App.Constants.MaterialRef.Foreground, 
  200.             'ForegroundMaterial': None, 
  201.             'BackgroundMaterial': {  # we don't use a background, but make sure it is not null
  202.                 'Color': (0,0,0), 
  203.                 'Pattern': None, 
  204.                 'Gradient': None, 
  205.                 'Texture': None
  206.                 },  
  207.             'Stroke': [
  208.                 (App.Constants.PathEntryInterpretation.Absolute,(0, YSpacing-1),0,1,0,1,0,1,0),
  209.                 (App.Constants.PathEntryInterpretation.Absolute,(XSpacing-1, YSpacing-1),0,1,0,1,0,1,0),
  210.                 (App.Constants.PathEntryInterpretation.Absolute,(XSpacing-1, 0),0,1,0,1,0,1,0)
  211.                 ], 
  212.             'GeneralSettings': {
  213.                 'ExecutionMode': App.Constants.ExecutionMode.Default, 
  214.                 'AutoActionMode': App.Constants.AutoActionMode.Match
  215.                 }
  216.             }, TargetDoc )
  217.  
  218.     return TargetDoc    
  219.  
  220. def SavePatternFile( Environment, PatternName, Doc ):
  221.     'save the active image as a pattern file, using the specified name.'
  222.     
  223.     # we need to get the file locations info and look up the pattern directory
  224.     Dirs = App.Do( Environment, 'ReturnFileLocations' )
  225.     PatternPath = Dirs['Patterns'][0]
  226.  
  227.     # data returned from ReturnFileLocations is in a form intended to be
  228.     # script syntax, so all \ characters are doubled so that they don't
  229.     # count as delimiters.  In this case we are using them as python strings
  230.     # and not running them back through the interpreter, so we turn all the
  231.     # double backslashes into singles.
  232.     PatternPath = string.replace( PatternPath, '\\\\', '\\' )
  233.     FullPath = PatternPath + '\\' + PatternName + '.PspImage'
  234.  
  235.     # save the file to the pattern directory    
  236.     App.Do( Environment, 'FileSaveAs', {
  237.             'Encoding': {
  238.                 'PSP': {
  239.                     'Compression': App.Constants.PspCompression.LZ77, 
  240.                     'Version': App.Constants.PspVersion.PSP8
  241.                     }
  242.                 }, 
  243.             'FileName': FullPath, 
  244.             'FileFormat': App.Constants.FileFormat.PSP, 
  245.             'FormatDesc': 'Paint Shop Pro Image', 
  246.             'GeneralSettings': {
  247.                 'ExecutionMode': App.Constants.ExecutionMode.Silent, 
  248.                 'AutoActionMode': App.Constants.AutoActionMode.AllAlways
  249.                 }, 
  250.             'DefaultProperties': []
  251.             }, Doc )
  252.  
  253.     # tell PSP we just invalidated the pattern cache
  254.     App.Do( Environment, 'EventNotify', { 'EventType': App.Constants.Event.PatternCache } )
  255.     
  256.     # don't need the pattern file anymore - we'll let the material palette load it for us
  257.     App.Do( Environment, 'FileClose', {
  258.             'GeneralSettings': {
  259.                 'ExecutionMode': App.Constants.ExecutionMode.Silent, 
  260.                 'AutoActionMode': App.Constants.AutoActionMode.Match
  261.                 }
  262.             }, Doc)
  263.  
  264. def Do(Environment):
  265.     if JascUtils.RequireADoc( Environment ) == App.Constants.Boolean.false:
  266.         return
  267.  
  268.     Target = App.TargetDocument
  269.     
  270.     ' Create a grid on a new layer, using spacing entered by the user'
  271.     # we need a foreground material - error if we don't have one
  272.     Foreground = App.Do( Environment, 'GetMaterial',{
  273.                         'IsPrimary': App.Constants.Boolean.true,
  274.                         'GeneralSettings': {
  275.                             'ExecutionMode': App.Constants.ExecutionMode.Silent 
  276.                             }, 
  277.                         })
  278.     
  279.     if JascUtils.IsNullMaterial( Foreground ):
  280.         App.Do(Environment,  'MsgBox', {
  281.                 'Buttons': App.Constants.MsgButtons.OK, 
  282.                 'Icon': App.Constants.MsgIcons.Stop, 
  283.                 'Text': 'This script requires a non-null foreground material.', 
  284.                 })
  285.         return
  286.  
  287.     # create the root TK window    
  288.     root = Tk()
  289.     
  290.     # create the dialog and show the dialog
  291.     Dlg = GridMakerDialog( root, 'Enter Grid Spacing')
  292.     # tell PSP that a foreign dialog is running.  This causes PSP to do some additional
  293.     # work to keep the UI updating properly and to prevent the script window from going
  294.     # behind PSP.
  295.     App.Do( Environment, 'StartForeignWindow', { 'WindowHandle': int(Dlg.winfo_id()) } )
  296.     
  297.     root.mainloop()
  298.     root.destroy()
  299.     App.Do( Environment, 'StartForeignWindow', { 'WindowHandle': 0 } )
  300.     
  301.     # if the user pressed cancel in the dialog just return
  302.     if not Dlg.OKPressed:
  303.         print 'Cancel pressed - aborting'
  304.         return
  305.     
  306.     XSpacing = Dlg.XSpacing.get()
  307.     YSpacing = Dlg.YSpacing.get()
  308.  
  309.     # since we are going to save the grid as a pattern file, lets try
  310.     # to name it in a quasi-descriptive manner.  We'll embed the grid
  311.     # size and the material description in the name.
  312.     PatternName = JascUtils.NameFromMaterial( Foreground )
  313.     PatternFile = 'Grid%dx%d_%s' % ( XSpacing, YSpacing, PatternName )
  314.     print 'Patternfile = ', PatternFile
  315.     
  316.     # Create the grid using the parameters we got from the dilaog    
  317.     PatternDoc = CreateGrid( Environment, XSpacing, YSpacing )
  318.  
  319.     # save the grid as a pattern file    
  320.     SavePatternFile( Environment, PatternFile, PatternDoc )
  321.     
  322.     # finally on to the heart of the matter - make a new layer, and then
  323.     # flood fill it with the pattern we went to all the trouble to create.
  324.     App.Do( Environment, 'NewRasterLayer', {
  325.             'General': {
  326.                 'Name': 'Grid Overlay', 
  327.                 }, 
  328.             'GeneralSettings': {
  329.                 'ExecutionMode': App.Constants.ExecutionMode.Silent, 
  330.                 'AutoActionMode': App.Constants.AutoActionMode.Match
  331.                 }
  332.             }, Target )
  333.  
  334.     # now flood fill it with the grid we created
  335.     App.Do( Environment, 'Fill', {
  336.             'BlendMode': 0, 
  337.             'MatchMode': 1, 
  338.             'Material': {
  339.                 'Color': None, 
  340.                 'Pattern': {
  341.                     'Name': PatternFile, 
  342.                     'Image': None, 
  343.                     'Angle': 0.000000, 
  344.                     'Scale': 100.000000
  345.                     }, 
  346.                 'Gradient': None, 
  347.                 'Texture': None
  348.                 }, 
  349.             'UseForground': App.Constants.Boolean.true, 
  350.             'Opacity': 100, 
  351.             'Point': (0,0), 
  352.             'SampleMerged': 0, 
  353.             'Tolerance': 20, 
  354.             'GeneralSettings': {
  355.                 'ExecutionMode': App.Constants.ExecutionMode.Default, 
  356.                 'AutoActionMode': App.Constants.AutoActionMode.Match
  357.                 }
  358.             }, Target )
  359.