Core procedures are all the procedures created for libgimp basically. In
opposition, procedures created by plug-ins are not core procedures.
GimpProcedure class in libgimp now has a gimp_procedure_is_core() which
will tell you if a procedure is core or not.
Private procedures already existed, except that they were only marked as
"private" in libgimp (e.g. _gimp_font_get_lookup_name()) starting with
an underscore and marked as G_GNUC_INTERNAL. Now we also store this
information in the procedure object itself for reuse.
In particular (gimp-drawable-filter-configure),
(gimp-drawable-merge-filter) and (gimp-drawable-append-filter) are
proper Script-fu methods.
I had to rename the PDB procedures for the 2 latter because they were
clashing with these wrapper. I had not realized that private PDB
procedures are still visible by Script-fu. This is not so glop. :-/
Right now, it doesn't look so useful compared to the -new- one-liner
variant procedures. But it will make sense when I will add aux input C
procedure wrappers.
It is this way possible to set a drawable as auxiliary input to a filter
in C and GObject-Introspected bindings.
Note that such filters can only be merged, not appended
non-destructively for the time being.
It can be reimplemented with (gimp-image-rotate) and
(gimp-item-transform-rotate-simple), with even more capabilities for the
latter.
The item rotate procedure is a bit more tricky though, since it takes
into account the selection. It means that either you want to just remove
the selection before (that's what I did here, because this script was
already losing the selection anyway), or you want to store the selection
(with (gimp-channel-copy)), then reapply it (very likely with
(gimp-channel-combine-masks)) at the end, after also rotating it
appropriately the same way as the image if needed.
For plug-in writers reference, these are equivalent:
- (plug-in-noisify RUN-NONINTERACTIVE theImage mLayer TRUE r g b a)
+ (gimp-drawable-merge-new-filter mLayer "gegl:noise-rgb" 0 LAYER-MODE-REPLACE 1.0
+ "independent" TRUE "red" r "green" g "blue" b "alpha" a
+ "correlated" FALSE "seed" (msrg-rand) "linear" TRUE)
Notes:
* When "independent" is FALSE, then you only need to set "red" (which is
equivalent to a "value" field) and "alpha".
* Original plug-in was using the second value ('g', a.k.a. noise_2 in
the PDB args) as alpha when the source drawable was grayscale. This
logic is meaningless now. Just set "alpha".
* The PDB procedure was wrapping the operation between
"gegl:cast-format" nodes to cast the input buffer to linear. This is
useless as the "gegl:noise-rgb" has already a "linear" argument
(defaulting to TRUE, but I specify it explicitly in this commit, for
clarity) which requests linear input when set.
For plug-in writers reference, these are equivalent:
- (plug-in-emboss RUN-NONINTERACTIVE img mask-emboss 315.0 45.0 7 TRUE)
+ (gimp-drawable-merge-new-filter mask-emboss "gegl:emboss" 0 LAYER-MODE-REPLACE 1.0 "azimuth" 315.0 "elevation" 45.0 "depth" 7 "type" "emboss")
Note: the last arg, emboss, must be replaced by a string, "emboss" when
it was TRUE, "bumpmap" when FALSE.
Similarly to "gegl:gaussian-blur", the call to wrap_in_gamma_cast() was
useless because "gegl:emboss" already sets its output format to linear,
as well as its input format (through GeglOperationAreaFilter parent
class).
For plug-in writers reference, these are equivalent:
- (plug-in-gauss RUN-NONINTERACTIVE image layer hblur vblur 0)
+ (gimp-drawable-merge-new-filter layer "gegl:gaussian-blur" 0 LAYER-MODE-REPLACE 1.0 "std-dev-x" hblur "std-dev-y" vblur "filter" "auto")
Note: the method arg { AUTO (0), FIR (1), IIR (2) } is transformed into
a string in lowercase. E.g. 1 becomes "fir".
At first, I was a bit annoyed by the wrap_in_gamma_cast() call which
converts the buffer to linear first, but looking at "gegl:gaussian-blur"
implementation, it is just a meta op to 2 "gegl:gblur-1d" which anyway
sets input format (to various formats, but always linear).
This legacy cast code must be a remnant from older times where it might
have been needed. Clearly it's not anymore.
This time, it's a Python plug-in, which is a bit more involved than C or
Script-fu usage (where we have variable args one-liner function) though
it's not too bad either. It's actually very similar (on purpose) to how
PDB procedures are run.
For plug-in writers reference, these are equivalent:
- (plug-in-threshold-alpha RUN-NONINTERACTIVE image layer threshold))
+ (gimp-drawable-merge-new-filter layer "gimp:threshold-alpha" 0 LAYER-MODE-REPLACE 1.0 "value" (/ threshold 255))
The main difference is that threshold arg was a [0; 255] int whereas
"value" is a [0.0; 1.0] double.
This commit also shows how to run filters in C plug-ins (file-ico here)
as a one-liner too, thanks to the varargs conviency function.
For plug-in writers reference:
- (plug-in-maze RUN-NONINTERACTIVE image active-layer 5 5 TRUE 0 seed 57 1)
+ (gimp-drawable-merge-new-filter active-layer "gegl:maze" 0 LAYER-MODE-REPLACE 1.0 "x" 5 "y" 5 "tileable" TRUE "algorithm-type" "depth-first"
+ "seed" seed
+ "fg-color" (car (gimp-context-get-foreground))
+ "bg-color" (car (gimp-context-get-background)))
Notes:
* FG and BG colors were hardcoded to current context colors. It also
means with the new API, you can use whatever else you want.
* The algorithm arg changes like this:
- 0 -> "depth-first"
- 0 -> "prim"
* multiple and offset args (the 2 last args) were bogus and were doing
nothing already.
For plug-in writers reference:
- (plug-in-edge RUN-NONINTERACTIVE image layer 2 1 0)
+ (gimp-drawable-merge-new-filter layer "gegl:edge" 0 LAYER-MODE-REPLACE opacity "amount" 2.0 "border-behavior" "loop" "algorithm" "sobel")
The warpmode (before-last) arg has to be replaced like this (types from
GeglAbyssPolicy enum type):
* NONE (0) -> "none"
* WRAP (1) -> "loop"
* SMEAR (2) -> "clamp"
* BLACK (3) -> "black"
For edgemode (last arg), just use the name value in lowercase as string:
{ SOBEL (0), PREWITT (1), GRADIENT (2), ROBERTS (3), DIFFERENTIAL (4), LAPLACE (5) }
E.g. "differencial" instead of formerly 4.
For plug-in developers reference:
- (plug-in-cubism RUN-NONINTERACTIVE image layer tile_size saturation 0)
+ (gimp-drawable-merge-new-filter layer "gegl:cubism" 0 LAYER-MODE-REPLACE 1.0 "tile-size" tile_size "tile-saturation" saturation "bg-color" '(0 0 0))
Now you can even choose the bg-color (not just an int/enum of black and
background color only).
For plug-in writers, here is how to replace it:
- (plug-in-c-astretch RUN-NONINTERACTIVE img drawable)
+ (gimp-drawable-merge-new-filter drawable "gegl:stretch-contrast" 0 LAYER-MODE-REPLACE 1.0 "keep-colors" FALSE)
When calling gimp_drawable_filter_get_config() the first time, we don't
want the config's properties to be at default values, but instead to be
set same as they are on core app.
On further calls though, we don't touch the values, because they may be
out-of-sync until the next call to gimp_drawable_filter_update().
… gimp_drawable_filter_update() first.
Otherwise this is bug-prone. When people were to update the
configuration of the filter, they obviously intend this to be used when
appending/merging.
Similarly to the config arguments, the set functions are not directly
calling core. Instead they are queuing changes until
gimp_drawable_filter_update() is run.
It is now possible to sync the GimpDrawableFilterConfig with core.
Another (simpler on usage) possibility could have been to sync
automatically when a property is updated. But considering that some
filters can be quite slow to render (especially in real-life usage when
working on possibly very big files), and especially that on bindings
with no variable args, scripts will likely have to edit properties one
by one, it could make editing multiple properties very slow. Therefore
the chosen solution is that editing properties stay local on libgimp and
all changed properties are synced with core at once (with a frozen
render until the end for single computation) when calling
gimp_drawable_filter_update().
This is mostly an empty shell whose goal is to serve as base class for
specific dynamically generated per-operation subclasses, which will have
properties mimicking the arguments of the GEGL operation.
Most of the fundamental type args will just use the base GLib param spec
types instead of GEGL ones.
As a special case, the GeglParamEnum arguments are transformed into
GimpChoice param specs on libgimp side. The reason is that most of the
time, enum types are created within the scope of an operation code only
and cannot be properly reconstructed over the wire. I could just
transform these into an int type (which is mostly what is done in GEGL
right now when running an op with such arg), but GimpChoice allow much
nicer string-type args, which make much more semantic code. This class
was initially created for plug-ins, but it would work very well to run
GEGL ops on drawables. So let's do it.
Finally add a gimp_drawable_filter_get_config() to request the current
config of a filter.
Note that right now, we can't do much with this config object other than
observing an operation args and default values. Being able to update a
filter's settings will come up in further commits.
A few functions were added, but the main one is
gimp_drawable_get_filters() to request the list of filters applied
non-destructively on a drawable. We can't do much with these for the
time being, but this will come.
WIP.
in gimp:offset filter.
Since gimp:offset is now an NDE filter,
always loading the background color from
context causes the color to change each
time the filter is redrawn. This is inconsistent
behavior.
This patch replaces the GimpContext
parameter with GeglColor, and updates
gimp_drawable_offset and related functions
to set the color directly. The libgimp version
loads the background color from context
and passes it on since the API is now
frozen.
In gimp_file_save (), we clear out the values
of any String parameters to prevent unexpected
results. However, GimpChoice is also a
String type. This causes the function to
fail because empty string is not a valid
option for GimpChoice.
This patch adds a prior check if the argument
is a GimpChoice, and sets it to its default
value instead to prevent this issue.
… legacy to gegl parameters.
This commit removed 57 legacy PDB procedures which were replacing
outdated plug-ins (before transformed into GEGL ops) as far as I
understand.
These were all kept only as a legacy compatibility layer for third-party
scripts. Since we are breaking API anyway, let's remove as many as we
can. I've only kept the few which are still used at least once in our
core scripts or plug-ins.
Now as pippin notes, we still have no easy way to quickly run GEGL ops
on drawables in script-fu. Though we have at least access to GEGL API
for C plug-ins and all GObject-Introspected bindings. But that's true
for all other ops anyway.
I guess what should happen (quickly-ish) after 3.0 release is a libgimp
utility function which does the heavy lifting of creating a GEGL graph
for us, and for script-fu probably a special-case binding or something.
I realized it is redundant with gimp_fonts_get_list() which is a bit
more complicated to use but also more powerful. Let's see if we ever
need the simpler utility function in the future.
- s/gimp_buffers_get_list/gimp_buffers_get_name_list/
- s/gimp_context_get_dynamics/gimp_context_get_dynamics_name/
- s/gimp_context_set_dynamics/gimp_context_set_dynamics_name/
- s/gimp_dynamics_get_list/gimp_dynamics_get_name_list/
Named buffers and dynamics don't have their own classes. Using
*_get_name_list() will make sure that *_get_list() is available so that
we have constant naming if we add the new types, even during the 3.0
series. Same for the gimp_context_*() functions.
Note that the buffer API in particular has a few more functions which
we'd like to be able to reuse (e.g. gimp_buffer_rename()) with a proper
type. But we'll probably name this type GimpNamedBuffer anyway
(GimpBuffer is too similarly-named with GeglBuffer IMO) so it will be
easy to create new API for the new type.
See also #12268.
There are 2 *_get_list() for buffers and dynamics but since we don't
have clases for these, they still just return a list of names for now.
I opened #12268 for further thinking on these.
Several types functions were using the wording "float" historically to
mean double-precision, e.g. the float array type (which was in fact a
double array). Or the scanner function gimp_scanner_parse_float() was in
fact returning a double value. What if we wanted someday to actually add
float (usually this naming means in C the single-precision IEEE 754
floating point representation) support? How would we name this?
Now technically it's not entirely wrong (a double is still a floating
point). So I've been wondering if that is because maybe we never planned
to have float and double precision may be good enough for all usage in a
plug-in API (which doesn't have to be as generic so the higher precision
is enough)? But how can we be sure? Also we already had some functions
using the wording double (e.g. gimp_procedure_add_double_argument()), so
let's just go the safe route and use the accurate wording.
The additional change in PDB is internal, but there too, I was also
finding very confusing that we were naming double-precision float as
'float' type. So I took the opportunity to update this. It doesn't
change any signature.
In fact the whole commit doesn't change any type or code logic, only
naming, except for one bug fix in the middle which I encountered while
renaming: in gimp_scanner_parse_deprecated_color(), I discovered a
hidden bug in scanning (color-hsv*) values, which was mistakenly using a
double type for an array of float.
Avoid the stack smashing bug from yesterday in other functions.
Additionally to fixing other functions, do not cast the pointer to size
in the PDB generation scripts so that we can quickly spot such bugs in
the future, through compilation time warnings, instead of hiding them.
Currently there are 5 separate plug-in-gauss
functions. IIR2 and RLE2 are not used, and
IIR and RLE are identical to each other.
Additionally, they all call a separate
gaussian_blur () function which multiples
two parameters by 0.32 to convert to the
actual GEGL operation.
This patch removes all functions except
for plug-in-gauss. It converts each
existing script that used one of the other
variants to use plug-in-gauss, and
multiples the coefficients by 0.32 so that
plug-in-gauss behaves the same as calling
gegl:gaussian-blur with a C plug-in.
There also exists a plug_in_pixelize2 ()
function in the PDB which allows the user to set
both the pixel width and height.
This patch converts this to become
plug_in_pixelize (), and removes the older
function which used a single width
parameter for both values.
Generated libgimp functions' arguments are normally tested through the
PDB, so that you get proper error messages when trying to call a
function with invalid arguments.
This is not true anymore for array arguments since the size argument is
not a PDB arg, only in the C function. Therefore I'm adding an
infrastructure asserting on invalid size, using the same PDB type
annotations as other args. It is important to assert valid input on
plug-in side (i.e. libgimp) so that the core doesn't make any assumption
on having received valid input when it has not.
Also changing size argument of gimppainttools PDB-generated functions to
proper gsize.