mirror of https://github.com/GNOME/gimp.git
devel-docs: delete various devel docs which are now in developer.gimp.org.
This commit is contained in:
parent
6c0c2f15c4
commit
62963aa748
|
@ -1,963 +0,0 @@
|
||||||
# GIMP Coding Style
|
|
||||||
|
|
||||||
This document describes the preferred coding style for the GIMP source code.
|
|
||||||
It was originally inspired by [GNU's coding
|
|
||||||
style](https://www.gnu.org/prep/standards/standards.html#Writing-C) and
|
|
||||||
developed from there across the years.
|
|
||||||
|
|
||||||
Coding style is completely arbitrary as it is a a matter of consistency,
|
|
||||||
readability and maintenance, not taste. Therefore it doesn't matter what
|
|
||||||
you prefer (we all have some part of the rules we would like different,
|
|
||||||
and we can apply these to our personal projects), just follow these
|
|
||||||
rules so that we can work together efficiently.
|
|
||||||
|
|
||||||
This document will use examples at the very least to provide
|
|
||||||
authoritative and consistent answers to common questions regarding the
|
|
||||||
coding style and will also try to identify the allowed exceptions.
|
|
||||||
|
|
||||||
## Table of contents
|
|
||||||
|
|
||||||
[TOC]
|
|
||||||
|
|
||||||
## Dealing with the old code
|
|
||||||
|
|
||||||
__The new GIMP code should adhere to the style explained below.__ The existing
|
|
||||||
GIMP code largely follows these conventions, but there are some differences like
|
|
||||||
extra or missing whitespace, tabs instead of space, wrong formatting, etc.
|
|
||||||
|
|
||||||
__Our policy is to update the style of a code block or function if and only if
|
|
||||||
you happen to touch that code.__
|
|
||||||
|
|
||||||
Please don't waste your time and reviewers' time with merge requests or patches
|
|
||||||
with _only_ code style fixes unless you have push rights to the GIMP's
|
|
||||||
repository.
|
|
||||||
|
|
||||||
## Git usage
|
|
||||||
### Commit messages
|
|
||||||
|
|
||||||
Commit messages should follow the following rules:
|
|
||||||
|
|
||||||
- Always provide informative titles. No one-word commits saying nothing
|
|
||||||
like "bug fix", so that we can at least search through the git history
|
|
||||||
if needed. It can still be short messages for very simple fixes: for
|
|
||||||
instance "Fix typo" or "Fix small memory leak" are informative of the
|
|
||||||
type of fix.
|
|
||||||
- Prefix the title with the codebase section (i.e. the root folder
|
|
||||||
usually) which was changed. For instance: `libgimpbase: fix memory
|
|
||||||
leak` immediately tells us it was a memory leak fix in the
|
|
||||||
`libgimpbase` library. If several sections are touched, list them with
|
|
||||||
comma-separation.
|
|
||||||
- Alternatively, when the change is a response to a bug report, you may
|
|
||||||
prefix with `Issue #123:` (where `#123` is the report ID) instead.
|
|
||||||
- If the changed code itself is not self-explanatory enough, you can add
|
|
||||||
longer change description (2 lines after the title) to explain more.
|
|
||||||
It is not mandatory, but it is never unwelcome because old code
|
|
||||||
exploration to understand why things were done (possibly years before
|
|
||||||
by people long gone) is a real thing we do all the time. So if it's
|
|
||||||
not obvious, explain us.
|
|
||||||
- Explanations can also be made in the shape of links to a bug report
|
|
||||||
(ours, or a third-party project tracker, or some manual), even though
|
|
||||||
additional text explanations may still be useful (unfortunately URLs
|
|
||||||
may change or disappear). If the link is to our own bug tracker,
|
|
||||||
usually giving the ID is enough.
|
|
||||||
- Same [as for code](#line-width), wrap your commit message to
|
|
||||||
reasonable line widths, such as 72 or 80 maximum so that other
|
|
||||||
contributors don't have to scroll horizontally on narrow
|
|
||||||
vizualisation. There may be exceptions, for instance when pasting some
|
|
||||||
error messages which may end up confusing when wrapped. But other than
|
|
||||||
this, wrap your text (most `git` client would have a feature to do it
|
|
||||||
for you).
|
|
||||||
- If the title is too long because of the max-width settings, a common
|
|
||||||
format is to break it with '…' and to continue the title 2 lines below.
|
|
||||||
Then the description goes again 2 lines below.
|
|
||||||
|
|
||||||
Here is an example of a well formatted fix in the `plug-ins/` section:
|
|
||||||
|
|
||||||
```
|
|
||||||
plug-ins: fix file-gih.
|
|
||||||
|
|
||||||
We currently cannot call gimp_pdb_run_procedure() for procedures
|
|
||||||
containing arrays because this C-type doesn't contain the size
|
|
||||||
information (which is in a second parameter but since the rule is not
|
|
||||||
hard-coded, our API can't know this).
|
|
||||||
|
|
||||||
See issue #7369.
|
|
||||||
```
|
|
||||||
|
|
||||||
Here is another as a response to a bug report and a long title:
|
|
||||||
|
|
||||||
```
|
|
||||||
Issue #6695: Wrong tab after JPG export because of "Show preview"…
|
|
||||||
|
|
||||||
… feature.
|
|
||||||
|
|
||||||
Using the new gimp_display_present() function in file-jpeg to make sure
|
|
||||||
the original display is back to the top.
|
|
||||||
```
|
|
||||||
|
|
||||||
If you want to see more good examples, this `git` command will list
|
|
||||||
commits whose messages are generally well formatted:
|
|
||||||
`git log --author="Jehan\|mitch\|Jacob Boerema"`
|
|
||||||
|
|
||||||
### Linear git log
|
|
||||||
|
|
||||||
Nearly all our repositories (`gimp-web` being the exception) have a
|
|
||||||
fully linear history. The "merge commit" workflow is definitely good and
|
|
||||||
useful in some projects' workflow, especially with bigger projects with
|
|
||||||
many contributors and subdivided maintenance roles (where the main tree
|
|
||||||
is mostly about merging public trees of several submaintainers' public
|
|
||||||
trees, who themselves applied contributed commits by individuals).
|
|
||||||
|
|
||||||
This doesn't work well with GIMP's current workflow and our number of
|
|
||||||
contributors. This is even worse with the completely useless merge
|
|
||||||
commits created by hosting tools which completely misused (or even
|
|
||||||
misunderstood) the merge concept.
|
|
||||||
|
|
||||||
This is why our Gitlab projects are configured to only push commits
|
|
||||||
linearly. This means that when a contributed tree is behind, you must
|
|
||||||
first rebase it through the "Rebase" button in the merge request (which
|
|
||||||
requires contributors to check the "*Allow commits from members who can
|
|
||||||
merge to the target branch*" option) or by rebasing in the tree then
|
|
||||||
force-pushing when Gitlab is unable to merge.
|
|
||||||
|
|
||||||
When you push directly (for contributors with push rights), you are also
|
|
||||||
expected to never push a merge commit.
|
|
||||||
|
|
||||||
### Multiple or single commits?
|
|
||||||
|
|
||||||
When contributing merge requests or patch files, you should break your
|
|
||||||
work into logical changes, not into review timelines.
|
|
||||||
|
|
||||||
E.g. after a review, instead of pushing fixes as an additional commit,
|
|
||||||
amend your commits to rewrite your local git history as though reviewed
|
|
||||||
bugs never existed.
|
|
||||||
|
|
||||||
On the other hand, we appreciate separate commits when they are logical
|
|
||||||
units. For instance, you could have 1 commit adding a GUI feature, then
|
|
||||||
1 commit adding a `libgimp` API to manipulate the new feature and 1
|
|
||||||
commit for a plug-in to use this new API. It makes perfect sense to
|
|
||||||
separate these 3 changes into their own commits and even help for review
|
|
||||||
and later dig through development logs.
|
|
||||||
|
|
||||||
## C code
|
|
||||||
### Line width
|
|
||||||
|
|
||||||
The recommended line width for source files is _80 characters_ whenever possible.
|
|
||||||
Longer lines are usually an indication that you either need a function or a
|
|
||||||
pre-processor macro.
|
|
||||||
|
|
||||||
The point is to have clear code to read and not overly long lines. Don't break
|
|
||||||
code into ugly and choppy parts to blindly follow this rule.
|
|
||||||
|
|
||||||
Function definitions in the function forward declaration block don't have to
|
|
||||||
obey the 80 characters limit. The only general rule for headers is to align the
|
|
||||||
function definitions vertically in three columns.
|
|
||||||
See more information in [Headers sections](#Headers)
|
|
||||||
|
|
||||||
### Whitespaces
|
|
||||||
#### Indentation
|
|
||||||
|
|
||||||
Each new level is indented 2 or more spaces than the previous level:
|
|
||||||
|
|
||||||
```c
|
|
||||||
if (condition)
|
|
||||||
single_statement ();
|
|
||||||
```
|
|
||||||
|
|
||||||
Use only __space characters__ to achieve this. Code indented with tabs will not
|
|
||||||
be accepted into the GIMP codebase.
|
|
||||||
|
|
||||||
Even if two spaces for each indentation level allow deeper nesting, GIMP favors
|
|
||||||
self-documenting function names that can be quite long. For this reason, you
|
|
||||||
should avoid deeply nested code.
|
|
||||||
|
|
||||||
*Note*: the only place where we use Tab indentation and alignment is the
|
|
||||||
Makefiles. In there, Tab are expected to be displayed as 8 characters
|
|
||||||
for proper display
|
|
||||||
|
|
||||||
#### Vertical spaces (new lines)
|
|
||||||
|
|
||||||
Except for one single newline at the end of the file, other empty lines (at the
|
|
||||||
beginning and the end) of a file are not allowed.
|
|
||||||
|
|
||||||
On the other hand, empty lines in the middle of code are very encouraged
|
|
||||||
for well-ventilated code. For instance gathering and separating code by
|
|
||||||
logical parts making it easy to read and understand.
|
|
||||||
|
|
||||||
#### Horizontal spaces
|
|
||||||
|
|
||||||
Always put a space before an opening parenthesis but never after:
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* valid */
|
|
||||||
if (condition)
|
|
||||||
do_my_things ();
|
|
||||||
|
|
||||||
/* valid */
|
|
||||||
switch (condition)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/* invalid */
|
|
||||||
if(condition)
|
|
||||||
do_my_things();
|
|
||||||
|
|
||||||
/* invalid */
|
|
||||||
if ( condition )
|
|
||||||
do_my_things ( );
|
|
||||||
```
|
|
||||||
|
|
||||||
Do not eliminate whitespace and newlines just because something would
|
|
||||||
fit on 80 characters:
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* invalid */
|
|
||||||
if (condition) foo (); else bar ();
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Tab characters in strings
|
|
||||||
|
|
||||||
Use `\t` instead of literal tab inside the source code strings.
|
|
||||||
|
|
||||||
### Braces
|
|
||||||
|
|
||||||
#### If-else
|
|
||||||
|
|
||||||
Don't use curly braces for single statement blocks:
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* valid */
|
|
||||||
if (condition)
|
|
||||||
single_statement ();
|
|
||||||
else
|
|
||||||
another_single_statement (arg1);
|
|
||||||
```
|
|
||||||
|
|
||||||
In the case of multiple statements, put curly braces on another indentation level:
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* valid */
|
|
||||||
if (condition)
|
|
||||||
{
|
|
||||||
statement_1 ();
|
|
||||||
statement_2 ();
|
|
||||||
statement_3 ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* invalid */
|
|
||||||
if (condition) {
|
|
||||||
statement_1 ();
|
|
||||||
statement_2 ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* invalid */
|
|
||||||
if (condition)
|
|
||||||
{
|
|
||||||
statement_1 ();
|
|
||||||
statement_2 ();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The "no block for single statements" rule has only three exceptions:
|
|
||||||
|
|
||||||
① _Both sides of the if-else statement_ must have curly braces when
|
|
||||||
either side of this if-else statement has braces or when
|
|
||||||
the single statement covers multiple lines, and it's followed
|
|
||||||
by else or else if (e.g., for functions with many arguments).
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* valid */
|
|
||||||
if (condition)
|
|
||||||
{
|
|
||||||
a_single_statement_with_many_arguments (some_lengthy_argument,
|
|
||||||
another_lengthy_argument,
|
|
||||||
and_another_one,
|
|
||||||
plus_one);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
another_single_statement (arg1, arg2);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
② if the condition is composed of many lines:
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* valid */
|
|
||||||
if (condition1 ||
|
|
||||||
(condition2 && condition3) ||
|
|
||||||
condition4 ||
|
|
||||||
(condition5 && (condition6 || condition7)))
|
|
||||||
{
|
|
||||||
a_single_statement ();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
③ In the case of nested if's, the block should be placed on the outermost if:
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* valid */
|
|
||||||
if (condition)
|
|
||||||
{
|
|
||||||
if (another_condition)
|
|
||||||
single_statement ();
|
|
||||||
else
|
|
||||||
another_single_statement ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* invalid */
|
|
||||||
if (condition)
|
|
||||||
if (another_condition)
|
|
||||||
single_statement ();
|
|
||||||
else if (yet_another_condition)
|
|
||||||
another_single_statement ();
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Switch
|
|
||||||
|
|
||||||
A `switch()` should open a block on a new indentation level, and each case
|
|
||||||
should start on the same indentation level as the curly braces, with the
|
|
||||||
case block on a new indentation level:
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* valid */
|
|
||||||
switch (condition)
|
|
||||||
{
|
|
||||||
case FOO:
|
|
||||||
do_foo ();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BAR:
|
|
||||||
do_bar ();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* invalid */
|
|
||||||
switch (condition) {
|
|
||||||
case FOO: do_foo (); break;
|
|
||||||
case BAR: do_bar (); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* invalid */
|
|
||||||
switch (condition)
|
|
||||||
{
|
|
||||||
case FOO: do_foo ();
|
|
||||||
break;
|
|
||||||
case BAR: do_bar ();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* invalid */
|
|
||||||
switch (condition)
|
|
||||||
{
|
|
||||||
case FOO:
|
|
||||||
do_foo ();
|
|
||||||
break;
|
|
||||||
case BAR:
|
|
||||||
do_bar ();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
It is preferable, though not mandatory, to separate the various cases with
|
|
||||||
a newline:
|
|
||||||
|
|
||||||
```c
|
|
||||||
switch (condition)
|
|
||||||
{
|
|
||||||
case FOO:
|
|
||||||
do_foo ();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BAR:
|
|
||||||
do_bar ();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
do_default ();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If a case block needs to declare new variables, the same rules as the inner
|
|
||||||
blocks (see above) apply; place the break statement outside of the inner block:
|
|
||||||
|
|
||||||
```c
|
|
||||||
switch (condition)
|
|
||||||
{
|
|
||||||
case FOO:
|
|
||||||
{
|
|
||||||
int foo;
|
|
||||||
|
|
||||||
foo = do_foo ();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Do not add `default:` case if your `switch ()` is supposed to handle _all cases_.
|
|
||||||
|
|
||||||
#### Random blocks
|
|
||||||
|
|
||||||
Using blocks to group code is discouraged and must not be used in newly
|
|
||||||
written code.
|
|
||||||
|
|
||||||
```c
|
|
||||||
int retval = 0;
|
|
||||||
gbool condition = retval >= 0;
|
|
||||||
|
|
||||||
statement_1 ();
|
|
||||||
statement_2 ();
|
|
||||||
|
|
||||||
/* discouraged in newly written code */
|
|
||||||
{
|
|
||||||
int var1 = 42;
|
|
||||||
gboolean res = FALSE;
|
|
||||||
|
|
||||||
res = statement_3 (var1);
|
|
||||||
retval = res ? -1 : 1;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Conditions
|
|
||||||
|
|
||||||
Do not check boolean values for equality:
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* valid */
|
|
||||||
if (another_condition)
|
|
||||||
do_bar ();
|
|
||||||
|
|
||||||
/* invalid */
|
|
||||||
if (condition == TRUE)
|
|
||||||
do_foo ();
|
|
||||||
```
|
|
||||||
|
|
||||||
Even if C handles NULL equality like a boolean, be explicit:
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* valid */
|
|
||||||
if (some_pointer == NULL)
|
|
||||||
do_blah ();
|
|
||||||
|
|
||||||
/* invalid */
|
|
||||||
if (some_other_pointer)
|
|
||||||
do_blurp ();
|
|
||||||
```
|
|
||||||
|
|
||||||
When conditions split over multiple lines, the logical operators should always
|
|
||||||
go at the end of the line. Align the same level boolean operators to show
|
|
||||||
explicitly which are on the same level and which are not:
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* valid */
|
|
||||||
if (condition1 &&
|
|
||||||
condition2 &&
|
|
||||||
(condition3 || (condition4 && condition5)))
|
|
||||||
{
|
|
||||||
do_blah ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* invalid */
|
|
||||||
if (condition1
|
|
||||||
|| condition2
|
|
||||||
|| condition3)
|
|
||||||
{
|
|
||||||
do_foo ();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Variables declaration and definition
|
|
||||||
|
|
||||||
Place each variable on a new line. The variable name must be right-aligned,
|
|
||||||
taking into account pointers:
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* valid */
|
|
||||||
int first = 42;
|
|
||||||
gboolean second = TRUE;
|
|
||||||
GimpObject *third = NULL;
|
|
||||||
```
|
|
||||||
|
|
||||||
Blocks of variable declaration/initialization should align the variable names,
|
|
||||||
allowing quick skimming of the variable list.
|
|
||||||
|
|
||||||
### Functions
|
|
||||||
|
|
||||||
Function header has the return type on one line; the name starting in the first
|
|
||||||
column of the following line. Prototype each parameter and place each on a
|
|
||||||
new line.
|
|
||||||
|
|
||||||
In function names, each word must be lowercase and separated by an underscore.
|
|
||||||
|
|
||||||
In the function definition, place the return value on a separate line from the
|
|
||||||
function name:
|
|
||||||
|
|
||||||
```c
|
|
||||||
void
|
|
||||||
my_function (void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The parameters list must be broken into a new line for each parameter, with the
|
|
||||||
parameter names right-aligned, taking into account pointers:
|
|
||||||
|
|
||||||
```c
|
|
||||||
void
|
|
||||||
my_function (some_type_t some_param,
|
|
||||||
another_type_t *a_pointer_param,
|
|
||||||
final_type_t final_param)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
While curly braces for function definitions should rest on a new line they
|
|
||||||
should not add an indentation level:
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* valid */
|
|
||||||
static void
|
|
||||||
my_function (int parameter)
|
|
||||||
{
|
|
||||||
do_my_things ();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The alignment also holds when invoking a function:
|
|
||||||
|
|
||||||
```c
|
|
||||||
align_function_arguments (first_argument,
|
|
||||||
second_argument,
|
|
||||||
third_argument);
|
|
||||||
```
|
|
||||||
|
|
||||||
If your function name is very long, it's always better to extract arguments into
|
|
||||||
separate variables to improve readability:
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* valid */
|
|
||||||
first_a = argument_the_first;
|
|
||||||
second_a = argument_the_second;
|
|
||||||
a_very_long_function_name_with_long_arguments (first_a, second_a);
|
|
||||||
```
|
|
||||||
|
|
||||||
Keep the function name and the arguments on the same line. Otherwise, it will
|
|
||||||
hurt readability.
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* invalid */
|
|
||||||
a_very_long_function_name_with_long_arguments
|
|
||||||
(argument_the_first, argument_the_second);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Macros
|
|
||||||
|
|
||||||
Try to avoid private macros unless strictly necessary. Remember to `#undef`
|
|
||||||
them at the end of a block or a series of functions needing them.
|
|
||||||
|
|
||||||
Use inline functions instead of private macro definitions.
|
|
||||||
Do not use public macros unless they evaluate to a constant.
|
|
||||||
|
|
||||||
### Includes
|
|
||||||
|
|
||||||
GIMP source files should never include the global `gimp.h` header, but instead
|
|
||||||
include the individual headers that are needed.
|
|
||||||
|
|
||||||
Includes must be in the following order:
|
|
||||||
|
|
||||||
0. `config.h` first;
|
|
||||||
0. System and third-party headers;
|
|
||||||
0. GIMP library headers (`libgimp*` headers);
|
|
||||||
0. GIMP core/app headers that it needs including its own;
|
|
||||||
|
|
||||||
Sort alphabetically the includes within the blocks.
|
|
||||||
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* valid */
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <gegl.h>
|
|
||||||
#include <gtk/gtk.h>
|
|
||||||
|
|
||||||
#include "libgimpbase/gimpbase.h"
|
|
||||||
#include "libgimpcolor/gimpcolor.h"
|
|
||||||
|
|
||||||
#include "core/gimp.h"
|
|
||||||
#include "core/gimpcontainer.h"
|
|
||||||
|
|
||||||
#include "gimpcolorpanel.h"
|
|
||||||
#include "gimpcontainerentry.h"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Structures
|
|
||||||
|
|
||||||
When declaring a structure type use newlines to separate logical sections:
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* preferred for new code*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
gint n_pages;
|
|
||||||
gint *pages;
|
|
||||||
|
|
||||||
gbool read_only;
|
|
||||||
} Pages;
|
|
||||||
```
|
|
||||||
|
|
||||||
When initializing a structure variable with constants, shortly enough
|
|
||||||
that it can be done on a single line, then you should add a space after
|
|
||||||
the opening curly brace and before the closing one, such as:
|
|
||||||
|
|
||||||
```C
|
|
||||||
GimpRGB color = { 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE };
|
|
||||||
```
|
|
||||||
|
|
||||||
### Memory management
|
|
||||||
|
|
||||||
To dynamically allocate data on the heap, use `g_new()`. To allocate memory for
|
|
||||||
multiple small data structures, `g_slice_new()`.
|
|
||||||
|
|
||||||
When possible, all public structure types should be returned fully initialized,
|
|
||||||
either explicitly for each member or by using `g_new0()` or `g_slice_new0()`.
|
|
||||||
|
|
||||||
As a general programming rule, it is better to allocate and free data on the
|
|
||||||
same level. It is much easier to review code because you know that when you
|
|
||||||
allocate something there, then you also free it there.
|
|
||||||
|
|
||||||
```c
|
|
||||||
GeglBuffer *buffer;
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
*buffer = gegl_buffer_new (some, args);
|
|
||||||
*p = g_new (something, n);
|
|
||||||
|
|
||||||
/* do stuff */
|
|
||||||
|
|
||||||
g_object_unref (buffer);
|
|
||||||
g_free (p);
|
|
||||||
```
|
|
||||||
|
|
||||||
When a transfer of ownership is unavoidable make it clear in the function
|
|
||||||
documentation.
|
|
||||||
|
|
||||||
### Comments
|
|
||||||
#### In-code explanation
|
|
||||||
|
|
||||||
The only allowed style is C-style comments `/* */`. In particular C++
|
|
||||||
comments `//` are strictly forbidden from our source.
|
|
||||||
|
|
||||||
We are not asking contributors to over-comment their code, yet we highly
|
|
||||||
value quality comments to explain complicated algorithms or non-obvious
|
|
||||||
code. Just ask yourself this: what if someone sees my code 5 years later
|
|
||||||
(another contributor or even your future self)…
|
|
||||||
|
|
||||||
- will one easily understand what you meant to do?
|
|
||||||
- In particular: if it needs to be removed later, won't one be scared to
|
|
||||||
delete now-useless code by fear of unexpected side-effects?
|
|
||||||
- Or oppositely: won't someone delete the code by mistake because it
|
|
||||||
looks useless while it was actually dealing with a very particular
|
|
||||||
(yet absolutely non-obvious) issue?
|
|
||||||
|
|
||||||
Adding links which explain well a problem or the reason for some
|
|
||||||
non-obvious code is also permitted. For instance a link to a bug report
|
|
||||||
(ours or some other projects') can sometimes be a good complement to a
|
|
||||||
comment.
|
|
||||||
Nevertheless it should not be overdone and in particular not for links
|
|
||||||
likely to disappear (personal blog posts, forums, corporate websites
|
|
||||||
which often revamp their design, breaking URLs, etc.).
|
|
||||||
|
|
||||||
#### Public API Documentation
|
|
||||||
|
|
||||||
All public APIs (i.e. any function exported in a header inside
|
|
||||||
`libgimp*/` folders) **MUST** have proper GObject-introspection (GIR) comments.
|
|
||||||
For functions, these should be placed in the source file directly above.
|
|
||||||
|
|
||||||
These annotations are also relevant for [GObject
|
|
||||||
Introspection](https://gi.readthedocs.io/en/latest/annotations/giannotations.html)
|
|
||||||
to generate bindings for other languages.
|
|
||||||
|
|
||||||
```c
|
|
||||||
/* valid */
|
|
||||||
/**
|
|
||||||
* gimp_object_set_name:
|
|
||||||
* @object: a #GimpObject
|
|
||||||
* @name: the @object's new name (transfer none)
|
|
||||||
*
|
|
||||||
* Sets the @object's name. Takes care of freeing the old name and
|
|
||||||
* emitting the ::name_changed signal if the old and new name differ.
|
|
||||||
**/
|
|
||||||
void
|
|
||||||
gimp_object_set_name (GimpObject *object,
|
|
||||||
const gchar *name)
|
|
||||||
{
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Doc comments for macros, function types, class structs, etc., should be placed
|
|
||||||
next to the definitions, typically in headers.
|
|
||||||
|
|
||||||
#### Non-public API documentation
|
|
||||||
|
|
||||||
Project-only code (for instance any code from the `app/` folder) can be
|
|
||||||
less documented. For instance when a function has obvious naming, not
|
|
||||||
explaining it is perfectly acceptable.
|
|
||||||
|
|
||||||
Nevertheless adding documentation even for these private APIs is
|
|
||||||
welcome, especially when the usage is not as obvious as it looks, or
|
|
||||||
to make sure to advertize the proper memory handling (does it allocate
|
|
||||||
new memory? Which function to free it with? Or shouldn't the returned
|
|
||||||
memory be freed?), avoiding silly bugs and not wasting developer times
|
|
||||||
(when we have to look at the implementation to verify each time we use a
|
|
||||||
function).
|
|
||||||
|
|
||||||
In such a case, using gtk-docs syntax is still a nice idea as we will
|
|
||||||
understand it directly (even though we won't generate any docs from it).
|
|
||||||
|
|
||||||
### Public API
|
|
||||||
#### No variables
|
|
||||||
|
|
||||||
Avoid exporting variables as public API since this is cumbersome on some
|
|
||||||
platforms. It is always preferable to add getters and setters instead.
|
|
||||||
|
|
||||||
#### Def files for Windows
|
|
||||||
|
|
||||||
List all public functions alphabetically in the corresponding `.def` file.
|
|
||||||
|
|
||||||
- `app/gimpcore.def`
|
|
||||||
- `libgimp/gimp.def`
|
|
||||||
- `libgimpbase/gimpbase.def`
|
|
||||||
- etc
|
|
||||||
|
|
||||||
## Natural language text
|
|
||||||
|
|
||||||
### Base rules
|
|
||||||
|
|
||||||
Any text in GIMP source should follow these base rules:
|
|
||||||
|
|
||||||
- Our base language is US English, both for historical reason and
|
|
||||||
because this is the usual expectation with `gettext`, the
|
|
||||||
localization tool used by GIMP. In particular when variants of words
|
|
||||||
or idioms exist in several native English countries, we should choose
|
|
||||||
the US variant. Other English variants can be used in specific locales
|
|
||||||
(such as `en_GB` or `en_CA`…).
|
|
||||||
- Text meant for technical people, such as API documentation (in-code
|
|
||||||
comments, in-repository documentation, or gtk-doc/docgen style
|
|
||||||
comments for generated docs…) usually does not need localization, and
|
|
||||||
therefore can just be written in US English.
|
|
||||||
- Text meant to be viewed by all users should be translatable. In
|
|
||||||
particular in GIMP source code, it means that we need to use `gettext`
|
|
||||||
API.
|
|
||||||
- Use gender-neutral terms, in particular not using words such as "she/he"
|
|
||||||
or "her/his" is better. We should not use over-complicated wording to
|
|
||||||
achieve this and should look for simpler writing if necessary.
|
|
||||||
- Be nice and open-minded in all text, even in code comments. Remember
|
|
||||||
these will be read by others and that we are here to have fun
|
|
||||||
together, not fight.
|
|
||||||
|
|
||||||
### User-visible text in C code
|
|
||||||
|
|
||||||
As explained, C code uses the gettext API. Any text which might appear
|
|
||||||
in front of people should be translatable, with the following
|
|
||||||
exceptions:
|
|
||||||
|
|
||||||
- Error or warning output in `stderr` might often be untranslated
|
|
||||||
(because we assume these are mostly used for debugging and people who
|
|
||||||
will see these would be more comfortable with digging into issue
|
|
||||||
causes; also it makes debugging and searches in code easier).
|
|
||||||
- Technical error text in the graphical interface when it is made to be
|
|
||||||
reported to developers. Basically error messages meant for users
|
|
||||||
themselves should still be translatable. For instance, if one tries to
|
|
||||||
draw on a layer group, we'd display:
|
|
||||||
|
|
||||||
```C
|
|
||||||
_("Cannot modify the pixels of layer groups.")
|
|
||||||
```
|
|
||||||
|
|
||||||
Indeed this is an error message to give an information to the user.
|
|
||||||
It's not a bug.
|
|
||||||
Now when a crash happens, we add a translated header message to
|
|
||||||
explain a problem occured, but the core information stays in English
|
|
||||||
because we are not asking people to understand it, only report it to
|
|
||||||
us.
|
|
||||||
|
|
||||||
The most common variant of gettext API is the underscore `_()` (alias of
|
|
||||||
`gettext()`) for simple text:
|
|
||||||
|
|
||||||
```C
|
|
||||||
frame = gimp_frame_new (_("Shadows"));
|
|
||||||
```
|
|
||||||
|
|
||||||
When used in some widgets, we may want to add mnemonics for
|
|
||||||
accessibility. This is done with the underscore:
|
|
||||||
|
|
||||||
```C
|
|
||||||
label = gtk_label_new_with_mnemonic (_("_Width:"));
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that it is a good idea to not change well-known mnemonics, such as
|
|
||||||
`_("_OK")`, `_("_Cancel")` or `_("_Reset")`. Also you should avoid using
|
|
||||||
the same mnemonics in 2 widgets on the same interface (even though GTK
|
|
||||||
has some way to handle mnemonic duplicate, but it's not really
|
|
||||||
practical).
|
|
||||||
|
|
||||||
Translators may (and often will) change mnemonics. It is therefore up to
|
|
||||||
them to take care of not having the same mnemonics on a same interface
|
|
||||||
in their specific locale.
|
|
||||||
|
|
||||||
When some messages cannot be translated at initialization, you must use
|
|
||||||
the no-op variant `N_()`. For instance, when we declare and initialize a
|
|
||||||
struct:
|
|
||||||
|
|
||||||
```C
|
|
||||||
static const struct
|
|
||||||
{
|
|
||||||
const gchar *name;
|
|
||||||
const gchar *description;
|
|
||||||
}
|
|
||||||
babl_descriptions[] =
|
|
||||||
{
|
|
||||||
{ "RGB u8", N_("RGB") },
|
|
||||||
[…]
|
|
||||||
{ "Y u8", N_("Grayscale") },
|
|
||||||
[…]
|
|
||||||
{ "R u8", N_("Red component") },
|
|
||||||
[…]
|
|
||||||
{ "G u8", N_("Green component") },
|
|
||||||
[…]
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
The normal gettext `_()` would not compile because you must initialize
|
|
||||||
struct elements with constants. `N_()` allows the gettext tools to
|
|
||||||
detect the strings which will need to go into the translator files.
|
|
||||||
Note though that these strings will still need to be translated when
|
|
||||||
used at runtime:
|
|
||||||
|
|
||||||
```C
|
|
||||||
g_hash_table_insert (babl_description_hash,
|
|
||||||
(gpointer) babl_descriptions[i].name,
|
|
||||||
gettext (babl_descriptions[i].description));
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally note that for any strings which depends on a variable number,
|
|
||||||
you must use the ngettext variant:
|
|
||||||
|
|
||||||
```C
|
|
||||||
desc = g_strdup_printf (ngettext ("Crop Layer to Selection",
|
|
||||||
"Crop %d Layers to Selection",
|
|
||||||
g_list_length (layers)),
|
|
||||||
g_list_length (layers));
|
|
||||||
```
|
|
||||||
|
|
||||||
It is important to use `ngettext()` even in cases where there will
|
|
||||||
always be a count bigger than 1. Say our indexed image do not support
|
|
||||||
the monochrome (1 color) case, and even less 0 colors, then this seems
|
|
||||||
useless because we will always use the second string only:
|
|
||||||
|
|
||||||
```C
|
|
||||||
g_snprintf (buf, sizeof (buf),
|
|
||||||
ngettext ("Indexed color (monochrome)",
|
|
||||||
"Indexed color (%d colors)",
|
|
||||||
gimp_image_get_colormap_size (image)),
|
|
||||||
gimp_image_get_colormap_size (image));
|
|
||||||
```
|
|
||||||
|
|
||||||
Yet it's actually not useless as it allows translators for languages
|
|
||||||
with more plural forms to translate GIMP correctly. For instance,
|
|
||||||
[gettext documentation](https://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms)
|
|
||||||
mentions the Polish language has different grammatical agreements for
|
|
||||||
2,3,4 and 5-21 or again 22-24 and so on. If we were to use solely
|
|
||||||
`_("Indexed color (%d colors)")`, Polish translators would not be able
|
|
||||||
to list all these cases (therefore GIMP would have a crappy Polish
|
|
||||||
localization), so we have to use `ngettext()` even if it feels useless
|
|
||||||
in English.
|
|
||||||
|
|
||||||
Finally when you add translated strings in a file which had none until
|
|
||||||
now, for it to be processed by `gettext`, you need to add its path in
|
|
||||||
alphabetical order in `po/POTFILES.in` for core files (or other
|
|
||||||
`POTFILES.in`, for instance `po-plug-ins/POTFILES.in` for plug-ins). We
|
|
||||||
have a test checking this, so the `make distcheck` step will fail anyway
|
|
||||||
when you forgot to add a new file with translation. Yet as developers
|
|
||||||
don't always run this step locally, the bug may be discovered during CI
|
|
||||||
builds. It is obviously prefered to not forget it hence not push code
|
|
||||||
which breaks the CI (and localization).
|
|
||||||
|
|
||||||
## Helping tools
|
|
||||||
### Git
|
|
||||||
|
|
||||||
We recommend enabling the default git pre-commit hook that detects trailing
|
|
||||||
whitespace and non-ASCII filenames for you and helps you to avoid corrupting
|
|
||||||
GIMP's tree with it.
|
|
||||||
|
|
||||||
In the terminal, navigate into your GIMP source code folder. Then do that as
|
|
||||||
follows (one command at a time):
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cp -v .git/hooks/pre-commit.sample .git/hooks/pre-commit
|
|
||||||
chmod a+x .git/hooks/pre-commit
|
|
||||||
```
|
|
||||||
|
|
||||||
If any command above fails, visit your `.git/hooks/` folder and check for the
|
|
||||||
existence of `pre-commit.sample` or `pre-commit` files.
|
|
||||||
|
|
||||||
You might also find the `git-stripspace` utility helpful, which acts as a filter
|
|
||||||
to remove trailing whitespace as well as initial, final, and duplicate blank
|
|
||||||
lines.
|
|
||||||
|
|
||||||
### Code editor / Integrated Development Environment (IDE)
|
|
||||||
|
|
||||||
GIMP's codebase is not tied to a specific editor or IDE. The whole build
|
|
||||||
can be performed from anywhere, and we don't care what you write your
|
|
||||||
code with (as long as it follows syntax rules from this document).
|
|
||||||
|
|
||||||
Several configuration files were contributed across the years to
|
|
||||||
configure your favorite software to follow our coding style.
|
|
||||||
You are very welcome to use them (or improve them and contribute the
|
|
||||||
change when they are not perfect):
|
|
||||||
|
|
||||||
- [.dir-locals.el](.dir-locals.el) for Emacs;
|
|
||||||
- [.kateconfig](.kateconfig) for Kate;
|
|
||||||
- [c.vim](devel-docs/c.vim) for Vim (check the top comments to see how
|
|
||||||
to enable it automatically when opening a file in the GIMP tree).
|
|
||||||
|
|
||||||
*Note: the Kate and Emacs config file should work out-of-the-box, but
|
|
||||||
the Vim one needs to be enabled explicitly because it is too powerful,
|
|
||||||
hence is basically [unsafe](https://github.com/vim/vim/issues/1015).*
|
|
||||||
|
|
||||||
If you use another software to write code, you are welcome to contribute
|
|
||||||
coding style files following our rules.
|
|
||||||
|
|
||||||
### Code Formatter
|
|
||||||
|
|
||||||
Our project contains a `.clang-format` in the repository root.
|
|
||||||
|
|
||||||
A good way to test your code is with the following command while it's
|
|
||||||
not committed yet:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
git diff -U0 --no-color | clang-format-diff -p1
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that we are not considering these format rules as perfect, because
|
|
||||||
it seems the tool still cannot handle several special cases we have in
|
|
||||||
our coding style. Also we are not perfectly fond of the way it handles
|
|
||||||
long lines (when to accept lines a bit longer than the max line width or
|
|
||||||
not) as well as other rules. Therefore the current document remains the
|
|
||||||
ultimate one to verify when unsure of how to format something.
|
|
||||||
|
|
||||||
The CI for any merge request will contain a job called `clang-format`
|
|
||||||
which will also run your proposed change through the clang-format code
|
|
||||||
formatter as a soft verification of contributed patches. Note that this
|
|
||||||
job is only informational and in particular, it isn't considered a CI
|
|
||||||
failure, since — as said above — we are not perfectly happy with the
|
|
||||||
tool yet.
|
|
||||||
Nevertheless we expect new contributors to look at the result to fix
|
|
||||||
their basic coding style mistakes and free up reviewing contributors'
|
|
||||||
time.
|
|
|
@ -135,10 +135,10 @@ request or attach your patch to the report as a plain text file, not
|
||||||
compressed.
|
compressed.
|
||||||
|
|
||||||
Please follow the guidelines for coding style and other requirements
|
Please follow the guidelines for coding style and other requirements
|
||||||
listed in [CODING_STYLE.md](CODING_STYLE.md). When you will contribute
|
listed in [CODING_STYLE.md](https://developer.gimp.org/core/coding_style/). When
|
||||||
your first patches, you will notice that we care very much about clean
|
you will contribute your first patches, you will notice that we care very much
|
||||||
and tidy code, which helps for understanding. Hence we care about coding
|
about clean and tidy code, which helps for understanding. Hence we care about
|
||||||
style and consistency!
|
coding style and consistency!
|
||||||
|
|
||||||
|
|
||||||
## Auto-generated Files
|
## Auto-generated Files
|
||||||
|
|
|
@ -7,12 +7,10 @@ SUBDIRS = \
|
||||||
performance-logs
|
performance-logs
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
CODING_STYLE.md \
|
|
||||||
HACKING.md \
|
HACKING.md \
|
||||||
README.md \
|
README.md \
|
||||||
contexts.txt \
|
contexts.txt \
|
||||||
debug-plug-ins.txt \
|
debug-plug-ins.txt \
|
||||||
exif-handling.txt \
|
|
||||||
gitlab-milestones.txt \
|
gitlab-milestones.txt \
|
||||||
includes.txt \
|
includes.txt \
|
||||||
libtool-instructions.txt \
|
libtool-instructions.txt \
|
||||||
|
|
|
@ -383,7 +383,7 @@ Eventually we want to move this pipeline to Gitlab as well.
|
||||||
|
|
||||||
When writing code, any core developer is expected to follow:
|
When writing code, any core developer is expected to follow:
|
||||||
|
|
||||||
- GIMP's [coding style](CODING_STYLE.md);
|
- GIMP's [coding style](https://developer.gimp.org/core/coding_style/);
|
||||||
- the [directory structure](#directory-structure-of-gimp-source-tree)
|
- the [directory structure](#directory-structure-of-gimp-source-tree)
|
||||||
- our [header file inclusion policy](includes.txt)
|
- our [header file inclusion policy](includes.txt)
|
||||||
|
|
||||||
|
@ -589,7 +589,7 @@ Developers are welcome to read the [specifications of XCF](specifications/xcf.tx
|
||||||
Items in an image can be locked in various ways to prevent different
|
Items in an image can be locked in various ways to prevent different
|
||||||
types of edits.
|
types of edits.
|
||||||
|
|
||||||
This is further explained in [the specifications of locks](specifications/locks.md).
|
This is further explained in [the specifications of locks](https://developer.gimp.org/core/specifications/locks/).
|
||||||
|
|
||||||
#### UI Framework
|
#### UI Framework
|
||||||
|
|
||||||
|
@ -627,11 +627,11 @@ GIMP supports Exif, IPTC and XMP metadata as well as various image
|
||||||
format-specific metadata. The topic is quite huge and complex, if not
|
format-specific metadata. The topic is quite huge and complex, if not
|
||||||
overwhelming.
|
overwhelming.
|
||||||
|
|
||||||
This [old document](exif-handling.txt) might be of interest (or maybe
|
This [old document](https://developer.gimp.org/core/specifications/exif_handling/)
|
||||||
not, it has not been recently reviewed and might be widely outdated; in
|
might be of interest (or maybe not, it has not been recently reviewed and might
|
||||||
any case, it is not a complete document at all as we definitely do a lot
|
be widely outdated; in any case, it is not a complete document at all as we
|
||||||
more nowadays). **TODO**: review this document and delete or update it
|
definitely do a lot more nowadays). **TODO**: review this document and delete or
|
||||||
depending of whether it still makes sense.
|
update it depending of whether it still makes sense.
|
||||||
|
|
||||||
#### Tagging
|
#### Tagging
|
||||||
|
|
||||||
|
|
|
@ -1,274 +0,0 @@
|
||||||
===================================
|
|
||||||
Compositing and layer modes in GIMP
|
|
||||||
===================================
|
|
||||||
|
|
||||||
This document describes the process of compositing layers and the layer modes
|
|
||||||
in GIMP.
|
|
||||||
|
|
||||||
License
|
|
||||||
-------
|
|
||||||
This is free documentation; you can modify and/or redistribute
|
|
||||||
it according to the terms of the GNU General Public License
|
|
||||||
as published by the Free Software Foundation, either version
|
|
||||||
2 of the license, or (at your option) any later version.
|
|
||||||
|
|
||||||
About this document
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
This document was originally written by Henning Makholm and part of the
|
|
||||||
XCF file format specification. Because the topics here are more general
|
|
||||||
in the context of GIMP they have been moved into a separate document.
|
|
||||||
|
|
||||||
9. COMPOSITING AND LAYER MODES
|
|
||||||
===============================
|
|
||||||
|
|
||||||
This section describes the "flattening" process that GIMP applies
|
|
||||||
when a multi-layer image is displayed in the editor or exported to
|
|
||||||
other image file formats. It is present for reference only; an XCF
|
|
||||||
consumer may well elect to do something different with pixel data from
|
|
||||||
the layers than flattening them.
|
|
||||||
|
|
||||||
Most XCF consumers will need to react to the layer mode property of
|
|
||||||
each layer; such a reaction must be informed by knowledge of how the
|
|
||||||
different layer modes affect the flattening process. In some
|
|
||||||
applications it might be acceptable for an XCF consumer to refuse
|
|
||||||
processing images with layer modes other than "Normal", but such an
|
|
||||||
application will probably not be considered fully XCF capable by its
|
|
||||||
users.
|
|
||||||
|
|
||||||
In this section we consider primary color (or grayscale) intensities
|
|
||||||
and alpha values for pixels to be real numbers ranging from 0.0 to
|
|
||||||
1.0. This makes many of the formulas easier; the reader is asked to
|
|
||||||
keep in mind that a (linear) conversion from the integral 0..255 scale
|
|
||||||
of the actual XCF scale is implied whenever data from the XCF file is
|
|
||||||
mentioned.
|
|
||||||
|
|
||||||
Any practical implementation of the computations specified below may
|
|
||||||
suffer rounding errors; this specification do not detail how these are
|
|
||||||
to be handled. GIMP itself rounds values to an integral number of
|
|
||||||
255ths at many points in the computation. This specification does not
|
|
||||||
specify exactly which these points are, and authors of XCF renderers
|
|
||||||
that aim to reproduce the effects of GIMP's flattening down to the
|
|
||||||
least significant bits are referred to studying its source code.
|
|
||||||
|
|
||||||
In the description below, the variable letter "a" is used for alpha
|
|
||||||
values. The variable letter "r", "g", "b" are used for primary
|
|
||||||
intensities, "y" is used for grayscale intensities, and "i" is used
|
|
||||||
for color map indexed. The letter "c" is used for the complete
|
|
||||||
color information for a pixel; depending on the color mode of the
|
|
||||||
image that is either an (r,g,b) triple, a y, or a c.
|
|
||||||
|
|
||||||
The flattening process works independently for each pixel in the
|
|
||||||
canvas area. The description of some layer modes in the GIMP manual
|
|
||||||
may give the impression that they involve filters that let pixels
|
|
||||||
influence neighbor pixels, but that is not true.
|
|
||||||
|
|
||||||
This description does not attempt to preserve the color information
|
|
||||||
for completely transparent pixels in a layer. If an application uses
|
|
||||||
this color information, it should document explicitly how it behaves
|
|
||||||
when transparent pixels from several different layers cover the same
|
|
||||||
point of the canvas.
|
|
||||||
|
|
||||||
Flattening overview
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
This is how to compute the flattened result for a single pixel
|
|
||||||
position (in theory, that is - efficient implementations will of
|
|
||||||
course follow this procedure or an equivalent one for many pixels in
|
|
||||||
parallel):
|
|
||||||
|
|
||||||
1. Initialize a "working pixel" (a1,c1) to be completely transparent
|
|
||||||
(that is, a1=0.0 and the value of c1 is immaterial).
|
|
||||||
|
|
||||||
2. Do the following for each visible layer in the image, starting with
|
|
||||||
the one that comes LAST in the master layer list:
|
|
||||||
|
|
||||||
3. Ignore the layer if it is the floating selection, or if it
|
|
||||||
does not overlap the pixel position in question.
|
|
||||||
|
|
||||||
4. Let (a2,c2) be the pixel data for the layer at the pixel
|
|
||||||
position in question. If the layer does not have an alpha
|
|
||||||
channel, then set a1 to 1.0.
|
|
||||||
|
|
||||||
5. If the layer is the one that the floating selection is attached
|
|
||||||
to and the floating selection overlaps the pixel position in
|
|
||||||
question, then do the following:
|
|
||||||
|
|
||||||
6. Let (a3,c3) be the pixel data for the floating selection
|
|
||||||
layer at the pixel position in question.
|
|
||||||
|
|
||||||
7. If there is a selection channel, then let x be its value
|
|
||||||
at the pixel position in question, and set a3 to a3*x.
|
|
||||||
|
|
||||||
8. Let m3 be the layer mode of the floating selection.
|
|
||||||
|
|
||||||
9. Set (a2,c2) to COMPOSITE(a2,c2, a3,c3,m3).
|
|
||||||
The COMPOSITE function is defined below.
|
|
||||||
|
|
||||||
10. If the layer has a layer mask and it is enabled, then let x be
|
|
||||||
the value of the layer mask at the pixel position in question,
|
|
||||||
and set a2 to a2*x.
|
|
||||||
|
|
||||||
11. Let m2 be the layer mode of the layer.
|
|
||||||
|
|
||||||
12. If the layer is the bottommost visible layer (i.e., if it is
|
|
||||||
the last visible layer in the master layer list) and m2 is not
|
|
||||||
"Normal" or "Dissolve", then set m2 to "Normal".
|
|
||||||
|
|
||||||
13. Set (a1,c1) to COMPOSITE(a1,c1, a2,c2,m2).
|
|
||||||
The COMPOSITE function is defined below.
|
|
||||||
|
|
||||||
14. If the flattened image is to be shown against a background of
|
|
||||||
color c0, then actually visible pixel is
|
|
||||||
COMPOSITE(1.0,c0, a1,c1,Normal).
|
|
||||||
|
|
||||||
Note that unless all layers have mode Normal, it would give the
|
|
||||||
wrong result to start by initializing (a1,c1) to (1.0,c0).
|
|
||||||
|
|
||||||
Helper functions
|
|
||||||
----------------
|
|
||||||
|
|
||||||
The following auxiliary functions are used in the definition of
|
|
||||||
COMPOSITE below:
|
|
||||||
|
|
||||||
MIN(x1,...,xn) is the least value of x1...xn
|
|
||||||
|
|
||||||
MAX(x1,...,xn) is the largest value of x1..xn
|
|
||||||
|
|
||||||
MID(x1,...,xn) = (MIN(x1,...,xn)+MAX(x1,...,xn))/2
|
|
||||||
|
|
||||||
CLAMP(x) = if x < 0 then 0.0 else if x > 1 then 1.0 else x
|
|
||||||
|
|
||||||
BLEND(a1,x1, a2,x2) = (1-k)*x1 + k*x2
|
|
||||||
where k = a2/(1-(1-a1)*(1-a2))
|
|
||||||
|
|
||||||
Layer modes
|
|
||||||
-----------
|
|
||||||
|
|
||||||
This and the following sections define the COMPOSITE function used in
|
|
||||||
the general flattening algorithm.
|
|
||||||
|
|
||||||
"Normal" mode for RGB or grayscale images is the usual mode of
|
|
||||||
compositing in computer graphics with alpha channels. In indexed
|
|
||||||
mode, the alpha value gets rounded to either 1.0 or 0.0 such that
|
|
||||||
no colors outside the color map get produced:
|
|
||||||
|
|
||||||
COMPOSITE(a1,y1, a2,y2,Normal)
|
|
||||||
= ( 1-(1-a1)*(1-a2), BLEND(a1,y1, a2,y2) )
|
|
||||||
|
|
||||||
COMPOSITE(a1,r1,g1,b1, a2,r2,g2,b2,Normal)
|
|
||||||
= ( 1-(1-a1)*(1-a2), BLEND(a1,r1, a2,r2),
|
|
||||||
BLEND(a1,g1, a2,g2),
|
|
||||||
BLEND(a1,b1, a2,b2) )
|
|
||||||
|
|
||||||
COMPOSITE(a1,i1, a2,i2,Normal) = if a2 > 0.5 then (1.0,i2) else (a1,i1)
|
|
||||||
|
|
||||||
"Dissolve" mode corresponds to randomly dithering the alpha channel to
|
|
||||||
the set {0.0, 1.0}:
|
|
||||||
|
|
||||||
COMPOSITE(a1,c1, a2,c2,Dissolve) = chose pseudo-randomly between
|
|
||||||
(1.0,c2) with probability a2
|
|
||||||
(a1,c1) with probability 1-a2
|
|
||||||
|
|
||||||
These two modes are the only ones that make sense for all of the RGB,
|
|
||||||
grayscale and indexed color models. In the indexed color model, all
|
|
||||||
layer modes except Dissolve are treated as Normal.
|
|
||||||
|
|
||||||
Most layer modes belong to the following group, which makes sense for
|
|
||||||
RGB and grayscale images, but not for indexed ones:
|
|
||||||
|
|
||||||
COMPOSITE(a1,y2, a2,y2,m)
|
|
||||||
= ( a1, BLEND(a1,y1, MIN(a1,a2),f(y1,y2, m)) )
|
|
||||||
|
|
||||||
COMPOSITE(a1,r1,g1,b1, a2,r2,g2,b2,m)
|
|
||||||
= ( a1, BLEND(a1,r2, MIN(a1,a2),f(r1,r2, m)),
|
|
||||||
BLEND(a1,g1, MIN(a1,a2),f(g1,g2, m)),
|
|
||||||
BLEND(a1,b1, MIN(a1,a2),f(b1,g2, m)) )
|
|
||||||
|
|
||||||
when 3 <= m <= 10 or 15 <= m <= 21.
|
|
||||||
|
|
||||||
The following table defines f(x1,x2,m):
|
|
||||||
|
|
||||||
Multiply: f(x1,x2, 3) = x1*x2
|
|
||||||
Screen: f(x1,x2, 4) = 1-(1-x1)*(1-x2)
|
|
||||||
Overlay: f(x1,x2, 5) = (1-x2)*x1^2 + x2*(1-(1-x2)^2)
|
|
||||||
Difference: f(x1,x2, 6) = if x1 > x2 then x1-x2 else x2-x1
|
|
||||||
Addition: f(x1,x2, 7) = CLAMP(x1+x2)
|
|
||||||
Subtract: f(x1,x2, 8) = CLAMP(x1-x2)
|
|
||||||
Darken Only: f(x1,x2, 9) = MIN(x1,x2)
|
|
||||||
Lighten Only: f(x1,x2, 10) = MAX(x1,x2)
|
|
||||||
Divide: f(x1,x2, 15) = CLAMP(x1/x2)
|
|
||||||
Dodge: f(x1,x2, 16) = CLAMP(x1/(1-x2))
|
|
||||||
Burn f(x1,x2, 17) = CLAMP(1-(1-x1)/x2)
|
|
||||||
Hard Light: f(x1,x2, 18) = if x2 < 0.5 then 2*x1*x2 else 1-2*(1-x1)(1-x2)
|
|
||||||
Soft Light: f(x1,x2, 19) = (1-x2)*x1^2 + x2*(1-(1-x2)^2)
|
|
||||||
Grain Extract: f(x1,x2, 20) = CLAMP(x1-x2+0.5)
|
|
||||||
Grain Merge: f(x1,x2, 21) = CLAMP(x1+x2-0.5)
|
|
||||||
|
|
||||||
Note that the "Overlay" and "Soft Light" modes have identical effects.
|
|
||||||
In the "Divide", "Dodge", and "Burn" modes, division by zero should
|
|
||||||
be considered to produce a number so large that CLAMP(x/0) = 1 unless
|
|
||||||
x=0, in which case CLAMP(0/0) = 0.
|
|
||||||
|
|
||||||
The remaining four layer modes only make sense in the RGB color model;
|
|
||||||
if the color mode of the image is grayscale or indexed they will be
|
|
||||||
interpreted as Normal.
|
|
||||||
|
|
||||||
COMPOSITE(a1,r1,g1,b1, a2,r2,g2,b2,m)
|
|
||||||
= ( a1, BLEND(a1,r2, MIN(a1,a2),r0),
|
|
||||||
BLEND(a1,g1, MIN(a1,a2),g0),
|
|
||||||
BLEND(a1,b1, MIN(a1,a2),b0) )
|
|
||||||
where (r0,g0,b0) = h(r1,g1,b1, r2,g2,b2, m)
|
|
||||||
|
|
||||||
when 11 <= m <= 14.
|
|
||||||
|
|
||||||
For defining these modes, we say that
|
|
||||||
|
|
||||||
(r,g,b) has the _hue_ of (r',g',b')
|
|
||||||
if r' = g' = b' and r >= g = b
|
|
||||||
or there exist p and q such that p>=0 and r=p*r'+q and b=p*b'+q and g=p*g'+q
|
|
||||||
|
|
||||||
(r,g,b) has the _value_ of (r',g',b')
|
|
||||||
if MAX(r,g,b) = MAX(r',g',b')
|
|
||||||
|
|
||||||
(r,g,b) has the _HSV-saturation_ of (r',g',b')
|
|
||||||
if r' = g' = b' = 0 and r = g = b
|
|
||||||
or MIN(r,g,b) = MAX(r,g,b)*MIN(r',g',b')/MAX(r',g',b')
|
|
||||||
|
|
||||||
(r,g,b) has the _luminosity_ of (r',g',b')
|
|
||||||
if MID(r,g,b) = MID(r',g',b')
|
|
||||||
|
|
||||||
(r,g,b) has the _HSL-saturation_ of (r',g',b')
|
|
||||||
if r' = g' = b' and r = g = b
|
|
||||||
or MAX(r,g,b)-MIN(r,g,b) = MIN(MID(r,g,b),1-MID(r,g,b)) *
|
|
||||||
(MAX(r',g',b')-MIN(r',g',b'))/MIN(MID(r',g',b'),1-MID(r',g',b'))
|
|
||||||
|
|
||||||
Mode 11: Hue (H of HSV)
|
|
||||||
|
|
||||||
h(r1,g1,b1, r2,g2,b2, 11) is
|
|
||||||
if r2=g2=b2 then (r1,g1,b1) unchanged
|
|
||||||
otherwise: the color that has
|
|
||||||
the hue of (r1,g2,b2)
|
|
||||||
the value of (r1,g1,b1)
|
|
||||||
the HSV-saturation of (r1,g1,b1)
|
|
||||||
|
|
||||||
Mode 12: Saturation (S of HSV)
|
|
||||||
|
|
||||||
h(r1,g1,b1, r2,g2,b2, 12) is the color that has
|
|
||||||
the hue of (r1,g1,b1)
|
|
||||||
the value of (r1,g1,b1)
|
|
||||||
the HSV-saturation of (r2,g2,b2)
|
|
||||||
|
|
||||||
Mode 13: Color (H and S of HSL)
|
|
||||||
|
|
||||||
h(r1,g1,b1, r2,g2,b2, 13) is the color that has
|
|
||||||
the hue of (r2,g2,b2)
|
|
||||||
the luminosity of (r1,g1,b1)
|
|
||||||
the HSL-saturation of (r2,g2,b2)
|
|
||||||
|
|
||||||
Mode 14: Value (V of HSV)
|
|
||||||
|
|
||||||
h(r1,g1,b1, r2,g2,b2, 14) is the color that has
|
|
||||||
the hue of (r1,g1,b1)
|
|
||||||
the value of (r2,g2,b2)
|
|
||||||
the HSV-saturation of (r1,g1,b1)
|
|
|
@ -1,97 +0,0 @@
|
||||||
How GIMP should handle EXIF data
|
|
||||||
|
|
||||||
Bill Skaggs 1/2/05
|
|
||||||
|
|
||||||
This is a summary of how an image editing program is supposed to
|
|
||||||
handle each of the EXIF fields, according to the EXIF specs. Note
|
|
||||||
that this expresses my understanding based on a quick reading, and
|
|
||||||
should not be taken as gospel. For details on the contents of each of
|
|
||||||
these fields, consult the formal EXIF specifications, available from
|
|
||||||
http://www.exif.org/specifications.html.
|
|
||||||
|
|
||||||
(Note: according to the EXIF specs, an EXIF jpeg file must have a name
|
|
||||||
that is ASCII, in 8.3 format, with extension .JPG, but of course we
|
|
||||||
are not going to enforce this.)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Fields that should be used to set up the GIMP image when an EXIF file
|
|
||||||
is loaded, either by using them to configure the image (e.g.,
|
|
||||||
orientation), or by placing them in parasites that can be accessed by
|
|
||||||
non-exif-aware functions.
|
|
||||||
|
|
||||||
Orientation
|
|
||||||
XResolution
|
|
||||||
YResolution
|
|
||||||
ResolutionUnit
|
|
||||||
ImageDescription
|
|
||||||
Artist
|
|
||||||
Copyright
|
|
||||||
Colorspace
|
|
||||||
ComponentsConfiguration
|
|
||||||
UserComment
|
|
||||||
SubjectArea
|
|
||||||
SubjectLocation
|
|
||||||
ImageUniqueID
|
|
||||||
PixelXDimension
|
|
||||||
PixelYDimension
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Fields that should be modified by GIMP when an EXIF jpeg file is
|
|
||||||
saved. A letter "M" indicates fields whose presence is mandatory
|
|
||||||
according to the spec.
|
|
||||||
|
|
||||||
Orientation
|
|
||||||
XResolution (M)
|
|
||||||
YResolution (M)
|
|
||||||
ResolutionUnit (M)
|
|
||||||
Software
|
|
||||||
DateTime
|
|
||||||
ImageDescription
|
|
||||||
Artist
|
|
||||||
Colorspace (M)
|
|
||||||
PixelXDimension (M)
|
|
||||||
PixelYDimension (M)
|
|
||||||
ComponentsConfiguration (M)
|
|
||||||
UserComment
|
|
||||||
SubsecTime
|
|
||||||
SubjectArea
|
|
||||||
SubjectLocation
|
|
||||||
FileSource
|
|
||||||
ImageUniqueID
|
|
||||||
thumbnail Compression (M)
|
|
||||||
thumbnail XResolution (M)
|
|
||||||
thumbnail YResolution (M)
|
|
||||||
thumbnail JPEGInterchangeFormat (M)
|
|
||||||
thumbnail JPEGInterchangeFormatLength (M)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Fields that should be used and saved related to color management:
|
|
||||||
|
|
||||||
TransferFunction
|
|
||||||
WhitePoint
|
|
||||||
PrimaryChromaticity
|
|
||||||
YCbCrCoefficients
|
|
||||||
ReferenceBlackWhite
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Fields that should be deleted if they exist when saving a file as
|
|
||||||
jpeg, because they only apply to uncompressed (TIFF) data. This
|
|
||||||
applies both to the main image and to the thumbnail, if there is one.
|
|
||||||
|
|
||||||
ImageWidth
|
|
||||||
ImageLength
|
|
||||||
BitsPerSample
|
|
||||||
Compression
|
|
||||||
SamplesPerPixel
|
|
||||||
PhotometricInterpretation
|
|
||||||
StripOffsets
|
|
||||||
PlanarConfiguration
|
|
||||||
YCbCrSubSampling
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Any field not mentioned here should be passed through unchanged.
|
|
Loading…
Reference in New Issue