for generated brushes.
The maximum radius we allowed for generated brushes was not used
consistently everywhere.
In the API call we clamped it to 0.0-32767.0, while the param_spec
set min and max to 0.1 and 4000.0, and the brush editor used a
maximum of 1000.0.
Using a large value (probably anything larger than 4000) would
sooner or later lead to a crash.
Instead of manual changes everywhere, let's define a maximum and
minimum in one place and use that wherever we need the min/max values.
Use the values as set in the param_spec for the defines.
The only place we can't easily do that is in brush.pdb, so we add
a comment above our defines that the values need updating there too.
Actually we should probably use more defines for other values too,
that way there is less chance of min/max values getting out of synch
throughout our code.
After discussing with Idriss, we found that if you create
a GimpTextLayer via the public API, the GIMP object
was not being stored in the GimpText object.
If markup like bold/italics was then applied, GIMP
would crash on saving as XCF because the serialization
code tried to access text->gimp_font_factory.
This patch resolves the issue by passing the GIMP
object into GimpText when we create it via the
API.
Adding an is_internal value was a mistake, or rather it was redundant.
We already had a procedure type and all internal procedure are set as
GIMP_PDB_PROC_TYPE_INTERNAL.
I also double-checked that it is not possible for a plug-in to create a
procedure with this type (it is rejected), so it's very fine.
… gimp_procedure_is_internal().
I realized we were already naming these "internal procedures" in the
Procedure Browser and this is in fact a better naming than "core
procedure".
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.
libgimpbase:
- Mew GimpFileChooserAction enum type: basically a near-mapping of
GtkFileChooserAction (GTK is not accessible from libgimpbase) with
an added GIMP_FILE_CHOOSER_ACTION_ANY.
- New GimpParamSpecFile param spec type: based off
GimpParamSpecObject, it has a default value, but also a none_ok and
action argument. This way, we can also know from the argument type
if this is a file argument meant for selecting a normal file or a
folder, or for saving into a file, or for creating a directory.
libgimp, plug-ins:
- All existing file arguments (until now using a standard
GParamSpecObject param with GFile value type) were moved to the new
GimpParamSpecFile.
- Script-Fu in particular will now generate the appropriate param type
depending on whether it is an SF-FILENAME or SF-DIRNAME.
- File arguments are now stored between runs as a URI rather than as a
path. As far as I can tell, a GFile always has a URI, but not always
a path (in particular remote file won't have a path).
… 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 previous versions what has been stored/specified as perceptual blending or
compositing spaces has really been the non-linear variant of the images babl
space.
To maintain loading of old files, the code has been updated to actually mean
non-linear and a new perceptual value has been added to the GimpLayerColorSpace
enum, while preserving all old enum values.
This change bumps XCF file version to 23
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.