Even though the libgimp wrapper has annotations, it is still possible to
pass a NULL font through, in Script-Fu for instance by not passing all
arguments (and very likely in a plug-in by calling the PDB procedure
directly rather). And unfortunately this would crash GIMP when it tries
to work on the NULL font.
Let's do some sanity check!
Cropping relatively to the full image contents is a common usage (it is
in fact the "Crop to Content" feature we have in the Image menu) so I
found it a bit frustrating that these 2 functions only allow to crop
relatively to a single drawable.
Therefore, I make NULL an acceptable input which will default to
cropping to the full image content instead.
- Clean up a bit the 2 procedures' descriptions and add more info in
gimp_image_autocrop() description to explain how the input drawable is
used.
- Rename gimp_image_autocrop_layer() to gimp_image_autocrop_selected_layers(),
which makes it clearer.
Rename plug_in_compat.pdb to image_autocrop.pdb so we retain commit history.
All procedures defined there are related to autocrop.
- made internal, not plugins
- renamed from plug-in- to gimp-image-
- exposed in libgimp
If we need plugin compatibility PDB group in the future,
a starting template can be recovered from plug_in_compat.pdb 2.10 or late 2.99.
Fixed plugins that call. The C plugin now calls libgimp instead of a PDB procedure.
It was not a bug per-say. Simply the filters were set as having "clip"
set by default. We should add a libgimp function to let people choose
instead, but I want to think a bit better how we handle clip and masks
in filters before creating more API. Cf. #12874.
So for now, let's just set clip to FALSE. If we have to choose a single
possible clip value for filters made by the libgimp API, I believe this
is the nicer value.
… gimp_file_create_thumbnail().
One more case where "save" is misleading, and even more as it's not a
procedure where we control where an image is stored. We only say
basically "make a thumbnail which maps to this file according to my
platform's rules".
As a side fix, I also improved a bit the logic so that it allows @file
to be the exported or — as last fallback — the imported file.
And finally improve the function's docs.
Followup of the save/export difference, plug-ins can only register
"export" handler procedure (save handlers are registered by core). Also
rename _gimp_pdb_set_file_proc_save_handler() though it's private so it
doesn't matter much.
Now gimp_file_save() is a special case, because it can indeed "save" to
XCF or "export" to any other format. So I just leave it named this way,
but I make the function's documentation more exhaustive.
Not sure what I had in mind with the class method copy() in libgimp
GimpLayer. The core duplicate code already takes care of returning an
object of the right type. Also the GimpTextLayer implementation was not
a perfect copy (only text, font and font size were copied). Now it is
because, again, core has all the duplication code necessary.
Finally this makes this function visible to PDB, hence Script-Fu, again.
The libgimp wrapper was just calling the PDB procedure. Get rid of the
wrapper and make the PDB proc public. Also reorder the name argument to
be in the second place, just like it was for the wrapper.
We had 2 flags to indicate that a PDB argument could be nullable:
null_ok and none_ok. That was a huge mixup and the PDB generation code
was using sometimes one, sometimes the other. Let's settle for only
none_ok.
This fixes a bunch of annotations.
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.