Page 2 of 2

Re: How to document current properties

PostPosted: Thu May 30, 2019 11:11 pm
by Corelius
Just in case anyone has already grabbed my first-posted version, I just tweaked the script to add an option (at the end) to open the log in Notepad.

Re: How to document current properties

PostPosted: Fri May 31, 2019 2:49 am
by cosmicDread
Thanks for sharing!

Re: How to document current properties

PostPosted: Fri May 31, 2019 11:08 pm
by Corelius
Here's an alternative version of my script that creates a much shorter and easier-to-read report that just includes the settings for each adjustment layer type that I'd be most likely to tweak.

It subjects the following layer types to the abridged treatment:

Levels, Histogram, Curves, White Balance, Hue/Saturation/Lightness, Vibrancy, Brightness/Contrast, and Fill Light/Clarity.

For other types of layers: Depending on how you set the IncludeNonHandledLayerTypes variable, it either reports no settings (if False) or all settings (if True). (It's set to True in the copy below.)

Code: Select all
from PSPApp import *
import pprint
import datetime
import subprocess

def ScriptProperties():
    return {
        'Host': u'PaintShop Pro',
        'Host Version': u'18.00'
        }

def Do(Environment):

    IncludeNonHandledLayerTypes = True

    now = datetime.datetime.now()
    FourDigitYrMo = now.strftime("%Y")[2:] + now.strftime("%m")
    LogFile = 'C:\\D\\ProgD\\PSPX9\\Logs\\LayerData_' + FourDigitYrMo + '.log'
    MajorLine = ('=' * 72) + '\n'
    MinorLine = ('-' * 68) + '\n'

    f = open(LogFile, 'a')
    f.write(MajorLine)
    f.write(App.TargetDocument.Name + '\n')
    f.write('   ' + now.strftime("%Y-%m-%d, %H:%M") + '\n')
    f.write(MajorLine)

    # get the path from the bottom from the active layer so we can restore it when done
    Props = App.Do( Environment, 'ReturnLayerProperties' )
    PathBack = Props[ 'Path' ]

    # start by selecting the bottommost layer in the image. 
    App.Do( Environment, 'SelectLayer', { 'Path': (9999,-9999, [], False ) } )

    # now iterate up the layer stack
    FoundLayer = True
    LayerNum = 1
    while FoundLayer == True:
        HandledLayer = False
        # get all layer properties
        Props = App.Do( Environment, 'ReturnLayerProperties' )
        # To create my layer heading, I also separately assign the
        # names of the layer and the layer's type to variables.
        LayerName = Props['General']['Name']
        for x in App.Constants.LayerType.Values():
            if x[1] == Props['LayerType']:
                break;
        LayerTypeName = x[0]  # Returns the name of the constant
       
        if LayerNum > 1:
            f.write(MinorLine)
        f.write(LayerName + '              [--' + LayerTypeName + ' layer--]\n')
        f.write(MinorLine)
        if Props['General']['IsVisible'] == False:
            f.write('***** NOT VISIBLE *****' + '\n')

        if Props[ 'LayerType' ] == App.Constants.LayerType.Raster:
            HandledLayer = True
         
        if Props[ 'LayerType' ] == App.Constants.LayerType.Levels:
            HandledLayer = True
            for x in ['RGB', 'Red', 'Green', 'Blue']:
                f.write(x + ': ' + str(Props['Levels'][x]) + '\n')
       
        if Props[ 'LayerType' ] == App.Constants.LayerType.Histogram:
            HandledLayer = True
            for x in ['LuminanceChannel', 'RedChannel', 'GreenChannel', 'BlueChannel']:
                f.write(x[:-7] + '\n')
                f.write('  Low: ' + str(Props['HistogramAdjustment'][x]['LowClipLimit']) + ', ')
                f.write('Gamma: ' + str(Props['HistogramAdjustment'][x]['Gamma']) + ', ')
                f.write('High: ' + str(Props['HistogramAdjustment'][x]['HighClipLimit']) + '\n')
                f.write('  Midtones: ' + str(Props['HistogramAdjustment'][x]['Appearance']) + '\n')

        if Props[ 'LayerType' ] == App.Constants.LayerType.Curves:
            HandledLayer = True
            for x in ['RGB', 'Red', 'Green', 'Blue']:
                f.write(x + ': ')
                f.write(str(Props['CurveParams'][x]) + '\n')

        if Props[ 'LayerType' ] == App.Constants.LayerType.ColorBalance:
            HandledLayer = True
            for x in ['Shadow', 'Midtone', 'Highlight']:
                f.write(x + ': ' + str(Props['ColorBalance'][x]) + '\n')
            f.write('Preserve Luminance: ' + str(Props['ColorBalance']['PreserveLuminance']) + '\n')

        if Props[ 'LayerType' ] == App.Constants.LayerType.HueSatLum:
            HandledLayer = True
            f.write('H: ' + str(Props['HSL']['Master'][0]) + ', ')
            f.write('S: ' + str(Props['HSL']['Master'][1]) + ', ')
            f.write('L: ' + str(Props['HSL']['Master'][2]) + '\n')

        if Props[ 'LayerType' ] == App.Constants.LayerType.Vibrancy:
            HandledLayer = True
            f.write('Vibrancy: ' + str(Props['Vibrancy']['Vibrancy']) + '\n')

        if Props[ 'LayerType' ] == App.Constants.LayerType.BrightnessContrast:
            HandledLayer = True
            f.write('B: ' + str(Props['BrightnessContrast']['Brightness']) + ', ')
            f.write('C: ' + str(Props['BrightnessContrast']['Contrast']) + '\n')

        if Props[ 'LayerType' ] == App.Constants.LayerType.FillLightClarity:
            HandledLayer = True
            f.write('C: ' + str(Props['FillLightClarity']['Clarity']) + ', ')
            f.write('FL: ' + str(Props['FillLightClarity']['FillLight']) + '\n')

        if (HandledLayer == False) and (IncludeNonHandledLayerTypes == True):
            pprint.pprint(Props, width=200, stream=f)

        # go to the next layer
        FoundLayer = App.Do( Environment, 'SelectNextLayer' )
        LayerNum = LayerNum + 1

    f.write(MajorLine + '\n')
    f.close()

    # now that the loop is done, select the bottom layer and then
    # use the pathback to restore the layer that was active when we started
    App.Do( Environment, 'SelectLayer', { 'Path': (9999,-9999, [], False ) } )
    App.Do( Environment, 'SelectLayer', { 'Path': PathBack } )
   
    MsgBoxResult = App.Do(Environment, 'MsgBox', {
        'Buttons': App.Constants.MsgButtons.YesNo,
        'Icon': App.Constants.MsgIcons.Question,
        'Text': 'Open the log file?'
    })
    if MsgBoxResult == 1:
        CommandString = 'notepad.exe ' + LogFile
        subprocess.Popen(CommandString)

Here's a sample of the output sent to the log file:

Code: Select all
========================================================================
D:\P\Scans\2019-05\Demo_01.pspimage
   2019-05-31, 14:53
========================================================================
Background              [--Raster layer--]
--------------------------------------------------------------------
--------------------------------------------------------------------
Levels 1              [--Levels layer--]
--------------------------------------------------------------------
RGB: (0, 255, 0.8446063173541758, 0, 255)
Red: (0, 255, 0.994353436858858, 0, 255)
Green: (0, 255, 1.0, 0, 255)
Blue: (0, 255, 1.0, 0, 255)
--------------------------------------------------------------------
Histogram adjustment layer 1              [--Histogram layer--]
--------------------------------------------------------------------
***** NOT VISIBLE *****
Luminance
  Low: 0, Gamma: 1.0, High: 255
  Midtones: 0
Red
  Low: 0, Gamma: 1.0, High: 255
  Midtones: 0
Green
  Low: 0, Gamma: 1.0, High: 255
  Midtones: 0
Blue
  Low: 0, Gamma: 1.0, High: 255
  Midtones: 0
--------------------------------------------------------------------
Curves 1              [--Curves layer--]
--------------------------------------------------------------------
RGB: [(0, 0), (38, 22), (64, 46), (128, 110), (160, 152), (192, 192), (228, 224), (255, 255)]
Red: [(0, 0), (255, 255)]
Green: [(0, 0), (255, 255)]
Blue: [(0, 0), (255, 255)]
--------------------------------------------------------------------
White Balance 1              [--ColorBalance layer--]
--------------------------------------------------------------------
Shadow: (0, 0, 0)
Midtone: (8, 0, -8)
Highlight: (-3, 0, 3)
Preserve Luminance: True
--------------------------------------------------------------------
Hue/Saturation/Lightness 1              [--HueSatLum layer--]
--------------------------------------------------------------------
H: 0, S: 20, L: 0
--------------------------------------------------------------------
Vibrancy adjustment Layer 1              [--Vibrancy layer--]
--------------------------------------------------------------------
Vibrancy: 35
--------------------------------------------------------------------
Brightness/Contrast 1              [--BrightnessContrast layer--]
--------------------------------------------------------------------
B: 0, C: 0
--------------------------------------------------------------------
Fill Light/Clarity 1              [--FillLightClarity layer--]
--------------------------------------------------------------------
C: 30, FL: 4
========================================================================

Re: How to document current properties

PostPosted: Mon Jun 03, 2019 2:14 am
by Corelius
Version 3.0 of my script (below) is the same as 2.0 from the user's standpoint, except that it adds a GetString dialog at the beginning where the user can input some memo text to be added at the start of the log entry. Just respond OK (leaving the box blank) if you don't want to add anything. If you click the Cancel button, the script aborts (by design).

Codewise, it's somewhat improved (I think). Version 2.0 should have had an if/elif/elif chain instead of if/if/if for the layers (duh), but 3.0 uses (maybe) a better way than if/elif, by putting each LayerType's reporting in a separate function, and calling the appropriate function by using locals()[stringX]() — with stringX partly generated by the LayerType name.

And I've enclosed the script within a try/finally pair to guard against the log file being left open if the script quits midway through because of an error.

Code: Select all
from PSPApp import *
import PSPUtils
import sys
import pprint
import datetime
import subprocess

def ScriptProperties():
    return {
        'Host': u'PaintShop Pro',
        'Host Version': u'19.00'
        }

def Do(Environment):
  try:
    if PSPUtils.RequireADoc( Environment ) == False:
        return

    IncludeNonHandledLayerTypes = True
   
    HandledLayerTypes = ['Raster', 'Levels', 'Histogram', 'Curves', 'ColorBalance', \
                        'HueSatLum', 'Vibrancy', 'BrightnessContrast', 'FillLightClarity']

    def ReportRaster():
        pass

    def ReportLevels():
        for x in ['RGB', 'Red', 'Green', 'Blue']:
            f.write(x + ': ' + str(Props['Levels'][x]) + '\n')

    def ReportHistogram():
        for x in ['LuminanceChannel', 'RedChannel', 'GreenChannel', 'BlueChannel']:
            f.write(x[:-7] + '\n')
            f.write('  Low: ' + str(Props['HistogramAdjustment'][x]['LowClipLimit']) + ', ')
            f.write('Gamma: ' + str(Props['HistogramAdjustment'][x]['Gamma']) + ', ')
            f.write('High: ' + str(Props['HistogramAdjustment'][x]['HighClipLimit']) + '\n')
            f.write('  Midtones: ' + str(Props['HistogramAdjustment'][x]['Appearance']) + '\n')

    def ReportCurves():
        for x in ['RGB', 'Red', 'Green', 'Blue']:
            f.write(x + ': ')
            f.write(str(Props['CurveParams'][x]) + '\n')

    def ReportColorBalance():
        for x in ['Shadow', 'Midtone', 'Highlight']:
            f.write(x + ': ' + str(Props['ColorBalance'][x]) + '\n')
        f.write('Preserve Luminance: ' + str(Props['ColorBalance']['PreserveLuminance']) + '\n')

    def ReportHueSatLum():
        f.write('H: ' + str(Props['HSL']['Master'][0]) + ', ')
        f.write('S: ' + str(Props['HSL']['Master'][1]) + ', ')
        f.write('L: ' + str(Props['HSL']['Master'][2]) + '\n')

    def ReportVibrancy():
        f.write('Vibrancy: ' + str(Props['Vibrancy']['Vibrancy']) + '\n')

    def ReportBrightnessContrast():
        f.write('B: ' + str(Props['BrightnessContrast']['Brightness']) + ', ')
        f.write('C: ' + str(Props['BrightnessContrast']['Contrast']) + '\n')

    def ReportFillLightClarity():
        f.write('C: ' + str(Props['FillLightClarity']['Clarity']) + ', ')
        f.write('FL: ' + str(Props['FillLightClarity']['FillLight']) + '\n')

    now = datetime.datetime.now()
    FourDigitYrMo = now.strftime("%Y")[2:] + now.strftime("%m")
    LogFile = 'C:\\D\\ProgD\\PSPX9\\Logs\\LayerData_' + FourDigitYrMo + '.log'
    MajorLine = ('=' * 72) + '\n'
    MinorLine = ('-' * 68) + '\n'

    MemoResult = App.Do( Environment, 'GetString', {
        'DefaultText': '',
        'DialogTitle': 'Memo',
        'Prompt': 'Add memo, if desired. (500 characters max.)\n"Cancel" cancels the script.',
        'MaxLength': 500,
        'GeneralSettings': {
            'ExecutionMode': App.Constants.ExecutionMode.Interactive
            }
        })
    if MemoResult['OKButton'] == False:
        sys.exit()

    f = open(LogFile, 'a')
    f.write(MajorLine)
    f.write(App.TargetDocument.Name + '\n')
    f.write('   ' + now.strftime("%Y-%m-%d, %H:%M") + '\n')
    if MemoResult['EnteredText'] != '':
        f.write(MinorLine)
        f.write(MemoResult['EnteredText'] + '\n')
    f.write(MajorLine)

    # get the path from the bottom from the active layer so we can restore it when done
    Props = App.Do( Environment, 'ReturnLayerProperties' )
    PathBack = Props['Path']

    # start by selecting the bottommost layer in the image. 
    App.Do( Environment, 'SelectLayer', { 'Path': (9999,-9999, [], False ) } )

    # now iterate up the layer stack
    FoundLayer = True
    LayerNum = 1
    while FoundLayer == True:
        # get all layer properties
        Props = App.Do( Environment, 'ReturnLayerProperties' )
        # To create my layer heading, I also separately assign the
        # names of the layer and the layer's type to variables.
        LayerName = Props['General']['Name']
        LayerTypeConstant = Props['LayerType']
        for x in App.Constants.LayerType.Values():
            if x[1] == LayerTypeConstant:
                break;
        LayerTypeName = x[0]  # Returns the name of the constant
       
        if LayerNum > 1:
            f.write(MinorLine)
        f.write(LayerName + '              [--' + LayerTypeName + ' layer--]\n')
        f.write(MinorLine)
        if Props['General']['IsVisible'] == False:
            f.write('***** NOT VISIBLE *****' + '\n')

        if LayerTypeName in HandledLayerTypes:
            locals()['Report' + LayerTypeName]()
        elif IncludeNonHandledLayerTypes == True:
            pprint.pprint(Props, width=200, stream=f)

        # go to the next layer
        FoundLayer = App.Do( Environment, 'SelectNextLayer' )
        LayerNum = LayerNum + 1

    f.write(MajorLine + '\n')
    f.close()

    # now that the loop is done, select the bottom layer and then
    # use the pathback to restore the layer that was active when we started
    App.Do( Environment, 'SelectLayer', { 'Path': (9999,-9999, [], False ) } )
    App.Do( Environment, 'SelectLayer', { 'Path': PathBack } )
   
    MsgBoxResult = App.Do(Environment, 'MsgBox', {
        'Buttons': App.Constants.MsgButtons.YesNo,
        'Icon': App.Constants.MsgIcons.Question,
        'Text': 'Open the log file?'
    })
    if MsgBoxResult == 1:
        subprocess.Popen('notepad.exe ' + LogFile)

  finally:
    try:
        if f.closed == False:
            f.close()
    except NameError:
        pass