Accessing last applied Auto Levels from a script - BigMackCam - 04-08-2024
Hi all
I'm new to writing GIMP scripts, and relatively new to python, but slowly I'm beginning to make progress with python-fu and simple script development.
I have a process I'm currently performing manually on a regular basis, and I'd like to create a script to automate it. The manual process is as follows:
1. Select an area of the image
2. Perform Auto Levels (Colors -> Levels -> Auto Input Levels)
3. Undo Levels
4. Select all of the image
5. Re-apply the previous levels (Filters -> Repeat Levels)
In scripting the above, I've got as far as step 4 successfully - but for step 5 I'm stuck, as I can't find any procedure in the pdb that lets me re-apply the previous levels. After a bit of searching online, I found that GIMP writes these values to a GimpLevelsConfig.settings file in the AppData\Roaming\GIMP\2.10\Filters directory (on my installation, at least) - and if I look in this file, I can indeed see the levels last applied... but I can't find any procedure that will let me retrieve the values.
So... my questions to the esteemed and knowledgeable python scripters here are:
1. Is there a way to call the Filters -> Repeat Levels function via an existing internal GIMP procedure?
2. If "no" to the above, is there a way to access the levels values last applied without resorting to the "GimpLevelsConfig.settings" file?
3. If "no" to the above, is there a way of reading the file via one or more existing internal GIMP procedures?
4. If "no" to the above, (a) how do I obtain the directory for the file (in case it's configured differently across versions and platforms), and (b) can anyone help me with guidance on reading and parsing the file to a set of variables?
Any assistance for this rank novice would be greatly appreciated. Thanks in advance!
Mike
PS. Sorry, I forgot to mention, I'm running GIMP 2.10 on Windows, Ubuntu and Fedora environments...
RE: Accessing last applied Auto Levels from a script - Ofnuts - 04-09-2024
- For Python, there is an optional run_mode named parameter that supports values'RUN_INTERACTIVE, RUN_NONINTERACTIVE, RUN_WITH_LAST_VALS , but AFAIK this works mostly with the file export dialogs.
- None I know of
- None I know of
- a) You can use the gimp.directory to obtain the Gimp use profiles, and for there its is os.path.join(gimp.directory,'filters','GimpLevelsConfig.settings') to access the file. b) The latest setting is at the top (so you don't need to search for it) and the rest. Will provide some sample code later today.
RE: Accessing last applied Auto Levels from a script - BigMackCam - 04-09-2024
Hi @Ofnuts and thanks so much for the helpful reply...
I checked the pdb.gimp_drawable_levels procedure and it doesn't seem to support the run_mode parameter, unless I'm missing something:
pdb.gimp_drawable_levels(drawable, channel, low_input, high_input, clamp_input, gamma, low_output, high_output, clamp_output)
Thanks for the information on how to obtain the correct directory path, and forthcoming sample code. Very much appreciated!
RE: Accessing last applied Auto Levels from a script - Ofnuts - 04-09-2024
(04-09-2024, 09:40 AM)BigMackCam Wrote: Hi @Ofnuts and thanks so much for the helpful reply...
I checked the pdb.gimp_drawable_levels procedure and it doesn't seem to support the run_mode parameter, unless I'm missing something:
pdb.gimp_drawable_levels(drawable, channel, low_input, high_input, clamp_input, gamma, low_output, high_output, clamp_output)
Thanks for the information on how to obtain the correct directory path, and forthcoming sample code. Very much appreciated!
Sample code
Code:
#! /bin/env python
import sys,re
from collections import namedtuple
stringValuePattern=r'\(([a-z-]+) ([^)]+)\)'
intValuePattern=r'\(([a-z-]+) (\d+)\)'
floatValuePattern=r'\(([a-z-]+) (\d+(\.\d+)?)\)'
booleanValuePattern=r'\(([a-z-]+) (yes|no)\)'
ChannelSettings=namedtuple('ChannelSettings',['name','loInput','hiInput','gamma','loOutput','hiOutput'])
LevelsSettings=namedtuple('LevelsSettings',['time','linear','clampInput','clampOutput','value','red','green','blue','alpha'])
def expected(pattern,name,line):
matched=re.search(pattern,line)
if not matched:
raise Exception('Pattern not matched for line %s',line)
if matched.group(1)!=name:
raise Exception('Unexpected name %s (expected: %s)' % (matched.group(1),name))
return matched.group(2)
def expectedChannel(channelName,line):
value=expected(stringValuePattern,'channel',line)
if value!=channelName:
raise Exception('Unexpected channel %s (expected: %s)' % (value,channelName))
def expectedInt(name,line):
value=expected(intValuePattern,name,line)
return int(value)
def expectedFloat(name,line):
value=expected(floatValuePattern,name,line)
return float(value)
def expectedBoolean(name,line):
value=expected(booleanValuePattern,name,line)
return value=='yes'
def readChannel(channelName,levelsConf):
expectedChannel(channelName,next(levelsConf))
return ChannelSettings(
channelName,
expectedFloat('low-input',next(levelsConf)),
expectedFloat('high-input',next(levelsConf)),
expectedFloat('gamma',next(levelsConf)),
expectedFloat('low-output',next(levelsConf)),
expectedFloat('high-output',next(levelsConf)),
)
def readLevels(file):
with open(file) as levelsConf:
next(levelsConf) # skip top comment
next(levelsConf) # skip blank line
next(levelsConf) # settings header
return LevelsSettings(
expectedInt('time',next(levelsConf)),
expectedBoolean('linear',next(levelsConf)),
expectedBoolean('clamp-input',next(levelsConf)),
expectedBoolean('clamp-output',next(levelsConf)),
readChannel('value',levelsConf),
readChannel('red',levelsConf),
readChannel('green',levelsConf),
readChannel('blue',levelsConf),
readChannel('alpha',levelsConf),
)
settings=readLevels(sys.argv[1])
print settings
From a file that beings with:
Code:
# settings
(GimpLevelsConfig "2024-04-09 10:32:38"
(time 1712651558)
(linear no)
(clamp-input no)
(clamp-output no)
(channel value)
(low-input 0)
(high-input 1)
(gamma 1)
(low-output 0.05849056603773585)
(high-output 1)
(channel red)
(low-input 0)
(high-input 1)
(gamma 1)
(low-output 0)
(high-output 1)
(channel green)
(low-input 0)
(high-input 1)
(gamma 1)
(low-output 0)
(high-output 1)
(channel blue)
(low-input 0)
(high-input 1)
(gamma 1)
(low-output 0)
(high-output 1)
(channel alpha)
(low-input 0)
(high-input 1)
(gamma 1)
(low-output 0)
(high-output 1))
(GimpLevelsConfig "2024-04-09 10:30:18"
(time 1712651418)
(linear no)
(clamp-input no)
(clamp-output no)
(channel value)
(low-input 0)
(high-input 1)
(gamma 1)
(low-output 0)
######## etc....
Yields:
Code:
LevelsSettings(time=1712651558, linear=False, clampInput=False, clampOutput=False,
value=ChannelSettings(name='value', loInput=0.0, hiInput=1.0, gamma=1.0, loOutput=0.05849056603773585, hiOutput=1.0),
red=ChannelSettings(name='red', loInput=0.0, hiInput=1.0, gamma=1.0, loOutput=0.0, hiOutput=1.0),
green=ChannelSettings(name='green', loInput=0.0, hiInput=1.0, gamma=1.0, loOutput=0.0, hiOutput=1.0),
blue=ChannelSettings(name='blue', loInput=0.0, hiInput=1.0, gamma=1.0, loOutput=0.0, hiOutput=1.0),
alpha=ChannelSettings(name='alpha', loInput=0.0, hiInput=1.0, gamma=1.0, loOutput=0.0, hiOutput=1.0))
Moderately tested. Enjoy.
RE: Accessing last applied Auto Levels from a script - BigMackCam - 04-09-2024
(04-09-2024, 12:55 PM)Ofnuts Wrote: Moderately tested. Enjoy.
Wow... This is great! At my current novice level with Python, I can understand what the code does, but I wouldn't have come up with such an elegant solution at this stage. I can't thank you enough for your help and the time you've spent on this. Hopefully I can pay it forward when my completed and tested scripts are ready for release, as I suspect a few folks may find them as useful as I will...
Many thanks & all the best.
Mike
|