diff --git a/.gitignore b/.gitignore index 714e0726db367a49615a396e28a162987af47b42..364fdec1aa19d3a1f8d926d500c0beffe5674be8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1 @@ -*.html -autolayout.xml -depends.tabular -gimpcon -screenshots/*thumb.png -writing-a-plug-in +public/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..b24307b7b9c7a71b4bee695fc8347e93d87bbf90 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,15 @@ + + +image: registry.gitlab.com/pages/hugo/hugo_extended:latest + +variables: + GIT_SUBMODULE_STRATEGY: recursive + +pages: + script: + - hugo + artifacts: + paths: + - public + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH diff --git a/.hugo_build.lock b/.hugo_build.lock new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Makefile b/Makefile deleted file mode 100644 index fdc8d9241d65261e114a70be49f1ebd049b9dcbb..0000000000000000000000000000000000000000 --- a/Makefile +++ /dev/null @@ -1,32 +0,0 @@ - -SUBDIRS=screenshots - -PROC=xsltproc -STYLEDIR=xsl -SCRIPTDIR=scripts -STYLESHEET=$(STYLEDIR)/mine.xsl - -all: subdirs website - -include depends.tabular - -subdirs: $(SUBDIRS) - -$(SUBDIRS): - $(MAKE) -C $@ - -autolayout.xml: layout.xml - $(PROC) $(STYLEDIR)/autolayout.xsl $< > $@ - $(MAKE) depends - -%.html: autolayout.xml - $(PROC) $(STYLESHEET) $(filter-out autolayout.xml,$^) $(TIDY) > $@ - -depends: autolayout.xml - $(PROC) $(STYLEDIR)/makefile-dep.xsl $< > depends.tabular - -depends.tabular: layout.xml - touch $@ - $(MAKE) depends - -.PHONY: clean subdirs $(SUBDIRS) diff --git a/README b/README index 3bafa09fc29a5d8126fb99efa00749fe7ad0f977..452314a99e7dcfa5b6f89a94f4c710ce632fb5e5 100644 --- a/README +++ b/README @@ -1,55 +1,37 @@ developer.gimp.org ------------------ -This CVS module holds the source for the developer.gimp.org website. -CVS commits to this module cause the website to be updated immidately. +This git repository holds the source for the developer.gimp.org website. + +Commits to this module cause the website to be updated immediately. So please do test all your changes locally before you commit them. A -prerequisite for local tests is that you can build the website. This -file will try to teach you how to do that... - -First of all some background information: The website is build using -DocBook XML. In particular we are using the WebSite doctype and -stylesheets. See http://docbook.sourceforge.net/projects/website/ for -more information on DocBook Website. - -In order to create HTML pages from the XML sources, you will need a -working DocBook XML setup. The default Makefile uses xsltproc as the -XSLT processor. This is a fairly common tool that you probably have -installed already; see http://xmlsoft.org/XSLT/xsltproc2.html. In -addition to the XSLT processor you need to have the DocBook DTDs and -stylesheets installed. And then, and that's often the problematic -part, you need an XML catalog (usually /etc/xml/catalog) that refers -the XSLT processors to the locally installed files. If that catalog is -missing or incomplete, xsltproc will try to download stylesheets -on-the-fly. This slows down processing considerably and since some -stylesheets are not always available online (mainly due to being -hosted on sourceforge) you should make sure that your catalog file is -complete. - -Assuming your setup is complete, all you need to do is to type 'make' -in the toplevel directory. The HTML files are created in the source -tree (but should not be checked into CVS). We also put the XML files -online. This allows to show people how easy the source for the HTML -pages looks like and to allow them to provide patches on the XML -sources w/o checking the whole thing out of CVS. - -The structure of the site is defined in the file layout.xml. Here the -hierarchy and relation of all pages is defined. If you want to add new -pages, start by adding a new tocentry here. Then, each XML file -corresponds to a HTML file in the generated site. We name the XML file -just like the HTML file in order to make our lifes easier. Please -stick to this rule if possible. - -If you want to add images, especially screenshots, please use the PNG -format (or JPEG if appropriate). Please add binary files such as -images with the -kb option so that the CVS server knows that the files -are binary and shouldn't attempt to create diffs. - -If you think there's info missing here, feel free to add it or send me -a mail with your questions. Before you do any commits to this CVS -module, please get in contact with me or write to the gimp-web -mailing-list. The only exception to this rule is an obvious build fix. -You are encouraged to not ask but simply do the fix then. - - - Sven Neumann +prerequisite for local tests is that you can build the website. + +## Testing your Changes + +Install hugo using the advice on +[their website](https://gohugo.io/getting-started/installing/). +Then build with + + $ hugo + +To test your site run: + + $ hugo serve + +The site will be hosted on your localhost with a port number decided +at launch, (by default 1313) so open for example: +[https://localhost:1313](https://localhost:1313) to see your changes. + +## Learning Hugo + +To learn how to edit the site start by reading any of the markdown +files while running your local server. It will automatically update +if you make changes and it should be easy to intuit how it works. + +For more advanced editing, read the +[official docs](https://gohugo.io/getting-started/usage/). + +The GIMP Development Team, +Sven Neumann + diff --git a/about.xml b/about.xml deleted file mode 100644 index a4a3cdd986ecf98779abcd8059b82d4ca885f6a0..0000000000000000000000000000000000000000 --- a/about.xml +++ /dev/null @@ -1,30 +0,0 @@ - - -]> - - - - - About this Site - About - About this Site - - - - The look of this site was borrowed from www.gimp.org. Under the hood - it is based on DocBook - Website. If you are curious, have a look at the XML source of the page you are reading. - - - - If you want to help us with developer.gimp.org, clone the - repository gimp-web-devel - from git. - - - diff --git a/api/2.0/index.html b/api/2.0/index.html deleted file mode 100644 index 1e65a92a725c8d762e60b76bb2f7a5b4de94130a..0000000000000000000000000000000000000000 --- a/api/2.0/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - GIMP Reference Manuals - - - - - - diff --git a/bugs.xml b/bugs.xml deleted file mode 100644 index 6c13a92295011eb4a173eae7f720bf735b6ca578..0000000000000000000000000000000000000000 --- a/bugs.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - Bug Tracking System - Gitlab - Bugs, bugs, bugs - - - - The GIMP project uses Gitlab's - issues, - to coordinate bug reports. Gitlab is also used for enhancement requests and the preferred - way to submit patches for The GIMP is make a - merge request. - - - - On www.gimp.org - you can find a document describing HOW TO - Report GIMP Bugs. You can also find a document that - describes How To - Create and Submit a Patch. - - - - Below is a list of links to get you started with Gitlab: - - - - List of Open Bugs - - - - List of Open Bugs (excluding enhancement requests) - - - - Tables of Open/Closed Bugs with milestone 2.10.34 - - - - Tables of Open/Closed Bugs with milestone 2.99.12 - - - - Issues without an associated, planned version number. - - - - - diff --git a/changelog.xml b/changelog.xml deleted file mode 100644 index 2b4bd40ec759bf5be964822426d654dfd86de446..0000000000000000000000000000000000000000 --- a/changelog.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - GIMP ChangeLog - ChangeLog - Keeping an eye on the development - - - - The - - GIT repository - - lists all changes in detail. The list below shows the latest - commits. It is generated from the RSS feed delivered by - the CIA. - - - - - diff --git a/config.toml b/config.toml new file mode 100644 index 0000000000000000000000000000000000000000..d869e0e86c4596ef96e56c3df4682a0e3c99fb2f --- /dev/null +++ b/config.toml @@ -0,0 +1,129 @@ +baseURL = "https://developer.gimp.org/" +languageCode = "en" +title = "GIMP Developer Resources" +author = "The GIMP Development Team" +theme = "hyde" +copyright = "Copyright 2003-2022 The GIMP Development Team" +DefaultContentLanguage = "en" +enableInlineShortcodes = true + +[taxanomies] +category = "categories" +tag = "tags" +series = "series" + +[menu] +[[menu.main]] + identifier = "git" + name = "Git" + url = "git.html" + weight = 10 + +[[menu.main]] + identifier = "changelog" + name = "ChangeLog" + url = "https://gitlab.gnome.org/browse/gimp/log/" + weight = 20 + +[[menu.main]] + identifier = "news" + name = "News" + url = "https://developer.gimp.org/NEWS" + weight = 21 + +[[menu.main]] + identifier = "hacking" + name = "Hacking" + url = "https://developer.gimp.org/HACKING" + weight = 22 + +[[menu.main]] + identifier = "gitlab" + name = "Gitlab" + url = "bugs.html" + weight = 30 + +[[menu.main]] + identifier = "mailing-lists" + name = "Mailing Lists" + url = "lists.html" + weight = 40 + +[[menu.main]] + identifier = "screenshots" + name = "Screenshots" + url = "screenshots.html" + weight = 50 + +[[menu.main]] + identifier = "plug-in" + name = "Plug-In Development" + url = "plug-ins.html" + weight = 60 + +[[menu.main]] + identifier = "api-ref" + name = "API Reference" + url = "api/2.0/index.html" + weight = 61 + +[[menu.main]] + identifier = "writing-plug-ins" + name = "Writing A Plug-In" + url = "writing-api-plug-in/1.html" + weight = 62 + +[[menu.main]] + identifier = "plug-in-template" + name = "Plug-In Template" + url = "plug-in-template.html" + weight = 63 + +[[menu.main]] + identifier = "conference" + name = "Conference" + url = "gimpcon/index.html" + weight = 70 + +[[menu.main]] + identifier = "gimpcon2000" + name = "GIMPCon 2000" + url = "gimpcon/2000/index.html" + weight = 71 + +[[menu.main]] + identifier = "gimpcon2003" + name = "GIMPCon 2003" + url = "gimpcon/2003/index.html" + weight = 72 + +[[menu.main]] + identifier = "gimpcon2004" + name = "GIMPCon 2004" + url = "gimpcon/2004/index.html" + weight = 73 + +[[menu.main]] + identifier = "gimpcon2006" + name = "GIMPCon 2006" + url = "gimpcon/2006/index.html" + weight = 74 + +[[menu.main]] + identifier = "faq" + name = "Developer FAQ" + url = "faq.html" + weight = 80 + +[[menu.main]] + identifier = "standards" + name = "Standards" + url = "standards.html" + weight = 90 + +[[menu.main]] + identifier = "about" + name = "About this Site" + url = "about.html" + weight = 100 + diff --git a/content/_index.md b/content/_index.md new file mode 100644 index 0000000000000000000000000000000000000000..12ae0d23b8c328e1997ddc8e4cdafe192a8cbc59 --- /dev/null +++ b/content/_index.md @@ -0,0 +1,21 @@ ++++ +title = "GIMP Development" +date = "2022-07-19" +description = "Online Resources for GIMP Developers" +url = "index.html" +author = "The GIMP Development Team" ++++ + +This site tries to provide useful information for GIMP developers. +No matter if you are into [plug-in development](plug-in.html) +or want to dive into the +[internals of the GIMP core](/api/2.0/app/app-hierarchy-part.html), +you should find your way from here. + +If you're looking for the main GIMP website you should visit +[www.gimp.org](https://www.gimp.org). + +The GIMP source code is versioned with git. You +can [browse the source](https://gitlab.gnome.org/GNOME/gimp/) +online. + diff --git a/api/2.0/libtest/test.txt b/content/api/2.0/libtest/test.txt similarity index 100% rename from api/2.0/libtest/test.txt rename to content/api/2.0/libtest/test.txt diff --git a/content/core_developers/_index.html b/content/core_developers/_index.html new file mode 100644 index 0000000000000000000000000000000000000000..92af60317953d9d7320bde1e489aac327a37c3ca --- /dev/null +++ b/content/core_developers/_index.html @@ -0,0 +1,7 @@ +--- +title: "Core Development" +date: 2022-07-24T10:46:15-0500 +author: "pat the wise and wonderful" +--- + +This is a holding page for the _section _"Core Development". diff --git a/content/core_developers/flood_algorithm.md b/content/core_developers/flood_algorithm.md new file mode 100644 index 0000000000000000000000000000000000000000..71ee61730368cf6de38b07e34822dbbae0188c98 --- /dev/null +++ b/content/core_developers/flood_algorithm.md @@ -0,0 +1,324 @@ +--- +Author: "Ell" +Date: 2021-01-18 +--- + +# Flood Algorithm + +## Abstract + +The flood operation eliminates "holes" -- darker areas surrounded by lighter areas -- in single-component (grayscale) images. +It is particularly useful for eliminating such holes from selections; see GIMP bug [https://bugzilla.gnome.org/show_bug.cgi?id=761060 #761060] +for more details. + +The conceptual model considers the input image as the height-map of a hilly +terrain. After heavy rain completely floods the terrain, the remaining +water form lakes in its depressions. + +``` + _______ + /.\ /\_____________ + ____________/...\ /..\ Water /..\ + /....\ /.....\/....\__ /....\____ + /......\____/....Ground.....\___/......\ /\ + __/........................................\/..\_ +``` + +Figure: A depiction of a one-dimensional flood. + +Valleys correspond to "holes" in the input image, filled with "water" according to their surrounding. + +The result of the flood operation is the height-map of the terrain after the +flood, taking both ground- and water-level into account. + +More formally, the flood operation assigns to each pixel the minimum of the +maximal input-image values along all paths from the pixel to the "outside". +That is, the output value ''o(x)'' at pixel 'x' is given by + +``` +[[File:Flood Algorithm - Formula 1.gif|center]] +``` + +where ''P(x)'' is the set of all paths from ''x'' to the outside, and ''i(y)'' is +the value of the input image at pixel ''y''. + +## Algorithm + +In accord with the conceptual flood model, we refer to the values of the +input image as the "ground level", and to the values of the output image as +the "water level"; these values range from 0 to 1, and are considered to +be 0 outside the bounds of the image. Note not to confuse "water level" +with "water depth"; we use the term "water level" simply to refer to the +elevation of either the ground or the water at a certain point. + +Our starting point is modeling the problem as a cellular automaton. The +state of each cell (pixel) is its current water level, which is initially 1 +everywhere inside the image. The water level at each cell is updated +according to the rule + +``` +[[File:Flood Algorithm - Formula 2.gif|center]] +``` + +where ''w_{n}(x)'' is the water level at pixel ''x'' on generation ''n'', ''g(x)'' is +the ground level at ''x'', and ''N(x)'' is the set of (orthogonal) neighbors of +''x'', including itself. In other words, the new water level at each pixel is +the maximum of its ground level, and the minimum of its own water level, and +that of its neighbors. This automaton converges to the output of the operation. + +The automaton converges after, at most, ''n'' generations, where ''n'' is the +number of pixels in the image. Therefore, a naive implementation, where +at most ''O(n)'' cells are processed on each generation, has a worst-case +time complexity of ''O(n2)''. By making a few observations, we can do +better, at least in the most common cases. + +First, note that the final state doesn't depend on the order of the +individual steps. That is, we don't actually have to update the water level +an entire generation at a time, but rather we can apply the transformation +rule to any pixel, at any time, arbitrarily, until convergence. +Furthermore, we don't even have to consider all the neighbors of a pixel +each time we apply the rule: as long as we make sure to never increase the +water level of a pixel, i.e., as long as we consider the pixel's own water +level as part of the minimum term, we can take a different subset of the +neighbors into account each time. + +Second, using the above observation, note that we can solve a one- +dimensional automaton (i.e., compute its final state) in linear time, using +two passes: On the first pass, we iterate over the pixels left-to-right, +applying the transformation rule while considering only the left neighbor of +each pixel (using the water level assigned to the neighbor on the previous +iteration; recall that the water level of the left neighbor of the leftmost +pixel of the image is considered to be 0.) On the second pass, we work in +reverse -- we iterate over the pixels right-to-left, applying the rule while +considering only the right neighbors. + +``` + _________________________________________________ + /.\ /\ __ + ____ /...\ /..\ /..\ + (a) /....\ /.....\/....\__ /....\ + /......\____/...............\___/......\ /\ + __/........................................\/..\_ + ______________________________ + /.\ /\ __ + ____________/...\ /..\ /..\ + (b) /....\ /.....\/....\__ /....\ + /......\____/...............\___/......\ /\ + __/........................................\/..\_ + _______ + /.\ /\_____________ + ____________/...\ /..\ /..\ + (c) /....\ /.....\/....\__ /....\____ + /......\____/...............\___/......\ /\ + __/........................................\/..\_ +``` + +Figure: Water level of a one-dimensional automaton. (a) initially; (b) after the first pass; (c) after the second pass. + +While this technique doesn't extend directly to two dimensions, we can +leverage it by processing one-dimensional strips of pixels in batch, as +described above, instead of transforming pixels individually. + +Finally, another obvious way to speed things up is to minimize the amount of +unnecessary work we're doing. In particular, we only need to process pixels +whose neighbors' state changed. + +Taking all of the above into consideration, this is what we do: + +We maintain a queue of "segments" -- one-dimensional, contiguous, strips of +pixels -- whose water level needs to be updated, as a result of a change in +the water level of the pixels of a neighboring segment, referred to as the +"source segment". Although, for efficiency reasons, we allow segments to be +either horizontal or vertical, for simplicity, we treat all segments as +though they're horizontal, and perform the necessary coordinate-system +transformation when dealing with vertical segments, as explained later. + +Each segment is processed using the following steps: + +'''1. Vertical propagation:''' The segment's pixels are updated, using the above transformation rule, considering only the corresponding +: neighboring pixels of the source segment. During the process, we inspect which of the segment's pixels actually changed, and create a +: list of "dirty ranges" of modified pixels. We construct the ranges such that all pixels of each range have the same water level; this +: becomes important in the next step. + +``` + - - -+-----+-----+-----+-----+-----+-----+-----+- - - + Source | | | | | | | | + Segment | | | | | | | | | | | | | | | + - - -+--|--+--|--+--|--+--|--+--|--+--|--+--|--+- - - + Current | V | V | V | V | V | V | V | + Segment | | x | x | | y | z | | + - - -+-----+-----+-----+-----+-----+-----+-----+- - - + Dirty ranges |-----------| |-----|-----| + The current segment's pixels are updated + according to the neighboring pixels of the + source segment, and contiguous runs of + modified, equivalent pixels form a list of + dirty ranges. +``` + +'''2. Horizontal propagation:''' The segment's pixels are updated, considering only their left and right neighbors, using the two-pass process +: described above. Though semantically equivalent, this process slightly more intricate than the one described above, since we use the +: dirty ranges from the previous step to take a few shortcuts. + +: Recall that all pixels of a single dirty range are equal, and therefore, unless modified as part of the current pass, don't affect +: each other's state. On the other hand, all pixels outside any dirty range didn't change, and therefore, unless modified as part of the +: current pass, don't affect each other's state either. As a result, initially, only the pixels that directly neighbor a dirty range, in the +: direction of the pass, need to be updated. If the water level of such pixel changes, we need to update the following pixel, and so on. Once +: the water level of a pixel remains the same, we don't have to update the next pixel, but can rather jump directly to the pixel at the edge +: of the next dirty range, and so on. + +: For example, when scanning left-to-right, we start at the pixel directly to the right of the first (leftmost) dirty range. We apply +: the transformation rule to this pixel, and to the pixels to its right, until the water level of one of them is unaffected. At this point, we +: jump directly to the pixel to the right of the next dirty range. + +``` + - -+---+---+---+---+---+---+---+---+---+---+---+- - + | | | | 1 | 2 |(3)| | | 4 |(5)| | + - -+---+---+---+---+---+---+---+---+---+---+---+- - + |-------| |---| + Pixel traversal order on a left-to-right + pass. Traversal starts to the right of + the first dirty range, at pixel ''1''. + Pixel ''(3)'' is unaffected, and so we jump + directly to the right of the second dirty + range. +``` + +Of course, when scanning right-to-left, it all reverses, and we start to the left of the last (rightmost) dirty range, etc. + +During each pass, we extend the dirty ranges, in the direction of the scan, to include the newly modified pixels. Note that, while scanning +a sequence of pixels next to one of the dirty ranges, we may reach the edge of the next range. In such case, we keep scanning the pixels of +the second range, but we don't extend the previous range any further, so that the two ranges meet, but don't overlap. + +``` + - -+---+---+---+---+---+---+---+---+---+---+---+- - + | | | | 1 | 2 |(3)| | | 4 | 5 | 6 | + - -+---+---+---+---+---+---+---+---+---+---+---+- - + Original |-------| |---| |---| + Extended |---------------| |-------|-------| + The dirty ranges are extended, in the + direction of the scan, to include the + newly modified pixels. The scan can + "leak" into existing ranges (notice the + third range in the illustration), in which + case the previous range is only extended + as far as the leaked-into range. +``` + +: Note that the rightmost and leftmost ranges may be extended past the bounds of the segment, during the left-to-right and right-to-left +: passes, respectively (recall that a segment doesn't necessarily span an entire row.) + +: Also note that, if a dirty range is extended, or if its existing pixels are modified, during the first, left-to-right, pass, then it's possible +: that its water level will not be uniform come the second, right-to-left, pass; this seems to break our assumption about the state of the +: dirty ranges, which allowed us to take the shortcut described above. +: This shortcut is still valid on the second pass, though. It turns out that we only need the ranges to meet a weaker condition -- it's enough +: for the water level of the pixels of each dirty range to be monotonically decreasing in the direction of the scan (right-to-left, +: in our case). This condition is still met at the end of the first pass. + +: One final detail: each dirty range has an associated ''modified'' flag, which is initially cleared. If, during the above process, the range is +: extended, or its existing pixels are modified, then its ''modified'' flag is set. This flag is used by the next step. + +'''3. Distribution:''' The changes to the current segment's water level may affect the two neighboring rows. For each dirty range, we push two new +: segments into the queue -- one for each neighboring row -- using the current row as their source segment. + +: There's one exception to this, however: if a dirty range hasn't been modified during the horizontal propagation step, i.e., if its +: ''modified'' flag is clear, then it necessarily doesn't affect the neighboring pixels of the source segment. Hence, in this case, we can +: avoid pushing a corresponding segment for the row of the source segment. + +``` + +---+---+---+---+ . . . +---+---+ . . + Source | | | | | | | | + +---+---+---+---+---+---+---+---+---+---+ . . + Current | | | | | | | | | + +---+---+---+---+---+---+---+---+---+---+ . . + | | | | | | | | | | + +---+---+---+---+ . +---+ +---+---+ . . + |---------------| |---| |-------| + Modified Modified + New segments, corresponding to the dirty + ranges, are pushed into the queue for each + of the current segment's neighboring rows. + No segments are pushed for the row of the + source segment for non-modified dirty + ranges. +``` + +: To amortize the cost of maintaining and processing multiple separate segments, dirty ranges that are separated by a small-enough gap are +: coalesced into a single range prior to this step; the gap between the ranges, if exists, becomes part of the coalesced range; the ''modified'' +: flag of the coalesced range is the logical-OR of the ''modified'' flags of the individual ranges. + +## Start and Termination + +Recall that segments are pushed into the queue as a result of a change in the water level of a neighboring segment. To kick this process off, we +pretend that the water level outside the image instantaneously dropped from 1 to 0, and push four segments, referred to as the "seed segments", +corresponding to the four edges of the image (there may, in fact, be less than four seed segments, if the image is 1- or 2-pixel wide or high.) +The source segment of the seed segments, hypothetically, lies outside the image; in particular, the water level of the neighboring pixels in the vertical +propagation step is taken to be 0 for the seed segments. + +``` + +-----------------------------------+ + | | + +---+---------------------------+---+ + | | | | + | | | | + | | | | + | | | | + | | | | + | | | | + | | | | + +---+---------------------------+---+ + | | + +-----------------------------------+ +``` + +Figure: The four seed segments -- one for each edge of the image. + +The process terminates when there are no more segments left in the queue. +At this point, the automaton has converged, and the water level corresponds to the output of the flood operation. + +## Coordinate Systems + +As mentioned above, segments can be either horizontal or vertical, but are treated internally as horizontal. Additionally, the region-of-interest +(ROI) of the operation might not span the entire image; in this case, the operation is performed on the ROI in isolation, and what we've been calling +the "image" up until now is in fact the ROI (in particular, the ground level outside the ROI is considered to be 0, even if the input image isn't +completely black outside the ROI.) + +To deal with this, we employ three coordinate systems: + +* '''Image-physical:''' This is the "real" coordinate system of the operation, used when talking to the outside world (i.e., GEGL). Its origin is at +: the top-left corner of the image, its x-axis points right, and its y-axis points down. + +* '''Image-virtual:''' This is the same as the image-physical coordinate system, except that the x- and y-coordinates are swapped when dealing +: with vertical segments. In other words, when processing a vertical segment, we pretend that image is transposed (i.e., reflected along the +: south-east diagonal). We transform to/from this coordinate system on the boundary between GEGL and the rest of the algorithm. + +* '''ROI-virtual:''' This is the same as the image-virtual coordinate system, except that its origin is translated to the top-left corner of the ROI. +: Internal coordinates, that aren't communicated to GEGL, are given in this coordinate system. + +``` + x y + +----> - - - - - - -+ +----> - - - - - - -+ +- - - - - - - - - -+ + y | | x | | | y | + | +- - - - -+ | +- - - - -+ +----> - -+ + v | | | v | | | | x | | | + ROI ROI | ROI + | | | | | | | | | v | | + +- - - - -+ +- - - - -+ +- - - - -+ + | | | | | | + +- - - - - - - - - -+ +- - - - - - - - - -+ +- - - - - - - - - -+ + (a) (b) (c) + The three coordinate systems: (a) image- + physical, (b) image-virtual (here shown + transposed), and (c) ROI-virtual. +``` + +To sum it up, internal coordinates (e.g., the y-coordinate of the current segment, or the x-coordinates of the dirty ranges) are given in the ROI- +virtual coordinate system. Coordinates of ''GeglRectangle''s (such as the ROI rectangle, or the rectangles used when reading and writing to the GEGL +buffers) are given in the image-virtual coordinate system, but are transformed to/from the image-physical coordinate system before being +passed-to/received-from GEGL. + + +[[Algorithms | Return to Index]] + + +Equations were rendered by [http://www.codecogs.com/latex/eqneditor.php Codecogs Online LaTex Equation Editor]. diff --git a/style/default.css b/content/default.css similarity index 100% rename from style/default.css rename to content/default.css diff --git a/content/gimpcon/2000/_index.md b/content/gimpcon/2000/_index.md new file mode 100644 index 0000000000000000000000000000000000000000..b5f58bb1cc32a0b3b260c9a1991a9f272e4f5852 --- /dev/null +++ b/content/gimpcon/2000/_index.md @@ -0,0 +1,28 @@ ++++ +title = "GIMP Developers Conference 2000" +author = "The GIMP Development Team" +abbrev = "GIMPCon 2000" +description = "Chaos Computer Club, Berlin" ++++ + +The first official GIMP Developers Conference took place +*June 2nd - 4th 2000* in [Berlin](https://www.berlin.de). + +The [Chaos Computer Club Berlin](http://berlin.ccc.de/) +was so kind to allow us to use their rooms for the +conference. The [Chaos Computer Club](https://www.ccc.de) +is a galactic community of human beings including +all ages, genders, races and social positions. They demand +unlimited freedom and flow of information without censorship. + +[people-small.jpg](The People at GIMPCon 2000) + +From left to right, top to bottom: Calvin, Simon, Seth, Jakub, +Lauri, Austin, Tigert, Tim, Jens, Tor, Jay, Daniel, Sven, Adam, +Mitch, Garry, Marc, Caroline, Andy, Yosh. + +We'd like to thank the [Free Software Foundation](https://www.fsf.org), +the [Chaos Computer Club](https://www.ccc.de) and +[O'Reilly Germany](https://www.oreilly.de) for their +help that made this meeting possible. + diff --git a/gimpcon/2000/people-small.jpg b/content/gimpcon/2000/people-small.jpg similarity index 100% rename from gimpcon/2000/people-small.jpg rename to content/gimpcon/2000/people-small.jpg diff --git a/gimpcon2003.xml b/content/gimpcon/2003/_index.md similarity index 83% rename from gimpcon2003.xml rename to content/gimpcon/2003/_index.md index 565e6c0f8a9a529f32a8825959346cd3235a2d5b..04651641f8555da7b00a0c32c86031da29d74f7a 100644 --- a/gimpcon2003.xml +++ b/content/gimpcon/2003/_index.md @@ -1,13 +1,7 @@ - - -]> ++++ +title = "GIMP Developers Conference 2003" ++++ - - - - GIMP Developers Conference 2003 GIMPCon 2003 Chaos Communication Camp, near Berlin diff --git a/content/gimpcon/2003/gimpcon2003-mins-1.md b/content/gimpcon/2003/gimpcon2003-mins-1.md new file mode 100644 index 0000000000000000000000000000000000000000..e9043c28c2ea94694d66e618c78367786598b073 --- /dev/null +++ b/content/gimpcon/2003/gimpcon2003-mins-1.md @@ -0,0 +1,188 @@ ++++ +title = "The First Big Serious Meeting of GIMPCon 2003" +abbrev = "First Meeting" +description = "Minutes of the first GIMPCon 2003 Meeting" +author = "The GIMP Development Team" ++++ + +August 7th 2003, around 8pm + +Discussion was led by Daniel Rogers (dsrogers) but stuff said is +for the most part anonymous. Partly because there shouldn't be any +ad hominem attacks that way, and partly because I didn't take down +any names. + +Present: Daniel Rogers (dsrogers), Raphaël Quinet, Dave Neary +(bolsh), Sven Neumann (Sven), Michael Natterer (mitch), Henrik +Brix Andersen (brix), Jakub Steiner (jimmac), Simon Budig (nomis), +Marc Lehmann, Ville Pätsi (drc), Øyvind Kolås (pippin), Calvin +Williamson (calvin), Roman Joost (romanofski). + +Absent but at camp: Maurits Rijk (Maurits), Branko Collin (bbc). + +Topic discussion, in approximate chronological order: + +* [The GIMP foundation](#the-gimp-foundation) +* [Release manager](#release-manager) +* [Decision making (or lack of it)](#decisions) +* [General stuff about CVS, Bugzilla](#general) +* [Communication](#communication) + +## The GIMP Foundation + +The idea of a foundation was proposed. Lots of ideas were thrown +about as to what kind of remit it would have. If created, the +foundation would certainly have 2 things we don't have at the +moment - a bank account people could donate to, and a focus on +marketing in the broadest sense of the word. + +Some of the issues were whether the foundation would be set up +in Europe or in the US (in the US it might make it easier to get +donations from US companies, but in Europe we're not as +litigious, so setting up would certainly cost less, but then we +probably wouldn't have NPO status in the US), whether it would +have any technical aspect (that is, would the foundation act as +a kind of steering committee for the general direction of the +GIMP?), and how, if the issue came up, we might pay someone. + +This led onto a discussion of whether the foundation would be +responsible for setting release dates, or whether we would have +a separate... + +## Release Manager + +The general consensus (more on that later) was that a release +manager is a good thing. There do seem to be a few different +ideas of what the role would entail. The general idea would be +that the release manager would be responsible for following CVS +and know at what stage a given feature is at, follow bugzilla +making sure that bugs got milestoned for some release in order +of their priority, would annoy people to get commits in before +feature freeze dates or postpone mercilessly features which are +not finished. + +It was agreed that a release schedule would be helpful to define +the perimeters of responsibility of the release manager - +basically, some way to set up large milestones to aim for with +things to go into those milestones. This release schedule would +be subject to revision, and would be no more realistic than any +other release schedule, but it would serve as a guide for +development. Dan agreed to draw up a first draft of this, and +we'll have something more concrete before the end of the +weekend. + +The questions that came up about the release manager were things +like where his authority comes from, how does he decide which +bugs are important and which features can be postponed and so +on. In other words, how do decisions get made. Is the release +manager a benevolent dictator, or does he answer to the larger +developer and user community? If so, to what extent? Is backing +out CVS commits OK, for example? + +So we started talking about how to get contentious decisions +made. + +## Decision making (or lack of it) + +Currently, there are two ways to get something done in the +GIMP. First, you can write decent code and patches for a while, +until you get CVS commit access, then you write whatever feature +you're interested in, and commit it. If no-one backs it out, +then it's in. + +Second, you can bring it up on the mailing list, or in bugzilla, +or in IRC (more on communication later), and discuss it until +there is a consensus. However, we tend to be pretty bad at +reaching consensus on anything even slightly contentious. The +important questions to be answered any time a discussion like +this comes up are what's going to be done, and who's going to do +it. + +It was agreed that beyond a certain point, there is generally +very little technical merit to these types of discussions. It +was felt that about 5 days was enough for everyone with an +opinion on a given matter to make that opinion known, and that +after that point, it would be an idea to have a summary of the +salient points and close the discussion. That means, the people +here would stop posting to the discussion. Of course, if other +people want to keep on flaming, they're free to do so, but +people will just ignore the thread. + +At this point, the summary should sum up the various points, and +finish with an answer to those two questions - what gets done, +and who's doing it. + +We may even have a bake-off system. If there are two competing +ideas for the way something should be done, currently no-one +tends to do it. Ideally, both people would do it and we pick the +best one. + +This brings up another point, though - in general, what is +authority? And in particular, at what point has someone gained +enough standing and authority to post one of these thread-ending +summaries? Some discussion is going to be had on that over the +weekend. + +## General stuff, about Bugzilla and CVS + +We talked about various ways of improving the way we use these +tools. First is whether it makes sense for us to have module +owners, and if so, who should they be? Should we use the system +of bug owners to track who is responsible for a bug at any given +time, or is the current scheme of bugs@gimp.org sufficient? Do +we need to change bugs@gimp.org to something else to avoid +confusion with the old bug reporting address? There were a few +open points in here. + +Second, we talked about pre-release branches, and whether it +would be worthwhile having a mozilla style release cycle with +feature-freezes, followed by concurrent bug-fixing before +unstable releases, freeing up the branch for bigger stuff that +people want to start committing. In general, it was felt that +there was very little to be gained from that, and the current +system of a long-lived devel branch with self-imposed feature +freezes every few weeks was a better way to go. + +We also expressed a desire to have more redundancy in the +non-technical aspects of The GIMP, things like the mailing lists +and ftp mirror lists should have more than one person with the +ability to change them so that if there's a problem, and that +person has no time to take care of it, then someone +will. Perhaps using a Debian or GNU style ticket system might +help here fro these particular tasks? In any case, everyone in a +given group should know everyone else in the group, and know +more or less that when an issue gets in, it will be handled by +at least one person. + +## Communication + +It was agreed that we need to communicate better (that's a +no-brainer, really). For a start, every developer should be +subscribed to the userlist. gimp-devel (if it doesn't disappear +altogether) would only be used for technical discussions of +implementation details - all the philosophical level discussions +of new features, ui changes, release mechanisms and so on should +be discussed on the user list. + +Basically, we're going to talk a lot more about how the +developers can interface better with the users. + +## Decisions + +Not too many of these... we will have a release manager, but we +need to define exactly what his/her remit will be. And who it +will be. We agreed that the 5 days and it's dead +rule for threads makes sense, so that will be done. + +## Future + +1. Roadmap - rough release schedule, we will have a first draft today. +2. GIMP Foundation - we need to define its responsibilities, set up election rules, and get this set up. The principle of the foundation is more or less agreed. +3. Communication +4. Release Manager - what'll he do, who'll he be. This should be short once we have discussed communication channels a bit. +5. Technie stuff - Sven and mitch are going to talk to us about the re-organisation of the code, GObjectification of everything, and other stuff. Daniel and Calvin are going to talk to us about GEGL and how they feel The GIMP could use it. This will probably be a two-way discussion about what kind of things we expect GEGL to furnish as well. +6. GIMP tutorials - jimmac and nomis are going to do some presentations for people, which should be good. +7. Plug-in distribution - 3 years ago this was discussion, yosh has been working on something as a proof-of-concept, it would be nice to address this and get something in place soon. + +Written by Dave Neary + diff --git a/content/gimpcon/2003/gimpcon2003-mins-2.md b/content/gimpcon/2003/gimpcon2003-mins-2.md new file mode 100644 index 0000000000000000000000000000000000000000..47f55ec37e236682f332e92b3b2afd66e351c4d4 --- /dev/null +++ b/content/gimpcon/2003/gimpcon2003-mins-2.md @@ -0,0 +1,295 @@ ++++ +title = "The Second Big Serious Meeting of GIMPCon2003" +abbrev = "Second Meeting" +description = "Minutes of the second GIMPCon 2003 Meeting" +author = "The GIMP Development Team" ++++ + +August 8th 2003, around 8pm + +Discussion was led by Daniel Rogers (dsrogers) but stuff said is +for the most part anonymous. Partly because there shouldn't be any +ad hominem attacks that way, and partly because I didn't take down +any names. + +Present: Daniel Rogers (dsrogers), Raphaël Quinet, Dave Neary +(bolsh), Sven Neumann (Sven), Michael Natterer (mitch), Henrik +Brix Andersen (brix), Jakub Steiner (jimmac), Simon Budig (nomis), +Marc Lehmann, Ville Pätsi (drc), Øyvind Kolås (pippin), Calvin +Williamson (calvin), Roman Joost (romanofski), Maurits Rijk +(Maurits), Branko Collin (bbc). + +Topic discussion, in approximate chronological order: + +* Features required for 2.0 +* Documentation +* Web-site +* Roadmap +* Bugs +* Task List +* GIMP Foundation +* Release manager + +## Features required for 2.0 + +There was quite a lot of talk on what was required for a 2.0 +release. It was agreed that a pre-release should have feature +complete versions of everything going into 2.0, for obvious +reasons. These can be somewhat buggy, but they should at least +support what is supported in the 1.2 equivalents. + +The major features or API changes which it was agreed are +necessary are: + + +1. Complete path tool (nomis) +2. Remove libgck (Sven and mitch) +Finish the text tool (Sven) +Documentation (more on this later) +Web-site (again, more on this later) +Some libgimp changes which need to be made now so that +we can havebinary compatibility across a 2.2 release + + + + + +
+Documentation + + +We felt that with pre-releases, the documentation will become +more complete. There should, however, be an effort to actively +get people writing docs. The main requirement, then, for 2.0 +pre-releases will be to have a working help framework, so that +when people hit F1 for help, they at least get a message saying +This help item does not exist yet.If you would like to +help write it, contact docs@gimp.org or some such. + + +That email address doesn't exist (yet). People interested in +helping with the documentation should have a look at the +Wiki. + + + +If documentation is going to be released as a separate package, +as now seems likely, then we will need to define the interface +between the core and the help pages reasonably quickly. The +general idea is to more or less hard-code tagnames for a +particular help topic, and get the core and help using the same +tags, and agreeing on how they be communicated. This will +presumably require a considerable amount of communication with +the help team. + +We also need to have the docs browsable online so that if people +want to browse them they can. + + +
+ +
+Web-site + + +The new site should switch over to www.gimp.org soon. There will +obviously be quite a bit of pain involved as content gets added +and we get lots of your website sucks type +feedback, but this will only befor the short term. We should +switch to mmaybe as the main site before 2.0pre1. It was +suggested to do it even earlier than that, in the region of 2 to +3 weeks time. + +It was also discussed whether it was a good idea to have a +separate coordinator for the website. + + +
+ +
+Roadmap + + +As an approximate set of ideals, it was agreed that we want +this: 2.0pre1 very soon, 2.0 soon, 2.2 next year, and GEGL +integration the end of next Summer. + +More specifically, the near-term release schedule that we agreed +was reasonable is this: + +1 or 2 developer releases (one now, more or less, and another +one in another 2 weeks). 6 weeks time (end of September 2003): +First pre-release of 2.0, including the features mentioned +above, and any other minor features that people code in the +meantime (hint, hint). Roughly 3 months later: 2.0 + +It was more or less agreed that 3 to 4 weeks was a nice +turnaround time for pre-releases, so that would imply between 4 +and 6 (inclusive) pre-releases before 2.0. + +The reason for not having a pre-release straight away was +mentioned above: to be feature complete, some features need a +little more than 2 weeks work, and people have real lives. So 6 +weeks was felt to be a reasonable amount of time to have the +path tool and the help browser in place. + + +
+ +
+Bugs + + +The developer release will also be a prelude to a bug week. We +would like people (that's you, in particular) to actively work +on bugzilla clean-up for 2.0 - bugs need to be prioritized, +unconfirmed bugs need confirming and milestoning (and if you're +feeling really helpful, fixing). The idea would more or less be +that the 2.0 milestone will be locked down for anything other +than serious bugs after this bug week, so if there are bugs that +are annoying you a lot, this is your chance to get them +considered and worked on for the 2.0 releases. + +Just to spell that out - at the end of the bug week, any bugs +reported against The GIMP in CVS will be milestoned for 2.0.x, +or even 2.2, unless they are considered blockers for the +release. If we want to get a 2.0 release soon, we need to get +lots of testing done, and lots of bugfixing done, but we also +need to choose what to do and what not to do. We felt this was a +reasonable compromise. + +It was also re-discussed whether it would make sense to have +module owners. The conclusion was that for certain components, +it makes sense to have a smaller group of people getting the bug +reports and having responsibility for them. This would be done +via mail aliases for the group of people guiding the component, +in a similar way to that which is used for (say) gtktreeview in +gtk+. + +The module owner group wouldn't have to be technical, and we +should be actively recruiting people to do this kind of work and +leave more time for programmers to program. + +This leads us on to... + + +
+ +
+Task list + + +There are lots of non-technical jobs that need doing around the +gimp-docs, website, bugzilla triage, internationalisation, +etc. Often it is quite difficult to know what needs doing, and +who to contact about getting it done. We need a list of +bite-sized tasks that people can do, including the kinds of +tasks that only take a few hours a week to do, but are ongoing +tasks. + +We used to have a TODO, and we could use that system again, if +someone were maintaining it. That could come under the remit of +the release manager to some extent, but since the mainenance of +the TODO list is mostly a non-technical task, anyone could do it +(in fact, as an example of a task, Maintaining the TODO +list would go in the TODO list). + +We might do this through Bugzilla using a keyword to allow +getting at the list easily, which would imply getting more +people looking at bugzilla regularly. Then again, if there were +a link to a bugzilla query on the webpage marked GIMP +TODO list we could get that for free. + + +
+ +
+GIMP Foundation + + +Basically, we're agreed this is a good idea to have some kind of +public face people and companies can contribute to. There is no +problem with having 2 foundations, one in Europe and one in the +US. It was more or less agreed that assigning copyright to the +foundation isn't going to happen soon (for a start, so many +plug-in authors have gone their merry way and are almost +unfindable) This may hapen in the future, but most people felt +that it would not be something they'd be happy doing personally. + +Other people said they would prefer to assign copyright to an +organism under the jurisdiction of European law rather than +under US jurisdiction. + +So, to sum up, there's no reason not to have one of +these. Daniel Rogers has agreed to do the necessary paperwork +and set up the foundation and the bank account for donations in +the US. Pretty quickly after getting that up and going, we will +need to get a board of directors and a set of by-laws. We know +lots of people who can help with this (in particular, the GNOME +foundation and the FSF). + +If someone wants to set up an equivalent in Europe, we're all +ears. Currently no-one has said they'll do it, so it's an open +point. To start, the foundation will only be a board an a bank +account - in the future, we could expand its responsibilities to +promotional work, a single point where people could go to get +speakers, a group that does press releases and so on. It was +agreed that at least in the short term it is undesirable to have +the foundation have actual control of source code, just in case +the foundation then gets sued. + +In brief, it's being set up with a very narrow remit, with the +possibility to expand later if it is felt that there is a need. + + +
+ +
+Release manager + + +The responsibilities are: + + +Follow CVS so that he can write release notes, and knows at +any given time who is working on what, and at what stage it +is + + +Follow bugzilla closely + + +Make releases regularly, according to the roadmap (or make +sure releases get made) + + +Update the roadmap to reflect reality + + +Write release notes for the releases (keep NEWS up to date) + + +Generally annoy people sending mails to the mailing lists and +sending content to the website to explain the state of play +and get people to work on stuff. + + + +Dave Neary (me) agreed to do this. He already regrets it. + +That's it folks - today, Sven and mitch are going to talk to us +about the major changes in the codebase and the general utility +stuff which exists now which has been written from scratch, +Calvin and Daniel are going to talk about GEGL and how we can +use it, and work towards having a GEGL that we can use in a +year. I'm going to lead a discussion on communication in the +GIMP, and how to maybe make it easier for people to contribute, +and jimmac is going to demonstrate what a power user really is. + +Goodbye from everyone at camp. As usual, comments are welcome on +all this stuff. While on a philosophical level, we are agreed on +the direction things should take, all the details are open to +discussion, if there's any reason to change them. + +Written by Dave Neary + diff --git a/gimpcon2003-mins-3.xml b/content/gimpcon/2003/gimpcon2003-mins-3.md similarity index 97% rename from gimpcon2003-mins-3.xml rename to content/gimpcon/2003/gimpcon2003-mins-3.md index b5ff41926c336fc92c7b493a2acabf639f205ce1..b1b3da95bd2a49866aea6d6caf43f66bcf070839 100644 --- a/gimpcon2003-mins-3.xml +++ b/content/gimpcon/2003/gimpcon2003-mins-3.md @@ -1,10 +1,7 @@ - - ++++ +author = "The GIMP Development Team" ++++ - - - The Third Big Serious Meeting of GIMPCon 2003 Third Meeting Minutes of the third GIMPCon 2003 Meeting diff --git a/gimpcon2003-mins.xml b/content/gimpcon/2003/gimpcon2003-mins.md similarity index 91% rename from gimpcon2003-mins.xml rename to content/gimpcon/2003/gimpcon2003-mins.md index 91cd87e4119d01658b38e7ce5e3f134174d72783..f1c68eb467ba872533fc810f824a7426221f1733 100644 --- a/gimpcon2003-mins.xml +++ b/content/gimpcon/2003/gimpcon2003-mins.md @@ -1,14 +1,7 @@ - - - - -]> ++++ +author = "The GIMP Development Team" ++++ - - - Minutes of The GIMP Developers Conference 2003 Minutes Minutes of the GIMPCon 2003 Meetings diff --git a/gimpcon/2003/people-small.png b/content/gimpcon/2003/people-small.png similarity index 100% rename from gimpcon/2003/people-small.png rename to content/gimpcon/2003/people-small.png diff --git a/gimpcon/2003/people.png b/content/gimpcon/2003/people.png similarity index 100% rename from gimpcon/2003/people.png rename to content/gimpcon/2003/people.png diff --git a/gimpcon/2004/Dave_Neary.jpg b/content/gimpcon/2004/Dave_Neary.jpg similarity index 100% rename from gimpcon/2004/Dave_Neary.jpg rename to content/gimpcon/2004/Dave_Neary.jpg diff --git a/gimpcon/2004/Oyvind_Kolas.png b/content/gimpcon/2004/Oyvind_Kolas.png similarity index 100% rename from gimpcon/2004/Oyvind_Kolas.png rename to content/gimpcon/2004/Oyvind_Kolas.png diff --git a/gimpcon2004.xml b/content/gimpcon/2004/_index.md similarity index 88% rename from gimpcon2004.xml rename to content/gimpcon/2004/_index.md index 1a3432b47f059f2db898ac7062504bcc61704f2d..0142cb75dd4dc0234e95f6aa9c07714fd7f56eef 100644 --- a/gimpcon2004.xml +++ b/content/gimpcon/2004/_index.md @@ -1,27 +1,17 @@ - - ++++ +title = "GIMP Developers Conference 2004" +abbrev = "GIMPCon 2004" +description = "GUADEC, Kristiansand" +author = "The GIMP Development Team" ++++ - +The GIMP Developers Conference 2004 was held as a sub-event + of GUADEC 5 in +Kristiansand, Norway, on the 28th, 29th and 30th of June. - - GIMP Developers Conference 2004 - GIMPCon 2004 - GUADEC, Kristiansand - +## GIMP related talks at GUADEC - - The GIMP Developers Conference 2004 was held as a sub-event - of GUADEC 5 in - Kristiansand, Norway, on the 28th, 29th and 30th of June. - - -
- GIMP related talks at GUADEC - - Programming a GIMP Plug-in — Dave Neary - @@ -300,26 +290,7 @@ much, much more! - - - - - - The main GUADEC - website - - - Getting - there - - - - Accommodation - - - -
-
+* The main GUADEC website +* Getting there +* Accommodation diff --git a/gimpcon/2004/gnu-head-sm.jpg b/content/gimpcon/2004/gnu-head-sm.jpg similarity index 100% rename from gimpcon/2004/gnu-head-sm.jpg rename to content/gimpcon/2004/gnu-head-sm.jpg diff --git a/gimpcon/2004/mac_gimp_logo4.png b/content/gimpcon/2004/mac_gimp_logo4.png similarity index 100% rename from gimpcon/2004/mac_gimp_logo4.png rename to content/gimpcon/2004/mac_gimp_logo4.png diff --git a/gimpcon/2004/macosx_screenshot1_thumb.jpg b/content/gimpcon/2004/macosx_screenshot1_thumb.jpg similarity index 100% rename from gimpcon/2004/macosx_screenshot1_thumb.jpg rename to content/gimpcon/2004/macosx_screenshot1_thumb.jpg diff --git a/gimpcon2006.xml b/content/gimpcon/2006/_index.md similarity index 99% rename from gimpcon2006.xml rename to content/gimpcon/2006/_index.md index 55fea55fbc114e38c3255bd836f79f16b02ef4fb..70e3a41b8d9c61e7ad8a3989931fa369180c1444 100644 --- a/gimpcon2006.xml +++ b/content/gimpcon/2006/_index.md @@ -1,10 +1,7 @@ - - ++++ +author = "The GIMP Development Team" ++++ - - - GIMP Developers Conference 2006 GIMPCon 2006 Libre Graphics Meeting, Lyon diff --git a/gimpcon/2006/meetings.jpg b/content/gimpcon/2006/meetings.jpg similarity index 100% rename from gimpcon/2006/meetings.jpg rename to content/gimpcon/2006/meetings.jpg diff --git a/gimpcon/2006/meetings_small.jpg b/content/gimpcon/2006/meetings_small.jpg similarity index 100% rename from gimpcon/2006/meetings_small.jpg rename to content/gimpcon/2006/meetings_small.jpg diff --git a/gimpcon/2006/people.jpg b/content/gimpcon/2006/people.jpg similarity index 100% rename from gimpcon/2006/people.jpg rename to content/gimpcon/2006/people.jpg diff --git a/gimpcon/2006/people_small.jpg b/content/gimpcon/2006/people_small.jpg similarity index 100% rename from gimpcon/2006/people_small.jpg rename to content/gimpcon/2006/people_small.jpg diff --git a/content/gimpcon/_index.md b/content/gimpcon/_index.md new file mode 100644 index 0000000000000000000000000000000000000000..8469c690138ef8463583c50f9cdec12d8592bec6 --- /dev/null +++ b/content/gimpcon/_index.md @@ -0,0 +1,19 @@ ++++ +title = "GIMP Developer Conferences" +abbrev = "Conference" +description = "Hanging out with GIMP developers." ++++ + + +The GIMP Developers Conference, also known as GIMPCon, is a +gathering of [GIMP](https://www.gimp.org) and +[GEGL](https://www.gegl.org) developers from all +over the World. This is where we get together and discuss the +future development, hack on GIMP and meet GIMP users. + +* [GIMPCon 2000](gimpcon/2000), June 2-3-4 in Berlin, Germany. +* [GIMPCon 2003](gimpcon/2003), August 7-8-9-10 in Berlin, Germany. +* [GIMPCon 2004](gimpcon/2004), June 28-29-30 in Kristiansand, Norway. +* GIMP meeting at GUADEC 2005, May 28-29-30-31 in Stuttgart, Germany. +* [GIMPCon 2006](gimpcon/2006), March 17-18-19 in Lyon, France. + diff --git a/content/homepage/_index.md b/content/homepage/_index.md new file mode 100644 index 0000000000000000000000000000000000000000..12ae0d23b8c328e1997ddc8e4cdafe192a8cbc59 --- /dev/null +++ b/content/homepage/_index.md @@ -0,0 +1,21 @@ ++++ +title = "GIMP Development" +date = "2022-07-19" +description = "Online Resources for GIMP Developers" +url = "index.html" +author = "The GIMP Development Team" ++++ + +This site tries to provide useful information for GIMP developers. +No matter if you are into [plug-in development](plug-in.html) +or want to dive into the +[internals of the GIMP core](/api/2.0/app/app-hierarchy-part.html), +you should find your way from here. + +If you're looking for the main GIMP website you should visit +[www.gimp.org](https://www.gimp.org). + +The GIMP source code is versioned with git. You +can [browse the source](https://gitlab.gnome.org/GNOME/gimp/) +online. + diff --git a/content/homepage/about.md b/content/homepage/about.md new file mode 100644 index 0000000000000000000000000000000000000000..6da9a09ecd00042236ba0c50dee17d053f1fb6e3 --- /dev/null +++ b/content/homepage/about.md @@ -0,0 +1,18 @@ ++++ +title = "About this Site" +description = "About this Site." +date = "2022-07-19" +author = "The GIMP Development Team" +url = "about.html" ++++ + +The look of this site was borrowed from +[www.gimp.org](http://www.gimp.org/). +Under the hood it is based on +[DocBook Website](http://docbook.sourceforge.net/projects/website/). +If you are curious, have a look at the [Markdown source](about.md) +of the page you are reading. + +If you want to help us with developer.gimp.org, clone the +repository `gimp-web-devel` from [git](git). + diff --git a/content/homepage/bugs.md b/content/homepage/bugs.md new file mode 100644 index 0000000000000000000000000000000000000000..c7f8d20256e8080855b7206801586e1bece2a488 --- /dev/null +++ b/content/homepage/bugs.md @@ -0,0 +1,28 @@ ++++ +title = "Bug Tracking System" +description = "Bugs, bugs, bugs" +date = "2022-07-19" +abbrev = "Gitlab" +url = "bugs.html" ++++ + +The GIMP project uses Gitlab's +[issues](https://gitlab.gnome.org/GNOME/gimp/-/issues), +to coordinate bug reports. Gitlab is also used for enhancement requests +and the preferred way to submit patches for the GIMP is make a +[merge request](https://gitlab.gnome.org/GNOME/gimp/-/merge_requests). + +On [www.gimp.org](https://www.gimp.org) you can find a document describing +[HOW TO Report GIMP Bugs](https://www.gimp.org/bugs/howtos/bugzilla.html). +You can also find a document that describes +[How To Create and Submit a Patch](https://www.gimp.org/bugs/howtos/submit-patch.html). + +Below is a list of links to get you started with Gitlab: + +* [List of Open Bugs](https://gitlab.gnome.org/GNOME/gimp/-/issues) +* [List of Open Bugs (excluding enhancement requests)](https://gitlab.gnome.org/GNOME/gimp/-/issues/?label_name%5B%5D=1.%20Bug) +* [Tables of Open/Closed Bugs with milestone 2.10.34](https://gitlab.gnome.org/GNOME/gimp/-/milestones/20#tab-issues) +* [Tables of Open/Closed Bugs with milestone 2.99.12](https://gitlab.gnome.org/GNOME/gimp/-/milestones/19#tab-issues) +* [Issues without an associated, planned version number.](https://gitlab.gnome.org/GNOME/gimp/-/milestones/1#tab-issues) + + diff --git a/content/homepage/changelog.md b/content/homepage/changelog.md new file mode 100644 index 0000000000000000000000000000000000000000..4426537e00f3b624bd57d7b9b02814645b2f1385 --- /dev/null +++ b/content/homepage/changelog.md @@ -0,0 +1,15 @@ ++++ +title = "GIMP ChangeLog" +date = "2022-07-20" +abbrev = "ChangeLog" +description = "Keeping an eye on the development." +url = "changelog.html" ++++ + +The [GIT repository](https://gitlab.gnome.org/GNOME/gimp/commits/master) +lists all changes in detail. The list below shows the latest +commits. It is generated from the RSS feed delivered by +the [CIA](https://cia.vc/). + + + diff --git a/content/homepage/cvs.md b/content/homepage/cvs.md new file mode 100644 index 0000000000000000000000000000000000000000..fb34569d335ce233974212d74f6846140686809e --- /dev/null +++ b/content/homepage/cvs.md @@ -0,0 +1,10 @@ ++++ +title = "CVS" +date = "2022-07-19" +description = "CVS migrated to Subversion." +url = "cvs.html" ++++ + +GIMP doesn't use CVS any longer. The source code repository has been +migrated to [git](git). + diff --git a/content/homepage/faq.md b/content/homepage/faq.md new file mode 100644 index 0000000000000000000000000000000000000000..5ea8f50224162a4ba416fe6024079d916ac46a71 --- /dev/null +++ b/content/homepage/faq.md @@ -0,0 +1,433 @@ ++++ +title = "Frequently Asked Questions" +date = "2022-07-20" +abbrev = "Developer FAQ" +description = "New to GIMP Development?" +url = "faq.html" ++++ + +Below you will find a collection of frequently asked questions +regarding development of the GIMP. + +## GIMP Development + +#### Who coordinates GIMP development? + +GIMP development is coordinated by Wilber the GIMP along +with a loosely knit team of GIMP developers. The +developers can be reached through the GIMP developer +mailing list. + +#### How can I become a GIMP developer? + +If you are a developer who wants to start contributing +code to the GIMP, the best way to get to know its +structure is by fixing bugs reported in Bugzilla. Pick a +bug, perhaps ask the advice of another developer as to +whether he/she thinks it will be an easy bug or not, and +then fix it. Sounds easy, doesn't it? + +After helping with a couple of bugs, people will start to +recognize your immense talent, and you will be on your way +to becoming a GIMP hacker. Any time you feel able, you +can pick a smaller enhancement request and have a go at +implementing it. It's that easy. + +#### Where can I discuss GIMP development? + +There are several mailing +lists associated with the GIMP project. +Developments related issues can be brought up on the GIMP +Developer mailing list. + +The GIMP has its own IRC channel on GIMPNet where most of +the active developers hang out. Join us in #gimp on +irc.gimp.org. + +Every once in a while the GIMP developers get together for +a few days to throw a GIMP Developers Conference, also +referred to as GIMPCon. + +#### Where can I find documentation for the GIMP API? + +You can pass --enable-gtk-doc to the gimp +`configure` script. This requires having +gtk-doc +installed. After running make you can +find the GIMP API reference in the +`devel-docs` directory. + +Pre-generated API documentation is included in the +official GIMP tarballs. + +The API reference will normally be installed in +`PREFIX/share/gtk-doc/html`. An on +line version of the GIMP API reference can be found +here. + +#### How do I make a stack trace? + +A stack trace is a list of function calls that leads to +some point in the program. Debugging tools like gdb +can get stack traces from crashed applications so that +developers can figure out what went wrong. By including a +stack trace with your bug report, it will be much easier +for the developers to fix the reported problem. + +Information on how to make a stack trace can be found in +the document Capturing +Stack Traces. + +#### What is the best way to submit a patch? + +The best way to submit a patch is to open a bug report in +Bugzilla and attach the patch there along with a +description of what it does and why it should be applied. + +An introduction to how this is done can be found in the + +How To Create and Submit a Patch document. + +#### What is the preferred coding style used in GIMP? + +We encourage you to follow the GIMP coding style +throughout the GIMP project. For the core components +(application and libs) this coding style is enforced. The +GIMP coding style is defined as follows: + +* Function names are lowercase, words separated by underscores. +* Macros and enums are all uppercase, words separated by underscores +* Types are all words capitalized, no separators between words. +* All functions in header files need to be prototyped. +* Indentation rules are GNU coding style, in particular: + * 2 characters indentation level + * Do not use tabs (of course your editor can use tabs, but it should write them to file as 8 spaces each). + * Opening brackets are on a new line and indented one level. + * Function header have the return type on one line, the name starting in the first column of the following line. All parameters are prototyped and there's a new line for each. + +Try to make use of GLib's object system as much as +possible. Do not create wrappers around functions of +parent classes. If you end up duplicating code, try to +create a common parent class and implement the common +methods there. + +Don't include headers in headers except where unavoidable +(e.g. for deriving objects). Opaque typedefs go to +`app/base/base-types.h`, `app/core/core-types.h` etc. See +`devel-docs/includes.txt` for a +detailed description of the include policy. + +Don't use the GTK wrappers around the GLib object and +signal system. + +The above coding style, along with other useful +information, is documented in the file HACKING. + +#### How can I configure my editor for this coding style? + +Your editor will not be able to do everything for you, but +you can configure most editors so that they use two spaces +for indentation, use spaces instead of tabs, etc. + +* If you are using Emacs, you can insert the following settings into your `~/.emacs` file: + +``` +;; Merge this into your custom-set-variables section if you already have one +(custom-set-variables +;; Syntax highlighting +'(global-font-lock-mode t nil (font-lock)) +'(show-paren-mode t nil (paren)) +) +;; use UTF-8 by default +(prefer-coding-system 'mule-utf-8) +;; use the GNU style for C files, spaces instead of tabs, highlight bad spaces +(setq c-mode-common-hook '(lambda () (c-set-style "gnu") + (setq indent-tabs-mode nil) + (setq show-trailing-whitespace t))) ]]> +``` + +* If you are using Vim, you can insert the following settings into your `~/.vimrc` file: + +``` +syn on " syntax highlighting +set expandtab " use spaces instead of tabs +set shiftwidth=2 " default indentation is 2 spaces ]]> +``` + +* If you are using another editor and you know how to configure it correctly, please tell us about it on the GIMP developer mailing list so that we can update this FAQ. + +#### Who coordinates the GIMP translation efforts? + +Any help with translations is appreciated. If you want to +help, please get in contact with the people from the +GNOME +Translation Project who coordinate all translation +efforts for projects hosted in the GNOME GIT repository. + +More information about GIMP and localisation can be found +in the file README.i18n. + + +#### How can I support GIMP development? + +By using GIMP and reporting any bugs you find to +Bugzilla +you're helping a great deal. But there are other +non-technical ways of supporting the development of The +GIMP as well. + +GIMP has a web site, application documentation, lots of +tutorials, and more. Unfortunately, as GIMP develops over +time, much of this documentation needs to be re-written or +freshened up, documentation needs to be added for new +functionality, the web site needs to get a new lick of +paint and so on. + +If you're interested in helping out you should drop an +e-mail to the GIMP developer mailing list offering your +help. + +## Plug-In Development + +#### Is there a plug-in template available? + +Yes. An official GIMP plug-in template is available in +the gimp-plugin-template + git module. Snapshots are available at ftp.gimp.org. + +#### How about a Script-Fu template? + +Yes. Simon Budig has written a fill-in-the-blanks +Script-Fu template which is available here. + +#### How do I get my plug-in included in the GIMP? + +The best way to make your plug-in available to the World +is to submit it to the GIMP Plug-In +Registry. + +If you are certain that your plug-in will be useful to all +GIMP users, then you can ask the GIMP developers to +consider it for inclusion in future GIMP release. The +best way to do that is to suggest it on the GIMP developer +mailing list or to +open an enhancement request in Bugzilla. However, we would +like to limit the number of plug-ins included in the +standard distribution and encourage all users to use the +registry. + +#### How do I debug a GIMP plug-in? + +Eeek! The plug-in you're working on has a bug in it! And +the fix isn't completely obvious, so you want to use +debugger to see what is going on. But hmm, how does one +start a plug-in under a debugger if GIMP is the one who is +starting the plug-in... + +To address this issue, libgimp has some hooks controlled +by the `GIMP_PLUGIN_DEBUG` environment +variable. The idea is that you can attach a debugger to +the pid of the plug-in you want to debug. The process is +described in the file debug-plug-ins.txt. + + +#### Will the plug-in I compiled against 2.0 work with GIMP 2.2 or 2.4? + +The short answer is yes. GIMP 2.2 and 2.4 are binary +compatible with plug-ins compiled for GIMP 2.0. The API is +also backwards source compatible, so your plug-in should +also compile cleanly against GIMP 2.2 and 2.4. + +If the plug-in you compiled for 2.0 does not work with 2.2 +or 2.4, there is one change which has been made which is +not backwards compatible, since the old behaviour was +considered incorrect. If you create a temporary drawable, +using for example gimp_layer_new(), you are now required +to add it to an image before calling any functions with +the drawable as an argument. + +## GIT + +#### What should I put in the commit message when doing a git commit? + +Please put a short explanation of the change on the first line. +Then, after an empty line, you can describe the change in more +detail using as many lines as you need. Try not to exceed 72 +colums. + +If the commit fixes a bug or part of a bug please use the +bug number and description as the first line of the commit +message. It's most convenient to just copy the line from the +Bugzilla bug page. + +## GEGL + +#### What is GEGL? + +GEGL is the Generic +Graphical Library. It is supposed to replace the +handling of various image processing tasks in GIMP in +a not too distant future (planned for GIMP 2.6). + +#### What will GEGL be able to do? + +GEGL will be a general image processing library. It uses +a directed acyclic graph, a DAG, to represent image +processing operations. In the DAG, images are edges, and +operations are nodes. It takes advantage of this DAG to +minimize regions which are processed, provide efficient +caching of operations, and efficient redrawing when a +parameter of the graph changes. + +GEGL should also be independent of the data type being +processed and will be able to handle high bit depth +images, ICC profiles and parallel processing of image +tiles. + +#### What does all that gibberish mean for GIMP? + +Many highly requested features of the GIMP will be easier +to do using GEGL. Layer effects, layer groups, and +adjustment layers are quite easily represented (and +efficiently calculated) using the DAG organization of GEGL. +CMYK and high bit depth support will be easier because +GEGL does not make the same assumptions about color spaces +and data types that the GIMP does. + +The reusability of image processing operations means that +plug-ins will be able to be designed in a much more modular +way. The brush system will be able to become more +flexible, especially when filter plug-ins are able to be +used as procedural brush plug-ins. + +## Bugzilla + +#### What is Bugzilla? + +The GIMP project uses GNOME Bugzilla for +tracking of bug reports, enhancement requests etc. + +A beginners tutorial describing how to report a bug can be +found in the +How To Report GIMP Bugs document. + +An easy to use interface to reporting GIMP bugs can be +found on bugs.gimp.org. + +#### What is the meaning of the NEEDINFO status code inBugzilla? + +If the status of a bug is changed to NEEDINFO it means the +GIMP developers need more information from the bug +reporter in order to resolve the bug. + +More information about the meaning of the Bugzilla status +field codes can be found in +A Bug's Life Cycle. + +#### What is the best way to refer to a bug in Bugzilla? + +The best way to refer to a bug is bug +#nnnnn, where nnnnn is the bug number. Using +bug before the number allows Bugzilla to +link to the corresponding bug report automatically. Using +# before the number is optional for +Bugzilla but makes it easier to locate references to bug +reports in the ChangeLog or in e-mails. + +When referencing multiple bugs, it is better to be a bit +redundant by writing bug #xxxxx, bug #yyyyy and bug +#zzzzz instead of bugs #xxxxx, #yyyyy and +#zzzzz in order to allow Bugzilla to link all bugs +automatically. + +#### What is the proper way of handling duplicate bug reports? + +A bug report describing the same bug as a previous bug +report should be marked as DUPLICATE of the older one. +In some exceptional cases, it is possible to mark an old +bug report as DUPLICATE of a newer one (e.g., when the +newer bug report has a significantly better description +than the older one). + +Another exception is when the same person submits the same +bug report several times (same description): in this case, +it is better to mark the additional copies of the bug +report as INVALID in order to avoid inflating the +statistics about the number of duplicates. + +#### What is the proper way of marking a bug as RESOLVED? + +When fixing a bug, always mention the bug number in the +commit message. Once the changes are in git, paste the +relevant part of the commit message (or all of it) in the +comment field and mark the bug as RESOLVED FIXED. +These cross-references help a lot when trying to find +when a bug was fixed, its relations to other bugs, and +potential regressions. + +A bug that is fixed in git or in an unstable release +should be marked as RESOLVED FIXED. Optionally, the +reporter or someone other than the one who fixed the bug +can mark it as VERIFIED after some testing. When the fix +is part of a stable release, it can be marked as CLOSED. + +This is explained further in A +Bug's Life Cycle except for the difference between +stable and unstable releases. + +## Miscellaneous + +#### Where can I learn more about the GObject system used by GIMP? + +The +GObject +documentation has a +nice tutorial that you might want to have a look at. + +#### Where can I learn more about color spaces etc? + +Charles Poynton has collected a set of Frequently +Asked Questions about Color. + +#### Where can I learn more about image manipulation algorithms? + +A good source of information is the +comp.graphics.algorithms list of Frequently +Asked Questions. + +#### Is there a GIMP user FAQ available? + +There is no user FAQ available at the moment. However +there has been discussions about creating one. If you +would like to help with this please drop a mail on the +GIMP developer mailing +list. + +#### How can I contribute to this FAQ? + +If you would like to contribute to this FAQ, send an +e-mail to the GIMP developer [mailing list](lists) with the +exact text you think should be included (both question and +answer). + +With your help this FAQ will grow and become more useful. + diff --git a/content/homepage/git.md b/content/homepage/git.md new file mode 100644 index 0000000000000000000000000000000000000000..7a8834e661ca4079d8ee391ac31a59eaea103cd5 --- /dev/null +++ b/content/homepage/git.md @@ -0,0 +1,30 @@ ++++ +title = "Git" +date = "2022-07-20" +abbrev = "Git" +description = "Living on the bleeding edge" +url = "git.html" ++++ + +The GIMP source code lives in the `gimp` repository on the +[GNOME git server](https://gitlab.gnome.org). +For more information on the GNOME git solution, go +[here](https://live.gnome.org/Git). + +The GNOME git server hosts a couple of GIMP related repositories: + +| Module | Description | +|---|---| +| [babl](https://gitlab.gnome.org/GNOME/gimp) | Pixel format conversion library | +| [gegl](https://gitlab.gnome.org/GNOME/gegl) | Generic Graphical Library | +| [gimp](https://gitlab.gnome.org/GNOME/gimp) | GIMP and the standard set of plug-ins | +| [gimp-data-extras](https://gitlab.gnome.org/Archive/gimp-data-extras) | GIMP Data files such as brushes, gradients, patterns and the like | +| [gimp-gap](https://gitlab.gnome.org/GNOME/gimp-gap) | GIMP Animation Package, a set of plug-ins that provide video editing functionality | +| [gimp-help](https://gitlab.gnome.org/GNOME/gimp-help) | GIMP User Manual | +| [gimp-perl](https://gitlab.gnome.org/GNOME/gimp-perl) | GIMP Perl bindings and a bunch of nice gimp-perl scripts | +| [gimp-plugin-template](https://gitlab.gnome.org/Archive/gimp-plugin-template) | GIMP Plug-In Template, a starting ground for plug-in developers, currently in need of updating with regards to the use of GEGL. | +| [gimp-plugins-unstable](https://gitlab.gnome.org/Archive/gimp-plugins-unstable) | GIMP plug-ins from the past, a collection of unstable and unmaintained plug-ins | +| [gimp-ruby](https://gitlab.gnome.org/GNOME/gimp-ruby) | GIMP Ruby-based scripting plug-in | +| [gimp-tiny-fu](https://gitlab.gnome.org/GNOME/gimp-tiny-fu) | GIMP Tiny-Fu, a drop-in replacement for Script-Fu | +| [gimp-web](https://gitlab.gnome.org/Infrastructure/gimp-web) | The GIMP web site, available at [www.gimp.org](https://www.gimp.org) | +| [gimp-web-devel](https://gitlab.gnome.org/Infrastructure/gimp-web-devel) | The source of the pages you are reading right now | diff --git a/content/homepage/lists.md b/content/homepage/lists.md new file mode 100644 index 0000000000000000000000000000000000000000..81f8687e628de69dd8373e9e90355085bc662f88 --- /dev/null +++ b/content/homepage/lists.md @@ -0,0 +1,10 @@ ++++ +title = "Mailing Lists" +description = "The finest spam in town" +date = "2022-07-20" +url = "lists.html" ++++ + +There are several mailing-lists related to GIMP and +[www.gimp.org lists them all](https://www.gimp.org/mail_lists.html). + diff --git a/content/homepage/plug-in-template.md b/content/homepage/plug-in-template.md new file mode 100644 index 0000000000000000000000000000000000000000..d2afcc0f425deac0c270af7e1304257c8149257a --- /dev/null +++ b/content/homepage/plug-in-template.md @@ -0,0 +1,23 @@ ++++ +title = "GIMP Plug-In Template" +abbrev = "Plug-In Template" +description = "Don't start from scratch" +date = "2022-07-20" +url = "plug-in-template.html" ++++ + +The GIMP Plug-In Template is an empty GIMP Plug-In that does +nothing. It also has a GUI that allows to control how it achieves +this task. But best of all, it comes with a complete setup for +[autoconf](https://www.gnu.org/software/autoconf/), +[automake](https://www.gnu.org/software/automake/), +internationalisation and all these things you never wanted to know +about. + +Thanks to the GIMP Plug-In Template you don't need to worry about +all these things. Just download the tarball, add some magic image +manipulation routines and voilà, your own GIMP plug-in. + +Grab the latest release from +[ftp.gimp.org/pub/gimp/plugin-template/](ftp://ftp.gimp.org/pub/gimp/plugin-template/). + diff --git a/content/homepage/plug-ins.md b/content/homepage/plug-ins.md new file mode 100644 index 0000000000000000000000000000000000000000..603a85dbc98d3648ee2d6eb916d04a02fe4373fa --- /dev/null +++ b/content/homepage/plug-ins.md @@ -0,0 +1,15 @@ ++++ +title = "Plug-In Development" +description = "Writing GIMP plug-ins" +date = "2022-07-20" ++++ + +* [Writing a GIMP Plug-In Part I](writing-a-plug-in/1) +* [Writing a GIMP Plug-In Part II](writing-a-plug-in/2) +* [Writing a GIMP Plug-In Part III](writing-a-plug-in/3) + +Make good use of the [GIMP 2.0 API reference](api/2.0), +and you can also have a look at a talk about +[GIMP plug-in programming](http://www.home.unix-ag.org/simon/gimp/guadec2002/gimp-plugin/html) +that Simon gave at GUADEC in Sevilla. + diff --git a/content/homepage/screenshots.md b/content/homepage/screenshots.md new file mode 100644 index 0000000000000000000000000000000000000000..533fc74ae51e0c714bbec431cd7a5619d5a90080 --- /dev/null +++ b/content/homepage/screenshots.md @@ -0,0 +1,52 @@ ++++ +title = "Screenshots" +description = "What everyone is after..." +url = "screenshots.html" ++++ + +Here are a few screenshots of the development version. More should +be added... + + + + + + + + +No image opened + + + +This screenshot shows a GNOME desktop and GIMP 2.5 right after +startup with no image loaded yet. + + + + + + + + + +Print dialog + + + +The Print plug-in has been further improved for GIMP 2.5. + + + + + + + + + +Curves dialog + + + +These screenshots illustrate changes to the Curves dialog for the +upcoming GIMP 2.6 release. + diff --git a/standards.xml b/content/homepage/standards.md similarity index 90% rename from standards.xml rename to content/homepage/standards.md index c02857a92fcbac49b1154d062606b70f5960be60..530eebe7590fc30b727d34a32394de615d516ede 100644 --- a/standards.xml +++ b/content/homepage/standards.md @@ -1,23 +1,17 @@ - - - - - - - GIMP and Standards - Standards - Standards GIMP conforms to - - - - GIMP is supposed to integrate well into your workflow. Thus is - needs to interoperate with other applications and your desktop. - Standards are there to make this happen and so we try to follow - established (and sometimes even proposed) standards. Below you - will find a list with links to specifications that a GIMP - developer may find useful. - ++++ +title = "GIMP and Standards" +date = "2022-07-20" +abbrev = "Standards" +description = "Standards GIMP conforms to" +url = "standards.html" ++++ + +GIMP is supposed to integrate well into your workflow. Thus is +needs to interoperate with other applications and your desktop. +Standards are there to make this happen and so we try to follow +established (and sometimes even proposed) standards. Below you +will find a list with links to specifications that a GIMP +developer may find useful. Image File Formats @@ -27,10 +21,8 @@ Extensible Markup Language (XML) - Describes the XML markup language, used to store the menu layout, the startup tips, help indices and other things. - @@ -39,10 +31,8 @@ Graphics Interchange Format - Describes the GIF file format, used in the GIF plug-in. GIF is bad, don't use it. - @@ -51,9 +41,7 @@ JPEG (Joint Photographic Experts Group) - Describes the JPEG JFIF file format, used in the JPEG plug-in. - @@ -62,11 +50,9 @@ JNG (JPEG Network Graphics) Format - GIMP doesn't use this format yet but it would be nice to extend the MNG plug-in to use it and to add a dedicated JNG plug-in. - @@ -75,9 +61,7 @@ MNG (Multiple-image Network Graphics) Format - Describes the MNG file format, used in the MNG plug-in. - @@ -86,11 +70,9 @@ Portable Network Graphics (PNG) - Describes the PNG file format, used in the PNG plug-in. GIMP also reads patterns in the PNG file format and it stores thumbnails as PNG images. - @@ -99,11 +81,9 @@ Scalable Vector Graphics (SVG) 1.1 - Describes the SVG file format, used in the SVG plug-in. GIMP uses SVG for import and export of paths and it also loads gradients from SVG files. - @@ -112,11 +92,9 @@ TIFF 6.0 - Describes the TIFF file format, used in the TIFF plug-in. See also the Unofficial TIFF Home Page. - @@ -125,10 +103,8 @@ Extensible Metadata Platform (XMP) - Describes XMP, a labeling technology that allows to embed data about a file, known as metadata, into the file itself. - @@ -137,10 +113,8 @@ Digital Negative (DNG) - Specifies DNG, a format, proposed by Adobe, aiming to become a standard for storing raw data from digital cameras. - @@ -155,10 +129,8 @@ sRGB Color Space - Describes sRGB, a color space proposed as a standard default color space for the Internet and other interested vendors. - @@ -167,12 +139,10 @@ ICC Specification - Specifies the profile format defined by the International Color Consortium (ICC). The intent of this format is to provide a cross-platform device profile format that can be used to translate color data between device colorspaces. - @@ -181,10 +151,8 @@ ICC Profiles In X Specification - This is a specification for associating ICC color profiles with X screens. GIMP 2.4 implements this proposed standard. - @@ -198,12 +166,10 @@ Desktop Entry Specification - This document describes desktop entries: files describing information about an application such as the name, icon, and description. GIMP installs such a .desktop file. - @@ -212,12 +178,10 @@ Desktop Message Bus - D-Bus is a message bus for the desktop. If available, GIMP uses it to detect if another GIMP instance is already running. In the future, GIMP might make even more use of D-Bus. - @@ -226,10 +190,8 @@ File URI Specification - Specifies how URIs for normal UNIX filenames (file: URIs) are interpreted and created. This functionality is provided by GLib, - @@ -238,10 +200,8 @@ GNOME Human Interface Guidelines - We don't follow this spec to the word but we try to adopt as much of these guidelines as makes sense. - @@ -250,10 +210,8 @@ Recent File Storage Specification - Provides a standard mechanism for storing a list of recently used files. Supported since GIMP version 2.1.6. - @@ -262,11 +220,9 @@ Shared MIME Database - The shared MIME database contains common MIME types, descriptions, and rules for determining the types of files. GIMP file plug-ins should use the MIME types and descriptions defined here. - @@ -275,11 +231,9 @@ Startup Notification - Specifies a mechanism allowing a desktop environment to track application startup to provide user feedback. GTK+ provides support for this protocol. - @@ -288,13 +242,11 @@ Thumbnail Managing Standard - Deals with the permanent storage of previews for file content. In particular, it tries to define a general and widely accepted standard for this task. GIMP 2.0 implements this standard and dropped support for the old-fashioned .xvpics. - @@ -309,10 +261,8 @@ Clipboards - Not a formal specification, but explains the consensus of the Qt and GTK+ developers on how the X clipboard works. - @@ -321,12 +271,10 @@ Clipboard Manager - The Clipboard Manager specification describes how applications can actively store the contents of the clipboard when the application is quit. This requires that a compliant clipboard manager is running. - @@ -335,10 +283,8 @@ Drag-and-Drop Protocol for the X Window System - XDND defines a standard for drag and drop on X11. It is implemented by GTK+. - @@ -347,11 +293,9 @@ Direct Save Protocol for the X Window System - XDS defines an extension to XDND that allow users to save a file by simply dragging it to a file manager window. GIMP 2.4 supports this protocol. - @@ -360,10 +304,8 @@ Extended Window Manager Hints - The Window Manager Specification is meant to unify the GNOME and KDE window manager hint conventions. - @@ -372,12 +314,10 @@ Inter-Client Communication Conventions Manual (ICCCM) - This spec defines the interaction between X11 clients. In particular it talks about selections, cut buffers, window and session management, manipulation of shared resources and device color characterization. - @@ -386,12 +326,10 @@ XSETTINGS - The XSETTINGS protocol provides a mechanism for applications written with different toolkits to share simple configuration settings such as double-click-times and background colors. GTK+ hides this from us. - @@ -405,11 +343,9 @@ GIMP Hackordnung - The last section from the file HACKING as found in the GIMP source tree explains how the GIMP source code should be formatted. - @@ -418,11 +354,9 @@ GNU coding standards - A guide to writing portable, robust and reliable programs. Also defines the GNU coding style. - @@ -431,9 +365,7 @@ ISO/IEC 9899 - ISO 9899 is the international standard for the C programming language. - diff --git a/images/developer-barbg.png b/content/images/developer-barbg.png similarity index 100% rename from images/developer-barbg.png rename to content/images/developer-barbg.png diff --git a/images/developer-left.png b/content/images/developer-left.png similarity index 100% rename from images/developer-left.png rename to content/images/developer-left.png diff --git a/images/developer-right.png b/content/images/developer-right.png similarity index 100% rename from images/developer-right.png rename to content/images/developer-right.png diff --git a/images/shadow.gif b/content/images/shadow.gif similarity index 100% rename from images/shadow.gif rename to content/images/shadow.gif diff --git a/images/shadow.png b/content/images/shadow.png similarity index 100% rename from images/shadow.png rename to content/images/shadow.png diff --git a/images/wilber-icon.png b/content/images/wilber-icon.png similarity index 100% rename from images/wilber-icon.png rename to content/images/wilber-icon.png diff --git a/images/wilber.png b/content/images/wilber.png similarity index 100% rename from images/wilber.png rename to content/images/wilber.png diff --git a/layout.xml b/content/layout.xml similarity index 100% rename from layout.xml rename to content/layout.xml diff --git a/content/resource_developers/_index.html b/content/resource_developers/_index.html new file mode 100644 index 0000000000000000000000000000000000000000..3a5c9cf1a8ebe93ebe154e3cef00c6ad0a9a840c --- /dev/null +++ b/content/resource_developers/_index.html @@ -0,0 +1,7 @@ +--- +title: "Resource Development" +date: 2022-07-24T10:46:15-0500 +author: "pat the wise and wonderful" +--- + +This is a holding page for the _section _"Resource Development". diff --git a/screenshots/Makefile b/content/screenshots/Makefile similarity index 100% rename from screenshots/Makefile rename to content/screenshots/Makefile diff --git a/content/screenshots/gimp-curves-thumb.png b/content/screenshots/gimp-curves-thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..6941a85a8b5d972e1934443d1b0259bb5ef61eee Binary files /dev/null and b/content/screenshots/gimp-curves-thumb.png differ diff --git a/screenshots/gimp-curves.png b/content/screenshots/gimp-curves.png similarity index 100% rename from screenshots/gimp-curves.png rename to content/screenshots/gimp-curves.png diff --git a/content/screenshots/gimp-empty-thumb.png b/content/screenshots/gimp-empty-thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..f4eda5d9d5e902f860a574716c20a6e38046d0c5 Binary files /dev/null and b/content/screenshots/gimp-empty-thumb.png differ diff --git a/screenshots/gimp-empty.png b/content/screenshots/gimp-empty.png similarity index 100% rename from screenshots/gimp-empty.png rename to content/screenshots/gimp-empty.png diff --git a/screenshots/gimp-osx.jpeg b/content/screenshots/gimp-osx.jpeg similarity index 100% rename from screenshots/gimp-osx.jpeg rename to content/screenshots/gimp-osx.jpeg diff --git a/content/screenshots/gimp-print-thumb.png b/content/screenshots/gimp-print-thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..5c78799412a1f495de6621ea7ca57bcaed844af1 Binary files /dev/null and b/content/screenshots/gimp-print-thumb.png differ diff --git a/screenshots/gimp-print.png b/content/screenshots/gimp-print.png similarity index 100% rename from screenshots/gimp-print.png rename to content/screenshots/gimp-print.png diff --git a/content/writing-a-plug-in/1.md b/content/writing-a-plug-in/1.md new file mode 100644 index 0000000000000000000000000000000000000000..e8581c1747df54dbc398826df3b41b192223c342 --- /dev/null +++ b/content/writing-a-plug-in/1.md @@ -0,0 +1,298 @@ ++++ +title = "How to write a GIMP plug-in" +abbrev = "Writing A Plug-In" +description = "Write your own" +author = "Dave Neary" ++++ + +Written By [Dave Neary](mailto:bolsh@NOSPAM.gimp.org). + +In this article, I present GIMP plug-ins basics and introduce the +libgimp API. I will also show how to use the PDB to make our +plug-in available to other script authors. + +## Introduction + +New developers are often intimidated by The GIMP size and its +reputation. They think that writing a plug-in would be a +difficult task. The goal of these articles is to dumb this +feeling down, by showing how easily one can make a C plug-in. + +In this part, I present a plug-in's basic elements. We will see +how to install a plug-in and how to get data from an image and +directly manipulate it. + +## Architecture + +architecture.png +[architecture.png](Architecture) + +The GIMP script interface is centered on the Procedural database +(PDB). At startup, The GIMP looks into a predefined set of +places for scripts and plug-ins, and asks each new script to +identify itself. + +The plug-in declares itself to the PDB at that time, and passes +informations like the position it wishes to get in the menu +hierarchy, input parameters, and output parameters. + +When a script or a plug-in wants to use our plug-in, it gets +through the PDB, which manages communicating parameters in one +direction and the other in a transparent way. + +Internal functions that wish to get exposed to plug-ins have to +be packaged first in the core, that will register them in the +PDB, and secondly in the libgimp that will allow the function to +be called as a normal one. + +This was the introduction - now, we will look closer at our +first plug-in, a "Hello, world!". + +## Compiling the plug-in + +To be able to compile simple plug-ins for The GIMP, one needs +libgimp headers, as well as an associated utility named +gimptool. + +With that utility, one can install a plug-in either in a private +directory (`~/.gimp-2.0/plug-ins`), or in the global plug-in +directory. + +Syntax is + +``` +gimptool-2.0 --install plugin.c or gimptool-2.0 --install-admin plugin.c +``` + +This utility, with other options, can also be used to install +scripts, or uninstall plug-ins. + +## Behaviour + +A GIMP plug-in can typically behave three different ways. It can +take image data, modify it, and send back the modified image, +like edge detection. It can generate an image and send it back, +like some script-fus, or file reading plug-ins like jpeg. Or it +can get an image, and process it without modifying its data, +like a file saver plug-in. + +## Essentials + +``` +#include +``` + +This header makes all basic plug-in elements available to us. + +``` +GimpPlugInInfo PLUG_IN_INFO = { + init, + quit, + query, + run +}; +``` + +This structure has to have that name. It contains four pointers +to functions, which will be called at set times of the plug-in +life. init and quit are optional, and thus can hold NULL values, +but the last two functions, query and run, are mandatory. + +The init() function is called each time The GIMP starts up. This +function is not typically used. Some plug-ins use it to make a +secondary search that is not done by the core. This function is +not used by any standard GIMP plug-in, but could be useful for +example for a plug-in that would like to register some procedure +conditionally on some files presence. + +The quit() function is not used much either. It is called when +The GIMP is about to be closed, to allow it to free some +resources. It is used in the script-fu plug-in. + +The query() function is called the first time the plug-in is +present, and then each time the plug-in changes. + +The run() function is the plug-in's centrepiece. It is called +when the plug-in is asked to run. It gets the plug-in name (as a +plug-in can register several procedures), input parameters, and +a pointer to output parameters, then determines if it is +launched in a interactive way or by a script, and does all the +plug-in processing. Its prototype is + +``` +void run (const gchar *name, + gint nparams, + const GimpParam *param, + gint *nreturn_vals, + GimpParam **return_vals); +``` + +## MAIN () + +MAIN is a C macro that holds a bit of dark magic to initialise +arguments. It also calls the appropriate PLUG_IN_INFO function +depending on the timing. Your plug-in needs it. + +## The query() function + +`query()` deals with the procedure registration and input +arguments definition. These informations are saved to speed up +startup time, and refreshed only when the plug-in is modified. + +For our "Hello, world!" plug-in, the query function will look +like this: + +``` +static void +query (void) +{ + static GimpParamDef args[] = { + { + GIMP_PDB_INT32, + "run-mode", + "Run mode" + }, + { + GIMP_PDB_IMAGE, + "image", + "Input image" + }, + { + GIMP_PDB_DRAWABLE, + "drawable", + "Input drawable" + } + }; + + gimp_install_procedure ( + "plug-in-hello", + "Hello, world!", + "Displays \"Hello, world!\" in a dialog", + "David Neary", + "Copyright David Neary", + "2004", + "_Hello world...", + "RGB*, GRAY*", + GIMP_PLUGIN, + G_N_ELEMENTS (args), 0, + args, NULL); + + gimp_plugin_menu_register ("plug-in-hello", + "/Filters/Misc"); +} +``` + +GimpParamDef contains three things - the parameter type, its +name, and a string describing the parameter. + +`gimp_install_procedure` declares the procedure name, some +description and help strings, menu path where the plug-in should +sit, image types handled by the plug-in, and at the end, input +and output parameters number, as well as the parameters +descriptors. + +"`RGB*, GRAY*`" declares the image types handled. It can be `RGB`, +`INDEXED` or `GRAY`, with or without Alpha. So "`RGB*, GRAY*`" +describes RGB, `RGBA`, `GRAY` or `GRAY` image type. + +GIMP_PLUGIN declares this procedure to be external, and not to +be executed in The GIMP core. + +By adding a stub run function now, we can check that our plug-in +has all the essential elements, and test that it registers +itself in the PDB with the "`Xtns->Plug-in Details`" plug-in. + +plug-in-details.png +plug-in-details-small.png +Plug-in details + +plug-in-menu.png +plug-in-menu-small.png +Our plug-in is in the menus + +## The run() function + +The other required function for PLUG_IN_INFO is run. The core of +the plug-in stands there. + +Output values (return_vals in the prototype) must have at least +one value associated - the plug-in status. Typically, this +parameter will hold "`GIMP_PDB_SUCCESS`". + +## Run-modes + +One can run a plug-in in several different ways, it can be run +from a GIMP menu if The GIMP is run interactively, or from a +script or a batch, or from the "Filters->Repeat Last" shortcut. + +The "`run_mode`" input parameter can hold one of these values: +"`GIMP_RUN_INTERACTIVE`", "`GIMP_RUN_NONINTERACTIVE`" or +"`GIMP_RUN_WITH_LAST_VALS`". + +"`GIMP_RUN_INTERACTIVE`" is typically the only case where one +creates an options dialog. Otherwise, one directly calls the +processing with values from input parameters or from memory. + +For our test plug-in, we will simply display a dialog containing +a "Hello, world!" message. Thankfully, this is really easy with +GTK+. Our run function could be: + +``` +static void +run (const gchar *name, + gint nparams, + const GimpParam *param, + gint *nreturn_vals, + GimpParam **return_vals) +{ +static GimpParam values[1]; +GimpPDBStatusType status = GIMP_PDB_SUCCESS; +GimpRunMode run_mode; + +/* Setting mandatory output values */ +*nreturn_vals = 1; +*return_vals = values; + +values[0].type = GIMP_PDB_STATUS; +values[0].data.d_status = status; + +/* Getting run_mode - we won't display a dialog if + * we are in NONINTERACTIVE mode */ +run_mode = param[0].data.d_int32; + +if (run_mode != GIMP_RUN_NONINTERACTIVE) + g_message("Hello, world!\n"); +} +``` + +Now, when we run our plug-in, there is action: + +[hello.png](Hello, world!) + +Have a look at the full [hello.c](hello.c) plug-in code. + +## Next part + +In next part +we will go on, making a more useful plug-in that will get its +hands on image data. We will see how to use The GIMP image +architecture to make the plug-in perform better, processing the +image tile by tile. + + + + + + + + +Creative Commons License + + + + +This work is licensed under a Creative +Commons Attribution-NonCommercial-ShareAlike 2.5 +License. + diff --git a/content/writing-a-plug-in/2.md b/content/writing-a-plug-in/2.md new file mode 100644 index 0000000000000000000000000000000000000000..6d959bcef8fa4b713cd9364d6e58d80b6afeb344 --- /dev/null +++ b/content/writing-a-plug-in/2.md @@ -0,0 +1,472 @@ ++++ +title = "How to write a GIMP plug-in, part II" +abbrev = "Part II" +description = "Write your own" +author = "Dave Neary" ++++ + +Written By [Dave Neary](mailto:bolsh@NOSPAM.gimp.org). + +In the [first part](writing-a-plug-in/1), +I presented essential elements to build a plug-in +interface with The GIMP. Now we will produce a simple but useful +algorithm that we could use in our plug-in. + +## Introduction + +The algorithm we are going to implement is a simple blur. It is +included in The GIMP as "Filters->Blur->Blur" with default +parameters. + +That algorithm is very simple. Each pixel in our image is +replaced by a mean value of its neighbours. For example, if we +look at the simplest case where the neighbourhood is 3x3 (see +figure 1), in that case the center value will be replaced with +5, the mean of the 9 numbers in its neighbourhood. + +With this method, edge differences are splatted, giving a +blurred result. One can choose another radius, using a `(2r + 1) +x (2r + 1)` matrix. + +## Image structure + +Last month, we wrote a run() function that did nothing useful. +Let's look again at run() prototype: + +``` +static void run (const gchar *name, + gint nparams, + const GimpParam *param, + gint *nreturn_vals, + GimpParam **return_vals); +``` + +We saw that for a filter (i.e. a plug-in that modifies the +image), the first three input parameters were the run mode, an +identifier for the image, and another one for the active +drawable (layer or mask). + +A GIMP image is a structure that contains, among others, guides, +layers, layer masks, and any data associated to the image. The +word "drawable" is often used in GIMP internal structures. A +"drawable" is an object where you can get, and sometimes modify, +raw data. So : layers, layer masks, selections are all +"drawables". + +GimpImage.png +GimpImage-small.png +Drawables + +## Accessing the data + +To get a GimpDrawable from its identifier, we need the +`gimp_drawable_get()` function: + +``` +GimpDrawable *gimp_drawable_get (gint32 drawable_id); +``` + +From this structure, one can access drawable data through a +GimpPixelRgn structure, and one can check the drawable type +(RGB, gray level). The full listing of functions available for a +GimpDrawable can be found in +the API. + +Two very important functions for plug-ins are +gimp_drawable_mask_bounds() and gimp_pixel_rgn_init(). The first +gives the active selection limits on the drawable, and the +second initialises the GimpPixelRgn we will use to access the +data. + +As soon as we have a well initialised GimpPixelRgn, we can +access the image data in several different ways, by pixel, by +rectangle, by row or by column. The best method will depend on +the algorithm one plans to use. Moreover, The GIMP uses a +tile-based architecture, and loading or unloading data is +expensive, so we should not use it more than necessary. + + + +Tiles + +The main functions to get and set image data are: + +``` +void gimp_pixel_rgn_get_pixel (GimpPixelRgn *pr, + guchar *buf, + gint x, + gint y); +void gimp_pixel_rgn_get_row (GimpPixelRgn *pr, + guchar *buf, + gint x, + gint y, + gint width); +void gimp_pixel_rgn_get_col (GimpPixelRgn *pr, + guchar *buf, + gint x, + gint y, + gint height); +void gimp_pixel_rgn_get_rect (GimpPixelRgn *pr, + guchar *buf, + gint x, + gint y, + gint width, + gint height); +void gimp_pixel_rgn_set_pixel (GimpPixelRgn *pr, + const guchar *buf, + gint x, + gint y); +void gimp_pixel_rgn_set_row (GimpPixelRgn *pr, + const guchar *buf, + gint x, + gint y, + gint width); +void gimp_pixel_rgn_set_col (GimpPixelRgn *pr, + const guchar *buf, + gint x, + gint y, + gint height); +void gimp_pixel_rgn_set_rect (GimpPixelRgn *pr, + const guchar *buf, + gint x, + gint y, + gint width, + gint height); +``` + +There is also another way to access image data (it's even used +more often), that allows to manage data at the tile level. We +will look at it in detail later. + +## Updating the image + +At last, a plug-in that has modified a drawable data must flush +it to send data to the core, and to tell the application that +the display must be updated. This is done with the following +function: + +``` +gimp_displays_flush (); +gimp_drawable_detach (drawable); +``` + +## Implementing blur() + +To be able to try out several different processing methods, we +will delegate the job to a blur() function. Our run() is below. + +``` +static void +run (const gchar *name, + gint nparams, + const GimpParam *param, + gint *nreturn_vals, + GimpParam **return_vals) +{ + static GimpParam values[1]; + GimpPDBStatusType status = GIMP_PDB_SUCCESS; + GimpRunMode run_mode; + GimpDrawable *drawable; + + /* Setting mandatory output values */ + *nreturn_vals = 1; + *return_vals = values; + + values[0].type = GIMP_PDB_STATUS; + values[0].data.d_status = status; + + /* Getting run_mode - we won't display a dialog if + * we are in NONINTERACTIVE mode */ + run_mode = param[0].data.d_int32; + + /* Get the specified drawable */ + drawable = gimp_drawable_get (param[2].data.d_drawable); + + gimp_progress_init ("My Blur..."); + + /* Let's time blur + * + * GTimer timer = g_timer_new time (); + */ + + blur (drawable); + + /* g_print ("blur() took %g seconds.\n", g_timer_elapsed (timer)); + * g_timer_destroy (timer); + */ + + gimp_displays_flush (); + gimp_drawable_detach (drawable); +} +``` + +There are a few lines here that need to be explained a bit more. +The call to gimp_progress_init() initialises a progress +measurement for our plug-in. Later, if we call +gimp_progress_update(double percent), the percentage given as an +input parameter will be shown graphically. The run_mode tells us +whether the plug-in was launched in a way such as we can display +a graphical interface or not. Possible values are +GIMP_RUN_INTERACTIVE, GIMP_RUN_NONINTERACTIVE or +GIMP_RUN_WITH_LAST_VALS, which mean the plug-in was executed +from The GIMP, from a script, or from the "Repeat last filter" +menu entry. + +Regarding the blur algorithm itself, the first version using +gimp_pixel_rgn_(get|set)_pixel() is found below. Some functions +in it have not been explained yet. + +`gimp_drawable_mask_bounds()` allows calculation of the filter's +effect limits, excluding any region that is not in the active +selection. Limiting the processing this way allows an important +performance improvement. + +`gimp_pixel_rgn_init()` takes as input parameters the drawable, +its limits for the processing, and two booleans that +significantly modify the behaviour of the resulting GimpPixelRgn. +The first one tells that "set" operations must be done on shadow +tiles, in order to leave original data as is until +gimp_drawable_merge_shadow() is called, when all modified data +will be merged. The second one tells that modified tiles should +be tagged "dirty" and sent to the core to be merged. Most of the +time, to read data, one uses FALSE and FALSE for these two +parameters, and to write data, one uses TRUE and TRUE. Other +combinations are possible but seldom used. + +``` +static void +blur (GimpDrawable *drawable) +{ + gint i, j, k, channels; + gint x1, y1, x2, y2; + GimpPixelRgn rgn_in, rgn_out; + guchar output[4]; + + /* Gets upper left and lower right coordinates, + * and layers number in the image */ + gimp_drawable_mask_bounds (drawable->drawable_id, + &x1, &y1, + &x2, &y2); + channels = gimp_drawable_bpp (drawable->drawable_id); + + /* Initialises two PixelRgns, one to read original data, + * and the other to write output data. That second one will + * be merged at the end by the call to + * gimp_drawable_merge_shadow() */ + gimp_pixel_rgn_init (&rgn_in, + drawable, + x1, y1, + x2 - x1, y2 - y1, + FALSE, FALSE); + gimp_pixel_rgn_init (&rgn_out, + drawable, + x1, y1, + x2 - x1, y2 - y1, + TRUE, TRUE); + + for (i = x1; i < x2; i++) + { + for (j = y1; j < y2; j++) + { + guchar pixel[9][4]; + + /* Get nine pixels */ + gimp_pixel_rgn_get_pixel (&rgn_in, + pixel[0], + MAX (i - 1, x1), + MAX (j - 1, y1)); + gimp_pixel_rgn_get_pixel (&rgn_in, + pixel[1], + MAX (i - 1, x1), + j); + gimp_pixel_rgn_get_pixel (&rgn_in, + pixel[2], + MAX (i - 1, x1), + MIN (j + 1, y2 - 1)); + + gimp_pixel_rgn_get_pixel (&rgn_in, + pixel[3], + i, + MAX (j - 1, y1)); + gimp_pixel_rgn_get_pixel (&rgn_in, + pixel[4], + i, + j); + gimp_pixel_rgn_get_pixel (&rgn_in, + pixel[5], + i, + MIN (j + 1, y2 - 1)); + + gimp_pixel_rgn_get_pixel (&rgn_in, + pixel[6], + MIN (i + 1, x2 - 1), + MAX (j - 1, y1)); + gimp_pixel_rgn_get_pixel (&rgn_in, + pixel[7], + MIN (i + 1, x2 - 1), + j); + gimp_pixel_rgn_get_pixel (&rgn_in, + pixel[8], + MIN (i + 1, x2 - 1), + MIN (j + 1, y2 - 1)); + + /* For each layer, compute the average of the + * nine */ + for (k = 0; k < channels; k++) + { + int tmp, sum = 0; + for (tmp = 0; tmp < 9; tmp++) + sum += pixel[tmp][k]; + output[k] = sum / 9; + } + + gimp_pixel_rgn_set_pixel (&rgn_out, + output, + i, j); + } + + if (i % 10 == 0) + gimp_progress_update ((gdouble) (i - x1) / (gdouble) (x2 - x1)); + } + + /* Update the modified region */ + gimp_drawable_flush (drawable); + gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); + gimp_drawable_update (drawable->drawable_id, + x1, y1, + x2 - x1, y2 - y1); +} +``` + +## Row processing + +Our function has a bug drawback: performance. On a 300x300 +selection, with the timing code uncommented, blur() took 12 +minutes on my K6-2 350MHz, well loaded with other stuff. To +compare, on the same selection, Gaussian blur took 3 seconds. + +If we modify our function to rather use +gimp_pixel_rgn_(get|set)_row() the result is far better. We +reduce the timing for the 300x300 selection from 760 seconds to +6 seconds. blur() V2 is below: + +``` +static void +blur (GimpDrawable *drawable) +{ + gint i, j, k, channels; + gint x1, y1, x2, y2; + GimpPixelRgn rgn_in, rgn_out; + guchar *row1, *row2, *row3; + guchar *outrow; + + gimp_drawable_mask_bounds (drawable->drawable_id, + &x1, &y1, + &x2, &y2); + channels = gimp_drawable_bpp (drawable->drawable_id); + + gimp_pixel_rgn_init (&rgn_in, + drawable, + x1, y1, + x2 - x1, y2 - y1, + FALSE, FALSE); + gimp_pixel_rgn_init (&rgn_out, + drawable, + x1, y1, + x2 - x1, y2 - y1, + TRUE, TRUE); + + /* Initialise enough memory for row1, row2, row3, outrow */ + row1 = g_new (guchar, channels * (x2 - x1)); + row2 = g_new (guchar, channels * (x2 - x1)); + row3 = g_new (guchar, channels * (x2 - x1)); + outrow = g_new (guchar, channels * (x2 - x1)); + + for (i = y1; i < y2; i++) + { + /* Get row i-1, i, i+1 */ + gimp_pixel_rgn_get_row (&rgn_in, + row1, + x1, MAX (y1, i - 1), + x2 - x1); + gimp_pixel_rgn_get_row (&rgn_in, + row2, + x1, i, + x2 - x1); + gimp_pixel_rgn_get_row (&rgn_in, + row3, + x1, MIN (y2 - 1, i + 1), + x2 - x1); + + for (j = x1; j < x2; j++) + { + /* For each layer, compute the average of the nine + * pixels */ + for (k = 0; k < channels; k++) + { + int sum = 0; + sum = row1[channels * MAX ((j - 1 - x1), 0) + k] + + row1[channels * (j - x1) + k] + + row1[channels * MIN ((j + 1 - x1), x2 - x1 - 1) + k] + + row2[channels * MAX ((j - 1 - x1), 0) + k] + + row2[channels * (j - x1) + k] + + row2[channels * MIN ((j + 1 - x1), x2 - x1 - 1) + k] + + row3[channels * MAX ((j - 1 - x1), 0) + k] + + row3[channels * (j - x1) + k] + + row3[channels * MIN ((j + 1 - x1), x2 - x1 - 1) + k]; + outrow[channels * (j - x1) + k] = sum / 9; + } + + } + + gimp_pixel_rgn_set_row (&rgn_out, + outrow, + x1, i, + x2 - x1); + + if (i % 10 == 0) + gimp_progress_update ((gdouble) (i - y1) / (gdouble) (y2 - y1)); + } + + g_free (row1); + g_free (row2); + g_free (row3); + g_free (outrow); + + gimp_drawable_flush (drawable); + gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); + gimp_drawable_update (drawable->drawable_id, + x1, y1, + x2 - x1, y2 - y1); +} +``` + +Have a look at the [slow](myblur1.c) or [fast](myblur2.c) blur complete code. + +## Next part + +In [next part](writing-a-plug-in/3), +we will see how to process the image tile by tile. We will also +have a look at preferences, by modifying our algorithm so it can +take an input parameter. + + + + + + + + + +Creative Commons License + + + + +This work is licensed under a Creative +Commons Attribution-NonCommercial-ShareAlike 2.5 +License. + + diff --git a/content/writing-a-plug-in/3.md b/content/writing-a-plug-in/3.md new file mode 100644 index 0000000000000000000000000000000000000000..233d834ddc11cb21b894d2ed3d6a7725908a0f6b --- /dev/null +++ b/content/writing-a-plug-in/3.md @@ -0,0 +1,747 @@ ++++ +title = "How to write a GIMP plug-in, part III" +abbrev = "Part III" +description = "Write your own" +date = "2022-07-23" +author = "Dave Neary" ++++ + +Written By [Dave Neary](mailto:bolsh@NOSPAM.gimp.org). + +In the [second part](writing-a-plug-in/2), +I told you about manipulating image data by pixel or +row. This time, I will go farther and process data by tile, which +will improve our plug-in performance. I will also update our +algorithm to take larger radius into account, and build a +graphical interface to allow changing that parameter. + +## Introduction + +Let's have a look at our simple algorithm: for each pixel, +generate a `(2r+1)x(2r+1)` neighbourhood and for each layer, +replace the layer's pixel value with the average value in the +neighbourhood. + +It's a bit more complex than that - we have to be careful near +image borders for example, but this algorithm makes a blur +effect that is not so bad in general. + +But until now, we wrote the algorithm for a 3x3 neighbourhood. +Time has come to generalise this part and to introduce the +radius as a parameter. + +First, a word on tiles. + +## Tile management + +A tile is an image data block with a 64x64 size. Usually, tiles +are sent to the plug-in on demand one by one, by shared memory. +Of course this process needs huge resources and should be +avoided. + +Usually, one doesn't need any particular cache, each tile is +sent when one needs it and freed when one asks for another one. +Nevertheless, we can tell our plug-in to keep a tile cache to +avoid this constant round trip, by calling the function: + +``` +gimp_tile_cache_ntiles (gulong ntiles); +``` + +In the second part example, we called `gimp_pixel_rgn_get_row()` +and `gimp_pixel_rgn_set_row()` but without using any cache. + +The number of tiles in a tile row will be the layer width +divided by the tile width, plus one. So, for a layer width of +65, we will cache two tiles. As we usually also process shadow +tiles, we can double that number to compute the ideal cache size +for our plug-in. + +``` +gimp_tile_cache_ntiles (2 * (drawable->width / + gimp_tile_width () + 1)); +``` + +With the cache, our slow plug-in becomes fast. On a 300x300 +selection, our last blur took 3 seconds, but on a 2000x1500 +selection it was much slower - 142 seconds. + +Adding the above line of code, things are getting better: 11 +seconds. We still lose transition time when we reach tile +borders, we can go down to 10 seconds when multiplying by 4 +instead of 2 (meaning we cache two tiles rows), but the more +tiles we cache, the more hard disk access we make, which reduce +the time gain at a point. + +## Algorithm generalisation + +We can modify the algorithm to take a parameter into account: +radius. With a radius of 3, the neighbourhood of a pixel will be +7x7, instead of 3x3 with a radius of 1. To achieve this I modify +the previous algorithm: + +* allocate space for 2r+1 tile rows +* initialise this rows array, taking care of borders +* for each tile row + * for each pixel in the tile row + * compute the neighbourhood average, taking care of borders +* get a new tile row and cycle rows + +This algorithm is more complex than the last one, because the +average computing will be a O(r²) algorithm. + +The modified code to get this behaviour is below. Most of the +work is done in the process_row function. init_mem and shuffle +are there to keep the blur code clean and small. + +``` +static void blur (GimpDrawable *drawable); + +static void init_mem (guchar ***row, + guchar **outrow, + gint num_bytes); +static void process_row (guchar **row, + guchar *outrow, + gint x1, + gint y1, + gint width, + gint height, + gint channels, + gint i); +static void shuffle (GimpPixelRgn *rgn_in, + guchar **row, + gint x1, + gint y1, + gint width, + gint height, + gint ypos); + +/* The radius is still a constant, we'll change that when the + * graphical interface will be built. */ +static gint radius = 3; +... + +static void +blur (GimpDrawable *drawable) +{ + gint i, ii, channels; + gint x1, y1, x2, y2; + GimpPixelRgn rgn_in, rgn_out; + guchar **row; + guchar *outrow; + gint width, height; + + gimp_progress_init ("My Blur..."); + + /* Gets upper left and lower right coordinates, + * and layers number in the image */ + gimp_drawable_mask_bounds (drawable->drawable_id, + &x1, &y1, + &x2, &y2); + width = x2 - x1; + height = y2 - y1; + + channels = gimp_drawable_bpp (drawable->drawable_id); + + /* Allocate a big enough tile cache */ + gimp_tile_cache_ntiles (2 * (drawable->width / + gimp_tile_width () + 1)); + + /* Initialises two PixelRgns, one to read original data, + * and the other to write output data. That second one will + * be merged at the end by the call to + * gimp_drawable_merge_shadow() */ + gimp_pixel_rgn_init (&rgn_in, + drawable, + x1, y1, + width, height, + FALSE, FALSE); + gimp_pixel_rgn_init (&rgn_out, + drawable, + x1, y1, + width, height, + TRUE, TRUE); + + /* Allocate memory for input and output tile rows */ + init_mem (&row, &outrow, width * channels); + + for (ii = -radius; ii <= radius; ii++) + { + gimp_pixel_rgn_get_row (&rgn_in, + row[radius + ii], + x1, y1 + CLAMP (ii, 0, height - 1), + width); + } + + for (i = 0; i < height; i++) + { + /* To be done for each tile row */ + process_row (row, + outrow, + x1, y1, + width, height, + channels, + i); + gimp_pixel_rgn_set_row (&rgn_out, + outrow, + x1, i + y1, + width); + /* shift tile rows to insert the new one at the end */ + shuffle (&rgn_in, + row, + x1, y1, + width, height, + i); + if (i % 10 == 0) + gimp_progress_update ((gdouble) i / (gdouble) height); + } + + /* We could also put that in a separate function but it's + * rather simple */ + for (ii = 0; ii < 2 * radius + 1; ii++) + g_free (row[ii]); + + g_free (row); + g_free (outrow); + + /* Update the modified region */ + gimp_drawable_flush (drawable); + gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); + gimp_drawable_update (drawable->drawable_id, + x1, y1, + width, height); +} + +static void +init_mem (guchar ***row, + guchar **outrow, + gint num_bytes) +{ + gint i; + + /* Allocate enough memory for row and outrow */ + *row = g_new (char *, (2 * radius + 1)); + + for (i = -radius; i <= radius; i++) + (*row)[i + radius] = g_new (guchar, num_bytes); + + *outrow = g_new (guchar, num_bytes); +} + +static void +process_row (guchar **row, + guchar *outrow, + gint x1, + gint y1, + gint width, + gint height, + gint channels, + gint i) +{ + gint j; + + for (j = 0; j < width; j++) + { + gint k, ii, jj; + gint left = (j - radius), + right = (j + radius); + + /* For each layer, compute the average of the + * (2r+1)x(2r+1) pixels */ + for (k = 0; k < channels; k++) + { + gint sum = 0; + + for (ii = 0; ii < 2 * radius + 1; ii++) + for (jj = left; jj <= right; jj++) + sum += row[ii][channels * CLAMP (jj, 0, width - 1) + k]; + + outrow[channels * j + k] = + sum / (4 * radius * radius + 4 * radius + 1); + } + } +} + +static void +shuffle (GimpPixelRgn *rgn_in, + guchar **row, + gint x1, + gint y1, + gint width, + gint height, + gint ypos) +{ + gint i; + guchar *tmp_row; + + /* Get tile row (i + radius + 1) into row[0] */ + gimp_pixel_rgn_get_row (rgn_in, + row[0], + x1, MIN (ypos + radius + y1, y1 + height - 1), + width); + + /* Permute row[i] with row[i-1] and row[0] with row[2r] */ + tmp_row = row[0]; + for (i = 1; i < 2 * radius + 1; i++) + row[i - 1] = row[i]; + row[2 * radius] = tmp_row; +} +``` + +## Adding a graphical interface and saving parameters + +To let the user modify the radius, or let a non-interactive +script give it as a parameter, we now need to get back to our +run() function and settle some simple things. + +First we create a structure to allow saving and returning +options. Usually one does this even for plug-ins with only one +parameter. + +``` +typedef struct +{ + gint radius; +} MyBlurVals; + + +/* Set up default values for options */ +static MyBlurVals bvals = +{ + 3 /* radius */ +}; +``` + +Next, we modify the run() function so that execution modes are +taken into account. In interactive mode and repeat last filter +mode, we try to get the last values used by the gimp_get_data() +function, which takes a unique data identifier as its first +input parameter. Usually, one uses the procedure's name. + +Finally, in interactive mode, we add a few lines that will build +the graphical interface allowing options modification. + + +``` +static void +run (const gchar *name, + gint nparams, + const GimpParam *param, + gint *nreturn_vals, + GimpParam **return_vals) +{ + static GimpParam values[1]; + GimpPDBStatusType status = GIMP_PDB_SUCCESS; + GimpRunMode run_mode; + GimpDrawable *drawable; + + /* Setting mandatory output values */ + *nreturn_vals = 1; + *return_vals = values; + + values[0].type = GIMP_PDB_STATUS; + values[0].data.d_status = status; + + /* Getting run_mode - we won't display a dialog if + * we are in NONINTERACTIVE mode */ + run_mode = param[0].data.d_int32; + + /* Get the specified drawable */ + drawable = gimp_drawable_get (param[2].data.d_drawable); + + switch (run_mode) + { + case GIMP_RUN_INTERACTIVE: + /* Get options last values if needed */ + gimp_get_data ("plug-in-myblur", &bvals); + + /* Display the dialog */ + if (! blur_dialog (drawable)) + return; + break; + + case GIMP_RUN_NONINTERACTIVE: + if (nparams != 4) + status = GIMP_PDB_CALLING_ERROR; + if (status == GIMP_PDB_SUCCESS) + bvals.radius = param[3].data.d_int32; + break; + + case GIMP_RUN_WITH_LAST_VALS: + /* Get options last values if needed */ + gimp_get_data ("plug-in-myblur", &bvals); + break; + + default: + break; + } + + blur (drawable); + + gimp_displays_flush (); + gimp_drawable_detach (drawable); + + /* Finally, set options in the core */ + if (run_mode == GIMP_RUN_INTERACTIVE) + gimp_set_data ("plug-in-myblur", &bvals, sizeof (MyBlurVals)); + + return; +} +``` + +## The graphical interface + +I won't detail GTK+ programming as this is done very well in +other places. Our first try will be very simple. We will use the +utility widget of GIMP, the GimpDialog, to create a window with +a header, a numeric control of type GtkSpinButton (associated +with a GtkAdjustment) and its label, nicely framed in a +GtkFrame. + +In the following parts, in order to show how easy one can do +such things, I will add a preview in the dialog to show real +time effects of the parameters. + +Our final dialog will look like this (tree generated with +Glade): + +glade-tree.png +glade-tree-small.png +Glade tree + +In The GIMP 2.2, there is a number of widgets that come bundled +with parameters that allow a coherent behaviour, consistent with +GNOME Human Interface Guidelines. GimpPreview also appeared in +2.2. Let's make a first try without it: + +blur_dialog1.png +Blur dialog + +``` +static gboolean +blur_dialog (GimpDrawable *drawable) +{ + GtkWidget *dialog; + GtkWidget *main_vbox; + GtkWidget *main_hbox; + GtkWidget *frame; + GtkWidget *radius_label; + GtkWidget *alignment; + GtkWidget *spinbutton; + GtkObject *spinbutton_adj; + GtkWidget *frame_label; + gboolean run; + + gimp_ui_init ("myblur", FALSE); + + dialog = gimp_dialog_new ("My blur", "myblur", + NULL, 0, + gimp_standard_help_func, "plug-in-myblur", + + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, + + NULL); + + main_vbox = gtk_vbox_new (FALSE, 6); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox); + gtk_widget_show (main_vbox); + + frame = gtk_frame_new (NULL); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame), 6); + + alignment = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment); + gtk_container_add (GTK_CONTAINER (frame), alignment); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 6, 6, 6); + + main_hbox = gtk_hbox_new (FALSE, 0); + gtk_widget_show (main_hbox); + gtk_container_add (GTK_CONTAINER (alignment), main_hbox); + + radius_label = gtk_label_new_with_mnemonic ("_Radius:"); + gtk_widget_show (radius_label); + gtk_box_pack_start (GTK_BOX (main_hbox), radius_label, FALSE, FALSE, 6); + gtk_label_set_justify (GTK_LABEL (radius_label), GTK_JUSTIFY_RIGHT); + + spinbutton_adj = gtk_adjustment_new (3, 1, 16, 1, 5, 5); + spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton_adj), 1, 0); + gtk_widget_show (spinbutton); + gtk_box_pack_start (GTK_BOX (main_hbox), spinbutton, FALSE, FALSE, 6); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE); + + frame_label = gtk_label_new ("Modify radius"); + gtk_widget_show (frame_label); + gtk_frame_set_label_widget (GTK_FRAME (frame), frame_label); + gtk_label_set_use_markup (GTK_LABEL (frame_label), TRUE); + + g_signal_connect (spinbutton_adj, "value_changed", + G_CALLBACK (gimp_int_adjustment_update), + &bvals.radius); + gtk_widget_show (dialog); + + run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK); + + gtk_widget_destroy (dialog); + + return run; +} +``` + +## Adding a GimpPreview + +Adding a GimpPreview is quite easy. First we create a GtkWidget +with `gimp_drawable_preview_new()`, then we attach an invalidated +signal to it, which will call the blur function to update the +preview. We also add a second parameter to MyBlurVals to +remember the activation state of the preview. + +A method to update easily the preview is to add a preview +parameter in the blur function, and if preview is not NULL, to +take GimpPreview limits. So when we call blur from run(), we set +the preview parameter to NULL. + +To take GimpPreview limits, we use gimp_preview_get_position() +and `gimp_preview_get_size()`, so we can generate only what will +be displayed. + +To achieve this the right way we'll tune some of the code - we +don't need to update the progress bar while generating the +preview, and we should tell at GimpPixelRgn init time that the +tiles should not be sent back to the core. + +Finally, we display the updated preview with the +gimp_drawable_preview_draw_region() function. We get a dialog +box that shows us in real time the plug-in effects. Moreover, +thanks to the GIMP core, our plug-in already takes selections +into account. + + + +Blur dialog, improved + + + +Blur a selection + +Here are the two functions in their last version: + +``` +static void +blur (GimpDrawable *drawable, + GimpPreview *preview) +{ + gint i, ii, channels; + gint x1, y1, x2, y2; + GimpPixelRgn rgn_in, rgn_out; + guchar **row; + guchar *outrow; + gint width, height; + + if (!preview) + gimp_progress_init ("My Blur..."); + + /* Gets upper left and lower right coordinates, + * and layers number in the image */ + if (preview) + { + gimp_preview_get_position (preview, &x1, &y1); + gimp_preview_get_size (preview, &width, &height); + x2 = x1 + width; + y2 = y1 + height; + } + else + { + gimp_drawable_mask_bounds (drawable->drawable_id, + &x1, &y1, + &x2, &y2); + width = x2 - x1; + height = y2 - y1; + } + + channels = gimp_drawable_bpp (drawable->drawable_id); + + /* Allocate a big enough tile cache */ + gimp_tile_cache_ntiles (2 * (drawable->width / + gimp_tile_width () + 1)); + + /* Initialises two PixelRgns, one to read original data, + * and the other to write output data. That second one will + * be merged at the end by the call to + * gimp_drawable_merge_shadow() */ + gimp_pixel_rgn_init (&rgn_in, + drawable, + x1, y1, + width, height, + FALSE, FALSE); + gimp_pixel_rgn_init (&rgn_out, + drawable, + x1, y1, + width, height, + preview == NULL, TRUE); + + /* Allocate memory for input and output tile rows */ + init_mem (&row, &outrow, width * channels); + + for (ii = -bvals.radius; ii <= bvals.radius; ii++) + { + gimp_pixel_rgn_get_row (&rgn_in, + row[bvals.radius + ii], + x1, y1 + CLAMP (ii, 0, height - 1), + width); + } + + for (i = 0; i < height; i++) + { + /* To be done for each tile row */ + process_row (row, + outrow, + x1, y1, + width, height, + channels, + i); + gimp_pixel_rgn_set_row (&rgn_out, + outrow, + x1, i + y1, + width); + /* shift tile rows to insert the new one at the end */ + shuffle (&rgn_in, + row, + x1, y1, + width, height, + i); + if (i % 10 == 0 && !preview) + gimp_progress_update ((gdouble) i / (gdouble) height); + } + + for (ii = 0; ii < 2 * bvals.radius + 1; ii++) + g_free (row[ii]); + + g_free (row); + g_free (outrow); + + /* Update the modified region */ + if (preview) + { + gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview), + &rgn_out); + } + else + { + gimp_drawable_flush (drawable); + gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); + gimp_drawable_update (drawable->drawable_id, + x1, y1, + width, height); + } +} + +static gboolean +blur_dialog (GimpDrawable *drawable) +{ + GtkWidget *dialog; + GtkWidget *main_vbox; + GtkWidget *main_hbox; + GtkWidget *preview; + GtkWidget *frame; + GtkWidget *radius_label; + GtkWidget *alignment; + GtkWidget *spinbutton; + GtkObject *spinbutton_adj; + GtkWidget *frame_label; + gboolean run; + + gimp_ui_init ("myblur", FALSE); + + dialog = gimp_dialog_new ("My blur", "myblur", + NULL, 0, + gimp_standard_help_func, "plug-in-myblur", + + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, + + NULL); + + main_vbox = gtk_vbox_new (FALSE, 6); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox); + gtk_widget_show (main_vbox); + + preview = gimp_drawable_preview_new (drawable, &bvals.preview); + gtk_box_pack_start (GTK_BOX (main_vbox), preview, TRUE, TRUE, 0); + gtk_widget_show (preview); + + frame = gimp_frame_new ("Blur radius"); + gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); + gtk_widget_show (frame); + + alignment = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment); + gtk_container_add (GTK_CONTAINER (frame), alignment); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 6, 6, 6); + + main_hbox = gtk_hbox_new (FALSE, 12); + gtk_container_set_border_width (GTK_CONTAINER (main_hbox), 12); + gtk_widget_show (main_hbox); + gtk_container_add (GTK_CONTAINER (alignment), main_hbox); + + radius_label = gtk_label_new_with_mnemonic ("_Radius:"); + gtk_widget_show (radius_label); + gtk_box_pack_start (GTK_BOX (main_hbox), radius_label, FALSE, FALSE, 6); + gtk_label_set_justify (GTK_LABEL (radius_label), GTK_JUSTIFY_RIGHT); + + spinbutton = gimp_spin_button_new (&spinbutton_adj, bvals.radius, + 1, 32, 1, 1, 1, 5, 0); + gtk_box_pack_start (GTK_BOX (main_hbox), spinbutton, FALSE, FALSE, 0); + gtk_widget_show (spinbutton); + + g_signal_connect_swapped (preview, "invalidated", + G_CALLBACK (blur), + drawable); + g_signal_connect_swapped (spinbutton_adj, "value_changed", + G_CALLBACK (gimp_preview_invalidate), + preview); + + blur (drawable, GIMP_PREVIEW (preview)); + + g_signal_connect (spinbutton_adj, "value_changed", + G_CALLBACK (gimp_int_adjustment_update), + &bvals.radius); + gtk_widget_show (dialog); + + run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK); + + gtk_widget_destroy (dialog); + + return run; +} +``` + +Have a look at the tiled, +UI or +preview blur complete code. + +## Conclusion + +In these articles, we saw basic concepts for several aspects of +a GIMP plug-in. We messed with image data treatment through a +simple algorithm, and followed a path that showed us how to +avoid performance problems. Finally, we generalised the +algorithm and added parameters to it, and we used some GIMP +widgets to make a nice user interface. + +## Thanks + +Thanks to my wife Anne and to David Odin (preview master) for +helping me while I was writing this article. + + + +Creative Commons License + +This work is licensed under a Creative +Commons Attribution-NonCommercial-ShareAlike 2.5 +License. + diff --git a/cvs.xml b/cvs.xml deleted file mode 100644 index bfed2c0901accefb2cd2b812ab95fcbbd0d3bf2d..0000000000000000000000000000000000000000 --- a/cvs.xml +++ /dev/null @@ -1,19 +0,0 @@ - - -]> - - - - - CVS - CVS migrated to Subversion - - - - GIMP doesn't use CVS any longer. The source code repository has been - migrated to git. - - - diff --git a/dtd/autolayout.dtd b/dtd/autolayout.dtd deleted file mode 100644 index f01720a0d3569bc817b17d38f897d4f1573aa091..0000000000000000000000000000000000000000 --- a/dtd/autolayout.dtd +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dtd/extensions.mod b/dtd/extensions.mod deleted file mode 100644 index 2db2f5cd2d0891b5662d94bb00141a96aa953a6c..0000000000000000000000000000000000000000 --- a/dtd/extensions.mod +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - -%namespaces.mod; - - - - - -]]> - - - - - - -]]> - - - - - - - - - diff --git a/dtd/forms.mod b/dtd/forms.mod deleted file mode 100644 index ff9919a676777528634f37d7e4bb829fde924ebc..0000000000000000000000000000000000000000 --- a/dtd/forms.mod +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dtd/layout.dtd b/dtd/layout.dtd deleted file mode 100644 index 5da6d9a95ddaa3718a53f8a41ce965c01638f62d..0000000000000000000000000000000000000000 --- a/dtd/layout.dtd +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dtd/namespaces.mod b/dtd/namespaces.mod deleted file mode 100644 index 0060470311717927a10713eb757061d60733bcf0..0000000000000000000000000000000000000000 --- a/dtd/namespaces.mod +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dtd/rddl.mod b/dtd/rddl.mod deleted file mode 100644 index a58b38aba328bddf743982dddd51a9e5f19c2021..0000000000000000000000000000000000000000 --- a/dtd/rddl.mod +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/dtd/website-custom.dtd b/dtd/website-custom.dtd deleted file mode 100644 index 28a80c9d89fcf6585b7c4dc29ea46f37a854babc..0000000000000000000000000000000000000000 --- a/dtd/website-custom.dtd +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - -%extensions.mod; - - - - - -%sdocbook; - - -%website.mod; - - - diff --git a/dtd/website-full.dtd b/dtd/website-full.dtd deleted file mode 100644 index 6d155b27b0a095041d6bb242728ea77c8421f7e5..0000000000000000000000000000000000000000 --- a/dtd/website-full.dtd +++ /dev/null @@ -1,40 +0,0 @@ - - - - - -%extensions.mod; - - - -%docbook.dtd; - - - - - - -%website.mod; - - - diff --git a/dtd/website.dtd b/dtd/website.dtd deleted file mode 100644 index d5bbeca0084945a27bfbae0e7dc635e3955272b8..0000000000000000000000000000000000000000 --- a/dtd/website.dtd +++ /dev/null @@ -1,1993 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dtd/website.mod b/dtd/website.mod deleted file mode 100644 index f0999858df4ef6976cefd5bc777aeeae1fac0048..0000000000000000000000000000000000000000 --- a/dtd/website.mod +++ /dev/null @@ -1,109 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -%rddl.mod; -]]> - - -%forms.mod; -]]> - - - diff --git a/faq.xml b/faq.xml deleted file mode 100644 index 5bdc003770fc633d6f2bd98d08b14c0304904fdc..0000000000000000000000000000000000000000 --- a/faq.xml +++ /dev/null @@ -1,812 +0,0 @@ - - - -]> - - - - - Frequently Asked Questions - Developer FAQ - New to GIMP Development? - - - - Below you will find a collection of frequently asked questions - regarding development of the GIMP. - - - - - GIMP Development - - - - - Who coordinates GIMP development? - - - - - GIMP development is coordinated by Wilber the GIMP along - with a loosely knit team of GIMP developers. The - developers can be reached through the GIMP developer - mailing list. - - - - - - - - How can I become a GIMP developer? - - - - - If you are a developer who wants to start contributing - code to the GIMP, the best way to get to know its - structure is by fixing bugs reported in Bugzilla. Pick a - bug, perhaps ask the advice of another developer as to - whether he/she thinks it will be an easy bug or not, and - then fix it. Sounds easy, doesn't it? - - - After helping with a couple of bugs, people will start to - recognize your immense talent, and you will be on your way - to becoming a GIMP hacker. Any time you feel able, you - can pick a smaller enhancement request and have a go at - implementing it. It's that easy. - - - - - - - - Where can I discuss GIMP development? - - - - - There are several mailing - lists associated with the GIMP project. - Developments related issues can be brought up on the GIMP - Developer mailing list. - - - The GIMP has its own IRC channel on GIMPNet where most of - the active developers hang out. Join us in #gimp on - irc.gimp.org. - - - Every once in a while the GIMP developers get together for - a few days to throw a GIMP Developers Conference, also - referred to as GIMPCon. - - - - - - - - Where can I find documentation for the GIMP API? - - - - - You can pass --enable-gtk-doc to the gimp - configure script. This requires having - gtk-doc - installed. After running make you can - find the GIMP API reference in the - devel-docs directory. - - - Pre-generated API documentation is included in the - official GIMP tarballs. - - - The API reference will normally be installed in - PREFIX/share/gtk-doc/html. An on - line version of the GIMP API reference can be found - here. - - - - - - - - How do I make a stack trace? - - - - - A stack trace is a list of function calls that leads to - some point in the program. Debugging tools like gdb - can get stack traces from crashed applications so that - developers can figure out what went wrong. By including a - stack trace with your bug report, it will be much easier - for the developers to fix the reported problem. - - - Information on how to make a stack trace can be found in - the document Capturing - Stack Traces. - - - - - - - - What is the best way to submit a patch? - - - - - The best way to submit a patch is to open a bug report in - Bugzilla and attach the patch there along with a - description of what it does and why it should be applied. - - - An introduction to how this is done can be found in the - - How To Create and Submit a Patch document. - - - - - - - - What is the preferred coding style used in GIMP? - - - - - We encourage you to follow the GIMP coding style - throughout the GIMP project. For the core components - (application and libs) this coding style is enforced. The - GIMP coding style is defined as follows: - - - - Function names are lowercase, words separated by - underscores. - - - - - Macros and enums are all uppercase, words separated - by underscores - - - - - Types are all words capitalized, no separators - between words. - - - - - All functions in header files need to be prototyped. - - - - - Indentation rules are GNU coding style, in - particular: - - - - 2 characters indentation level - - - - - Do not use tabs (of course your editor can use - tabs, but it should write them to file as 8 - spaces each). - - - - - Opening brackets are on a new line and - indented one level. - - - - - Function header have the return type on one - line, the name starting in the first column of - the following line. All parameters are - prototyped and there's a new line for each. - - - - - - - - - Try to make use of GLib's object system as much as - possible. Do not create wrappers around functions of - parent classes. If you end up duplicating code, try to - create a common parent class and implement the common - methods there. - - - Don't include headers in headers except where unavoidable - (e.g. for deriving objects). Opaque typedefs go to - app/base/base-types.h, - app/core/core-types.h etc. See - devel-docs/includes.txt for a - detailed description of the include policy. - - - Don't use the GTK wrappers around the GLib object and - signal system. - - - The above coding style, along with other useful - information, is documented in the file HACKING. - - - - - - - - How can I configure my editor for this coding style? - - - - - Your editor will not be able to do everything for you, but - you can configure most editors so that they use two spaces - for indentation, use spaces instead of tabs, etc. - - - - - If you are using Emacs, you can insert the following - settings into your ~/.emacs file: - - - - - - If you are using Vim, you can insert the following - settings into your ~/.vimrc file: - - - - - - If you are using another editor and you know how to - configure it correctly, please tell us about it on the - GIMP developer mailing - list so that we can update this FAQ. - - - - - - - - - - Who coordinates the GIMP translation efforts? - - - - - Any help with translations is appreciated. If you want to - help, please get in contact with the people from the - GNOME - Translation Project who coordinate all translation - efforts for projects hosted in the GNOME GIT repository. - - - More information about GIMP and localisation can be found - in the file README.i18n. - - - - - - - - How can I support GIMP development? - - - - - By using GIMP and reporting any bugs you find to - Bugzilla - you're helping a great deal. But there are other - non-technical ways of supporting the development of The - GIMP as well. - - - GIMP has a web site, application documentation, lots of - tutorials, and more. Unfortunately, as GIMP develops over - time, much of this documentation needs to be re-written or - freshened up, documentation needs to be added for new - functionality, the web site needs to get a new lick of - paint and so on. - - - If you're interested in helping out you should drop an - e-mail to the GIMP developer mailing list offering your - help. - - - - - - - Plug-In Development - - - - - Is there a plug-in template available? - - - - - Yes. An official GIMP plug-in template is available in - the gimp-plugin-template - git module. Snapshots are available at ftp.gimp.org. - - - - - - - - How about a Script-Fu template? - - - - - Yes. Simon Budig has written a fill-in-the-blanks - Script-Fu template which is available here. - - - - - - - - How do I get my plug-in included in the GIMP? - - - - - The best way to make your plug-in available to the World - is to submit it to the GIMP Plug-In - Registry. - - - If you are certain that your plug-in will be useful to all - GIMP users, then you can ask the GIMP developers to - consider it for inclusion in future GIMP release. The - best way to do that is to suggest it on the GIMP developer - mailing list or to - open an enhancement request in Bugzilla. However, we would - like to limit the number of plug-ins included in the - standard distribution and encourage all users to use the - registry. - - - - - - - - How do I debug a GIMP plug-in? - - - - - Eeek! The plug-in you're working on has a bug in it! And - the fix isn't completely obvious, so you want to use - debugger to see what is going on. But hmm, how does one - start a plug-in under a debugger if GIMP is the one who is - starting the plug-in... - - - To address this issue, libgimp has some hooks controlled - by the GIMP_PLUGIN_DEBUG environment - variable. The idea is that you can attach a debugger to - the pid of the plug-in you want to debug. The process is - described in the file debug-plug-ins.txt. - - - - - - - - Will the plug-in I compiled against 2.0 work with - GIMP 2.2 or 2.4? - - - - - The short answer is yes. GIMP 2.2 and 2.4 are binary - compatible with plug-ins compiled for GIMP 2.0. The API is - also backwards source compatible, so your plug-in should - also compile cleanly against GIMP 2.2 and 2.4. - - - If the plug-in you compiled for 2.0 does not work with 2.2 - or 2.4, there is one change which has been made which is - not backwards compatible, since the old behaviour was - considered incorrect. If you create a temporary drawable, - using for example gimp_layer_new(), you are now required - to add it to an image before calling any functions with - the drawable as an argument. - - - - - - - GIT - - - - - What should I put in the commit message when doing a git commit? - - - - - Please put a short explanation of the change on the first line. - Then, after an empty line, you can describe the change in more - detail using as many lines as you need. Try not to exceed 72 - colums. - - - If the commit fixes a bug or part of a bug please use the - bug number and description as the first line of the commit - message. It's most convenient to just copy the line from the - Bugzilla bug page. - - - - - - - GEGL - - - - - What is GEGL? - - - - - GEGL is the Generic - Graphical Library. It is supposed to replace the - handling of various image processing tasks in GIMP in - a not too distant future (planned for GIMP 2.6). - - - - - - - - What will GEGL be able to do? - - - - - GEGL will be a general image processing library. It uses - a directed acyclic graph, a DAG, to represent image - processing operations. In the DAG, images are edges, and - operations are nodes. It takes advantage of this DAG to - minimize regions which are processed, provide efficient - caching of operations, and efficient redrawing when a - parameter of the graph changes. - - - GEGL should also be independent of the data type being - processed and will be able to handle high bit depth - images, ICC profiles and parallel processing of image - tiles. - - - - - - - - What does all that gibberish mean for GIMP? - - - - - Many highly requested features of the GIMP will be easier - to do using GEGL. Layer effects, layer groups, and - adjustment layers are quite easily represented (and - efficiently calculated) using the DAG organization of GEGL. - CMYK and high bit depth support will be easier because - GEGL does not make the same assumptions about color spaces - and data types that the GIMP does. - - - The reusability of image processing operations means that - plug-ins will be able to be designed in a much more modular - way. The brush system will be able to become more - flexible, especially when filter plug-ins are able to be - used as procedural brush plug-ins. - - - - - - Bugzilla - - - - - What is Bugzilla? - - - - - The GIMP project uses GNOME Bugzilla for - tracking of bug reports, enhancement requests etc. - - - A beginners tutorial describing how to report a bug can be - found in the - How To Report GIMP Bugs document. - - - An easy to use interface to reporting GIMP bugs can be - found on bugs.gimp.org. - - - - - - - - What is the meaning of the NEEDINFO status code in - Bugzilla? - - - - - If the status of a bug is changed to NEEDINFO it means the - GIMP developers need more information from the bug - reporter in order to resolve the bug. - - - More information about the meaning of the Bugzilla status - field codes can be found in - A Bug's Life Cycle. - - - - - - - - What is the best way to refer to a bug in Bugzilla? - - - - - The best way to refer to a bug is bug - #nnnnn, where nnnnn is the bug number. Using - bug before the number allows Bugzilla to - link to the corresponding bug report automatically. Using - # before the number is optional for - Bugzilla but makes it easier to locate references to bug - reports in the ChangeLog or in e-mails. - - - When referencing multiple bugs, it is better to be a bit - redundant by writing bug #xxxxx, bug #yyyyy and bug - #zzzzz instead of bugs #xxxxx, #yyyyy and - #zzzzz in order to allow Bugzilla to link all bugs - automatically. - - - - - - - - What is the proper way of handling duplicate bug reports? - - - - - A bug report describing the same bug as a previous bug - report should be marked as DUPLICATE of the older one. - In some exceptional cases, it is possible to mark an old - bug report as DUPLICATE of a newer one (e.g., when the - newer bug report has a significantly better description - than the older one). - - - Another exception is when the same person submits the same - bug report several times (same description): in this case, - it is better to mark the additional copies of the bug - report as INVALID in order to avoid inflating the - statistics about the number of duplicates. - - - - - - - - What is the proper way of marking a bug as RESOLVED? - - - - - When fixing a bug, always mention the bug number in the - commit message. Once the changes are in git, paste the - relevant part of the commit message (or all of it) in the - comment field and mark the bug as RESOLVED FIXED. - These cross-references help a lot when trying to find - when a bug was fixed, its relations to other bugs, and - potential regressions. - - - A bug that is fixed in git or in an unstable release - should be marked as RESOLVED FIXED. Optionally, the - reporter or someone other than the one who fixed the bug - can mark it as VERIFIED after some testing. When the fix - is part of a stable release, it can be marked as CLOSED. - - - This is explained further in A - Bug's Life Cycle except for the difference between - stable and unstable releases. - - - - - - - Miscellaneous - - - - - Where can I learn more about the GObject system used by - GIMP? - - - - - The - GObject - documentation has a - nice tutorial that you might want to have a look at. - - - - - - - - Where can I learn more about color spaces etc? - - - - - Charles Poynton has collected a set of Frequently - Asked Questions about Color. - - - - - - - - Where can I learn more about image manipulation - algorithms? - - - - - A good source of information is the - comp.graphics.algorithms list of Frequently - Asked Questions. - - - - - - - - Is there a GIMP user FAQ available? - - - - - There is no user FAQ available at the moment. However - there has been discussions about creating one. If you - would like to help with this please drop a mail on the - GIMP developer mailing - list. - - - - - - - - How can I contribute to this FAQ? - - - - - If you would like to contribute to this FAQ, send an - e-mail to the GIMP developer mailing list with the - exact text you think should be included (both question and - answer). - - - With your help this FAQ will grow and become more useful. - - - - - - - - - diff --git a/gimpcon.xml b/gimpcon.xml deleted file mode 100644 index fcdf91262c76130aba103c47708560d891c9fbfd..0000000000000000000000000000000000000000 --- a/gimpcon.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - -]> - - - - - GIMP Developer Conferences - Conference - Hanging out with GIMP developers - - - - The GIMP Developers Conference, also known as GIMPCon, is a - gathering of GIMP and - GEGL developers from all - over the World. This is where we get together and discuss the - future development, hack on GIMP and meet GIMP users. - - - - - - GIMPCon 2000, June - 2-3-4 in Berlin, Germany. - - - GIMPCon 2003, - August 7-8-9-10 in Berlin, Germany. - - - GIMPCon 2004, - June 28-29-30 in Kristiansand, Norway. - - - GIMP meeting at GUADEC 2005, May 28-29-30-31 in Stuttgart, Germany. - - - GIMPCon 2006, - March 17-18-19 in Lyon, France. - - - - - diff --git a/gimpcon2000.xml b/gimpcon2000.xml deleted file mode 100644 index e03fbabb9e9ae848496099e87424ed5a052bd2b6..0000000000000000000000000000000000000000 --- a/gimpcon2000.xml +++ /dev/null @@ -1,56 +0,0 @@ - - -]> - - - - - GIMP Developers Conference 2000 - GIMPCon 2000 - Chaos Computer Club, Berlin - - - - The first official GIMP Developers Conference took place - June 2nd - 4th 2000 in Berlin. - - - - The Chaos Computer Club - Berlin was so kind to allow us to use their rooms for the - conference. The Chaos Computer - Club is a galactic community of human beings including - all ages, genders, races and social positions. They demand - unlimited freedom and flow of information without censorship. - - - - - - - - - - The People at GIMPCon 2000 - - - - - - From left to right, top to bottom: Calvin, Simon, Seth, Jakub, - Lauri, Austin, Tigert, Tim, Jens, Tor, Jay, Daniel, Sven, Adam, - Mitch, Garry, Marc, Caroline, Andy, Yosh. - - - - We'd like to thank the Free - Software Foundation, the Chaos Computer Club and O'Reilly Germany for their - help that made this meeting possible. - - - diff --git a/gimpcon2003-mins-1.xml b/gimpcon2003-mins-1.xml deleted file mode 100644 index d51e16bf24bb6f5b3ebcbc06932b5a8ed647681e..0000000000000000000000000000000000000000 --- a/gimpcon2003-mins-1.xml +++ /dev/null @@ -1,310 +0,0 @@ - - - - - - - The First Big Serious Meeting of GIMPCon 2003 - First Meeting - Minutes of the first GIMPCon 2003 Meeting - - - - August 7th 2003, around 8pm - - - - Discussion was led by Daniel Rogers (dsrogers) but stuff said is - for the most part anonymous. Partly because there shouldn't be any - ad hominem attacks that way, and partly because I didn't take down - any names. - - - - Present: Daniel Rogers (dsrogers), Raphaël Quinet, Dave Neary - (bolsh), Sven Neumann (Sven), Michael Natterer (mitch), Henrik - Brix Andersen (brix), Jakub Steiner (jimmac), Simon Budig (nomis), - Marc Lehmann, Ville Pätsi (drc), Øyvind Kolås (pippin), Calvin - Williamson (calvin), Roman Joost (romanofski). - - - - Absent but at camp: Maurits Rijk (Maurits), Branko Collin (bbc). - - - - Topic discussion, in approximate chronological order: - - - The GIMP foundation - - - Release manager - - - Decision making (or lack of - it) - - - General stuff about CVS, - Bugzilla - - - Communication - - - - -
- The GIMP Foundation - - - The idea of a foundation was proposed. Lots of ideas were thrown - about as to what kind of remit it would have. If created, the - foundation would certainly have 2 things we don't have at the - moment - a bank account people could donate to, and a focus on - marketing in the broadest sense of the word. - - - - Some of the issues were whether the foundation would be set up - in Europe or in the US (in the US it might make it easier to get - donations from US companies, but in Europe we're not as - litigious, so setting up would certainly cost less, but then we - probably wouldn't have NPO status in the US), whether it would - have any technical aspect (that is, would the foundation act as - a kind of steering committee for the general direction of the - GIMP?), and how, if the issue came up, we might pay someone. - - - - This led onto a discussion of whether the foundation would be - responsible for setting release dates, or whether we would have - a separate... - - -
- -
- Release Manager - - - The general consensus (more on that later) was that a release - manager is a good thing. There do seem to be a few different - ideas of what the role would entail. The general idea would be - that the release manager would be responsible for following CVS - and know at what stage a given feature is at, follow bugzilla - making sure that bugs got milestoned for some release in order - of their priority, would annoy people to get commits in before - feature freeze dates or postpone mercilessly features which are - not finished. - - - - It was agreed that a release schedule would be helpful to define - the perimeters of responsibility of the release manager - - basically, some way to set up large milestones to aim for with - things to go into those milestones. This release schedule would - be subject to revision, and would be no more realistic than any - other release schedule, but it would serve as a guide for - development. Dan agreed to draw up a first draft of this, and - we'll have something more concrete before the end of the - weekend. - - - - The questions that came up about the release manager were things - like where his authority comes from, how does he decide which - bugs are important and which features can be postponed and so - on. In other words, how do decisions get made. Is the release - manager a benevolent dictator, or does he answer to the larger - developer and user community? If so, to what extent? Is backing - out CVS commits OK, for example? - - - - So we started talking about how to get contentious decisions - made. - - -
- -
- Decision making (or lack of it) - - - Currently, there are two ways to get something done in the - GIMP. First, you can write decent code and patches for a while, - until you get CVS commit access, then you write whatever feature - you're interested in, and commit it. If no-one backs it out, - then it's in. - - - - Second, you can bring it up on the mailing list, or in bugzilla, - or in IRC (more on communication later), and discuss it until - there is a consensus. However, we tend to be pretty bad at - reaching consensus on anything even slightly contentious. The - important questions to be answered any time a discussion like - this comes up are what's going to be done, and who's going to do - it. - - - - It was agreed that beyond a certain point, there is generally - very little technical merit to these types of discussions. It - was felt that about 5 days was enough for everyone with an - opinion on a given matter to make that opinion known, and that - after that point, it would be an idea to have a summary of the - salient points and close the discussion. That means, the people - here would stop posting to the discussion. Of course, if other - people want to keep on flaming, they're free to do so, but - people will just ignore the thread. - - - - At this point, the summary should sum up the various points, and - finish with an answer to those two questions - what gets done, - and who's doing it. - - - - We may even have a bake-off system. If there are two competing - ideas for the way something should be done, currently no-one - tends to do it. Ideally, both people would do it and we pick the - best one. - - - - This brings up another point, though - in general, what is - authority? And in particular, at what point has someone gained - enough standing and authority to post one of these thread-ending - summaries? Some discussion is going to be had on that over the - weekend. - - -
- -
- General stuff, about Bugzilla and CVS - - - We talked about various ways of improving the way we use these - tools. First is whether it makes sense for us to have module - owners, and if so, who should they be? Should we use the system - of bug owners to track who is responsible for a bug at any given - time, or is the current scheme of bugs@gimp.org sufficient? Do - we need to change bugs@gimp.org to something else to avoid - confusion with the old bug reporting address? There were a few - open points in here. - - - - Second, we talked about pre-release branches, and whether it - would be worthwhile having a mozilla style release cycle with - feature-freezes, followed by concurrent bug-fixing before - unstable releases, freeing up the branch for bigger stuff that - people want to start committing. In general, it was felt that - there was very little to be gained from that, and the current - system of a long-lived devel branch with self-imposed feature - freezes every few weeks was a better way to go. - - - - We also expressed a desire to have more redundancy in the - non-technical aspects of The GIMP, things like the mailing lists - and ftp mirror lists should have more than one person with the - ability to change them so that if there's a problem, and that - person has no time to take care of it, then someone - will. Perhaps using a Debian or GNU style ticket system might - help here fro these particular tasks? In any case, everyone in a - given group should know everyone else in the group, and know - more or less that when an issue gets in, it will be handled by - at least one person. - - -
- -
- Communication - - - It was agreed that we need to communicate better (that's a - no-brainer, really). For a start, every developer should be - subscribed to the userlist. gimp-devel (if it doesn't disappear - altogether) would only be used for technical discussions of - implementation details - all the philosophical level discussions - of new features, ui changes, release mechanisms and so on should - be discussed on the user list. - - - - Basically, we're going to talk a lot more about how the - developers can interface better with the users. - - -
- -
- Decisions - - - Not too many of these... we will have a release manager, but we - need to define exactly what his/her remit will be. And who it - will be. We agreed that the 5 days and it's dead - rule for threads makes sense, so that will be done. - - -
- -
- Future - - - - - Roadmap - rough release schedule, we will have a first draft - today. - - - GIMP Foundation - we need to define its responsibilities, - set up election rules, and get this set up. The principle of - the foundation is more or less agreed. - - - Communication - - - Release Manager - what'll he do, who'll he be. This should - be short once we have discussed communication channels a - bit. - - - Technie stuff - Sven and mitch are going to talk to us about - the re-organisation of the code, GObjectification of - everything, and other stuff. Daniel and Calvin are going to - talk to us about GEGL and how they feel The GIMP could use - it. This will probably be a two-way discussion about what - kind of things we expect GEGL to furnish as well. - - - GIMP tutorials - jimmac and nomis are going to do some - presentations for people, which should be good. - - - Plug-in distribution - 3 years ago this was discussion, yosh - has been working on something as a proof-of-concept, it - would be nice to address this and get something in place - soon. - - - - -
- - - Written by Dave Neary - - -
diff --git a/gimpcon2003-mins-2.xml b/gimpcon2003-mins-2.xml deleted file mode 100644 index 2624d2c9814f5a84258d0ef45b8c1c62598e188d..0000000000000000000000000000000000000000 --- a/gimpcon2003-mins-2.xml +++ /dev/null @@ -1,374 +0,0 @@ - - - - - - - The Second Big Serious Meeting of GIMPCon2003 - Second Meeting - Minutes of the second GIMPCon 2003 Meeting - - - - August 8th 2003, around 8pm - - - - Discussion was led by Daniel Rogers (dsrogers) but stuff said is - for the most part anonymous. Partly because there shouldn't be any - ad hominem attacks that way, and partly because I didn't take down - any names. - - - - Present: Daniel Rogers (dsrogers), Raphaël Quinet, Dave Neary - (bolsh), Sven Neumann (Sven), Michael Natterer (mitch), Henrik - Brix Andersen (brix), Jakub Steiner (jimmac), Simon Budig (nomis), - Marc Lehmann, Ville Pätsi (drc), Øyvind Kolås (pippin), Calvin - Williamson (calvin), Roman Joost (romanofski), Maurits Rijk - (Maurits), Branko Collin (bbc). - - - - Topic discussion, in approximate chronological order: - - - Features required for 2.0 - - - Documentation - - - Web-site - - - Roadmap - - - Bugs - - - Task List - - - GIMP Foundation - - - Release manager - - - - -
- Features required for 2.0 - - - There was quite a lot of talk on what was required for a 2.0 - release. It was agreed that a pre-release should have feature - complete versions of everything going into 2.0, for obvious - reasons. These can be somewhat buggy, but they should at least - support what is supported in the 1.2 equivalents. - - - - The major features or API changes which it was agreed are - necessary are: - - Complete path tool (nomis) - Remove libgck (Sven and mitch) - Finish the text tool (Sven) - Documentation (more on this later) - Web-site (again, more on this later) - Some libgimp changes which need to be made now so that - we can havebinary compatibility across a 2.2 release - - - -
- -
- Documentation - - - We felt that with pre-releases, the documentation will become - more complete. There should, however, be an effort to actively - get people writing docs. The main requirement, then, for 2.0 - pre-releases will be to have a working help framework, so that - when people hit F1 for help, they at least get a message saying - This help item does not exist yet.If you would like to - help write it, contact docs@gimp.org or some such. - - - That email address doesn't exist (yet). People interested in - helping with the documentation should have a look at the - Wiki. - - - - - - If documentation is going to be released as a separate package, - as now seems likely, then we will need to define the interface - between the core and the help pages reasonably quickly. The - general idea is to more or less hard-code tagnames for a - particular help topic, and get the core and help using the same - tags, and agreeing on how they be communicated. This will - presumably require a considerable amount of communication with - the help team. - - - - We also need to have the docs browsable online so that if people - want to browse them they can. - - -
- -
- Web-site - - - The new site should switch over to www.gimp.org soon. There will - obviously be quite a bit of pain involved as content gets added - and we get lots of your website sucks type - feedback, but this will only befor the short term. We should - switch to mmaybe as the main site before 2.0pre1. It was - suggested to do it even earlier than that, in the region of 2 to - 3 weeks time. - - - - It was also discussed whether it was a good idea to have a - separate coordinator for the website. - - -
- -
- Roadmap - - - As an approximate set of ideals, it was agreed that we want - this: 2.0pre1 very soon, 2.0 soon, 2.2 next year, and GEGL - integration the end of next Summer. - - - - More specifically, the near-term release schedule that we agreed - was reasonable is this: - - - - 1 or 2 developer releases (one now, more or less, and another - one in another 2 weeks). 6 weeks time (end of September 2003): - First pre-release of 2.0, including the features mentioned - above, and any other minor features that people code in the - meantime (hint, hint). Roughly 3 months later: 2.0 - - - - It was more or less agreed that 3 to 4 weeks was a nice - turnaround time for pre-releases, so that would imply between 4 - and 6 (inclusive) pre-releases before 2.0. - - - - The reason for not having a pre-release straight away was - mentioned above: to be feature complete, some features need a - little more than 2 weeks work, and people have real lives. So 6 - weeks was felt to be a reasonable amount of time to have the - path tool and the help browser in place. - - -
- -
- Bugs - - - The developer release will also be a prelude to a bug week. We - would like people (that's you, in particular) to actively work - on bugzilla clean-up for 2.0 - bugs need to be prioritized, - unconfirmed bugs need confirming and milestoning (and if you're - feeling really helpful, fixing). The idea would more or less be - that the 2.0 milestone will be locked down for anything other - than serious bugs after this bug week, so if there are bugs that - are annoying you a lot, this is your chance to get them - considered and worked on for the 2.0 releases. - - - - Just to spell that out - at the end of the bug week, any bugs - reported against The GIMP in CVS will be milestoned for 2.0.x, - or even 2.2, unless they are considered blockers for the - release. If we want to get a 2.0 release soon, we need to get - lots of testing done, and lots of bugfixing done, but we also - need to choose what to do and what not to do. We felt this was a - reasonable compromise. - - - - It was also re-discussed whether it would make sense to have - module owners. The conclusion was that for certain components, - it makes sense to have a smaller group of people getting the bug - reports and having responsibility for them. This would be done - via mail aliases for the group of people guiding the component, - in a similar way to that which is used for (say) gtktreeview in - gtk+. - - - - The module owner group wouldn't have to be technical, and we - should be actively recruiting people to do this kind of work and - leave more time for programmers to program. - - - - This leads us on to... - - -
- -
- Task list - - - There are lots of non-technical jobs that need doing around the - gimp-docs, website, bugzilla triage, internationalisation, - etc. Often it is quite difficult to know what needs doing, and - who to contact about getting it done. We need a list of - bite-sized tasks that people can do, including the kinds of - tasks that only take a few hours a week to do, but are ongoing - tasks. - - - - We used to have a TODO, and we could use that system again, if - someone were maintaining it. That could come under the remit of - the release manager to some extent, but since the mainenance of - the TODO list is mostly a non-technical task, anyone could do it - (in fact, as an example of a task, Maintaining the TODO - list would go in the TODO list). - - - - We might do this through Bugzilla using a keyword to allow - getting at the list easily, which would imply getting more - people looking at bugzilla regularly. Then again, if there were - a link to a bugzilla query on the webpage marked GIMP - TODO list we could get that for free. - - -
- -
- GIMP Foundation - - - Basically, we're agreed this is a good idea to have some kind of - public face people and companies can contribute to. There is no - problem with having 2 foundations, one in Europe and one in the - US. It was more or less agreed that assigning copyright to the - foundation isn't going to happen soon (for a start, so many - plug-in authors have gone their merry way and are almost - unfindable) This may hapen in the future, but most people felt - that it would not be something they'd be happy doing personally. - - - - Other people said they would prefer to assign copyright to an - organism under the jurisdiction of European law rather than - under US jurisdiction. - - - - So, to sum up, there's no reason not to have one of - these. Daniel Rogers has agreed to do the necessary paperwork - and set up the foundation and the bank account for donations in - the US. Pretty quickly after getting that up and going, we will - need to get a board of directors and a set of by-laws. We know - lots of people who can help with this (in particular, the GNOME - foundation and the FSF). - - - - If someone wants to set up an equivalent in Europe, we're all - ears. Currently no-one has said they'll do it, so it's an open - point. To start, the foundation will only be a board an a bank - account - in the future, we could expand its responsibilities to - promotional work, a single point where people could go to get - speakers, a group that does press releases and so on. It was - agreed that at least in the short term it is undesirable to have - the foundation have actual control of source code, just in case - the foundation then gets sued. - - - - In brief, it's being set up with a very narrow remit, with the - possibility to expand later if it is felt that there is a need. - - -
- -
- Release manager - - - The responsibilities are: - - - Follow CVS so that he can write release notes, and knows at - any given time who is working on what, and at what stage it - is - - - Follow bugzilla closely - - - Make releases regularly, according to the roadmap (or make - sure releases get made) - - - Update the roadmap to reflect reality - - - Write release notes for the releases (keep NEWS up to date) - - - Generally annoy people sending mails to the mailing lists and - sending content to the website to explain the state of play - and get people to work on stuff. - - - - - - Dave Neary (me) agreed to do this. He already regrets it. - - - - That's it folks - today, Sven and mitch are going to talk to us - about the major changes in the codebase and the general utility - stuff which exists now which has been written from scratch, - Calvin and Daniel are going to talk about GEGL and how we can - use it, and work towards having a GEGL that we can use in a - year. I'm going to lead a discussion on communication in the - GIMP, and how to maybe make it easier for people to contribute, - and jimmac is going to demonstrate what a power user really is. - - - - Goodbye from everyone at camp. As usual, comments are welcome on - all this stuff. While on a philosophical level, we are agreed on - the direction things should take, all the details are open to - discussion, if there's any reason to change them. - - - - Written by Dave Neary - - -
- -
diff --git a/git.xml b/git.xml deleted file mode 100644 index e62090613c4b1903eac16da1005586cdfef38f22..0000000000000000000000000000000000000000 --- a/git.xml +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - Git - Git - Living on the bleeding edge - - - - The GIMP source code lives in the gimp - repository on the - GNOME git server. - For more information on the GNOME git solution, go - here. - - - - The GNOME git server hosts a couple of GIMP related repositories: - - - - - - - Module - Description - - - - - - babl - - - Pixel format conversion library - - - - - gegl - - - Generic Graphical Library - - - - - gimp - - - GIMP and the standard set of plug-ins - - - - - gimp-data-extras - - - GIMP Data files such as brushes, gradients, patterns and the like - - - - - gimp-gap - - - GIMP Animation Package, a set of plug-ins that provide - video editing functionality - - - - - gimp-help-2 - - - GIMP User Manual - - - - - gimp-perl - - - GIMP Perl bindings and a bunch of nice gimp-perl scripts - - - - - gimp-plugin-template - - - GIMP Plug-In Template, a starting ground for plug-in developers, - currently in need of updating with regards to the use of GEGL - - - - - gimp-plugins-unstable - - - GIMP plug-ins from the past, a collection of unstable and - unmaintained plug-ins - - - - - gimp-ruby - - - GIMP Ruby-based scripting plug-in - - - - - gimp-tiny-fu - - - GIMP Tiny-Fu, a drop-in replacement for Script-Fu - - - - - gimp-web - - - The GIMP web site, available at www.gimp.org - - - - - gimp-web-devel - - - The source of the pages you are reading right now - - - - - - - diff --git a/index.xml b/index.xml deleted file mode 100644 index cb9c8bb9b6a5972f485e7e6e54cc6799f185ec3a..0000000000000000000000000000000000000000 --- a/index.xml +++ /dev/null @@ -1,37 +0,0 @@ - - -]> - - - - - - GIMP Development - Online Resources for GIMP Developers - - - - This site tries to provide useful information for GIMP developers. - No matter if you are into plug-in - development or want to dive into the - internals of the - GIMP core, you should find your way from here. - - - - If you're looking for the main GIMP website you should visit - www.gimp.org. - - - - The GIMP source code is versioned with git. You - can browse the - source online. - - - diff --git a/mailing-lists.xml b/mailing-lists.xml deleted file mode 100644 index 730af9a86556005ad5f5d4078ad7e881275c14a0..0000000000000000000000000000000000000000 --- a/mailing-lists.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - Mailing Lists - The finest spam in town - - - - There are several mailing-lists related to GIMP and - www.gimp.org lists them all. - - - diff --git a/plug-in-template.xml b/plug-in-template.xml deleted file mode 100644 index 5f13fe01f47526d3f50e3b648ad428331383f128..0000000000000000000000000000000000000000 --- a/plug-in-template.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - GIMP Plug-In Template - Plug-In Template - Don't start from scratch - - - - The GIMP Plug-In Template is an empty GIMP Plug-In that does - nothing. It also has a GUI that allows to control how it achieves - this task. But best of all, it comes with a complete setup for - autoconf, - automake, - internationalisation and all these things you never wanted to know - about. - - - - Thanks to the GIMP Plug-In Template you don't need to worry about - all these things. Just download the tarball, add some magic image - manipulation routines and voilà, your own GIMP plug-in. - - - - Grab the latest release from - - ftp.gimp.org/pub/gimp/plugin-template/ - - - - diff --git a/plug-ins.xml b/plug-ins.xml deleted file mode 100644 index 2361348cd05ddcbf24f48b0c087bed026622d426..0000000000000000000000000000000000000000 --- a/plug-ins.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - -]> - - - - - Plug-In Development - Writing GIMP plug-ins - - - - - - Writing a GIMP Plug-In Part I - - - Writing a GIMP Plug-In Part II - - - Writing a GIMP Plug-In Part III - - - - - - Make good use of the GIMP 2.0 API reference, - and you can also have a look at a talk about - GIMP plug-in programming that Simon gave at GUADEC in Sevilla. - - - diff --git a/screenshots.xml b/screenshots.xml deleted file mode 100644 index 10e3afe186b34749081dcf5be501f8980c54341d..0000000000000000000000000000000000000000 --- a/screenshots.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - Screenshots - What everyone is after... - - - - Here are a few screenshots of the development version. More should - be added... - - - - - - - - - - No image opened - - - - This screenshot shows a GNOME desktop and GIMP 2.5 right after - startup with no image loaded yet. - - - - - - - - - - Print dialog - - - - The Print plug-in has been further improved for GIMP 2.5. - - - - - - - - - - Curves dialog - - - - These screenshots illustrate changes to the Curves dialog for the - upcoming GIMP 2.6 release. - - - diff --git a/scripts/make_api_docs.sh b/scripts/make_api_docs.sh new file mode 100755 index 0000000000000000000000000000000000000000..b7c00d97b0371c50f11f2d8f347c4991bf412f1f --- /dev/null +++ b/scripts/make_api_docs.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# git clone https://gitlab.gnome.org/GNOME/gimp + +function build_api_docs () { +rm -fr gimp_$1 +cp -r gimp gimp_$1 +cd gimp_$1 +git checkout $1 +aclocal +autoupdate +autoconf +libtoolize +automake --add-missing +./configure --prefix=`pwd` --enable-gtk-doc --enable-gtk-doc-app \ + --disable-python +make +make install +cd .. +} + +build_api_docs GIMP_2_7_5 +build_api_docs GIMP_2_8_8 +build_api_docs GIMP_2_9_8 +build_api_docs GIMP_2_10_32 diff --git a/themes/hyde/CHANGELOG.md b/themes/hyde/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..891329a05ea154128945473c7657c2154b69e3fd --- /dev/null +++ b/themes/hyde/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + +## Version 1.0 + +- Due to the switch to the base template feature the minimum required version of Hugo changed to v0.21 +- Support for Google Analytics have been added +- Hugo's internal Disqus template replaced the custom one of this theme. The Disqus shortname now has to be defined outsite the `[params]` blog diff --git a/themes/hyde/LICENSE.md b/themes/hyde/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..c344d146f49f6ebb8fb06709f403d1ada1f1e684 --- /dev/null +++ b/themes/hyde/LICENSE.md @@ -0,0 +1,9 @@ +# Released under MIT License + +Copyright (c) 2013 Mark Otto. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/themes/hyde/README.md b/themes/hyde/README.md new file mode 100644 index 0000000000000000000000000000000000000000..fa8c4b903d57cbd640a63d0779723e16ec8bdda9 --- /dev/null +++ b/themes/hyde/README.md @@ -0,0 +1 @@ +# GIMP Developer theme based on Hyde diff --git a/themes/hyde/archetypes/default.md b/themes/hyde/archetypes/default.md new file mode 100644 index 0000000000000000000000000000000000000000..74583a252b67661df2332406fe1c477cf22432a5 --- /dev/null +++ b/themes/hyde/archetypes/default.md @@ -0,0 +1,6 @@ ++++ +Description = "" +Tags = ["Development", "golang"] +Categories = ["Development", "GoLang"] +menu = "main" ++++ diff --git a/themes/hyde/go.mod b/themes/hyde/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..3ee4de379e94cef11dc9bede5115314599196e78 --- /dev/null +++ b/themes/hyde/go.mod @@ -0,0 +1,3 @@ +module github.com/spf13/hyde + +go 1.12 diff --git a/themes/hyde/images/screenshot.png b/themes/hyde/images/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..8248097bb818d88cbef7239da9c26cd347e41153 Binary files /dev/null and b/themes/hyde/images/screenshot.png differ diff --git a/themes/hyde/images/tn.png b/themes/hyde/images/tn.png new file mode 100644 index 0000000000000000000000000000000000000000..b6778fdbb338a85b85eb9574ba398af4565e5395 Binary files /dev/null and b/themes/hyde/images/tn.png differ diff --git a/themes/hyde/layouts/404.html b/themes/hyde/layouts/404.html new file mode 100644 index 0000000000000000000000000000000000000000..a919514ade829ae2c153f14310e1ffb5038e6770 --- /dev/null +++ b/themes/hyde/layouts/404.html @@ -0,0 +1,4 @@ +{{ define "main" -}} +

404: Page not found

+

Sorry, we've misplaced that URL or it's pointing to something that doesn't exist. Head back home to try finding it again.

+{{- end }} \ No newline at end of file diff --git a/themes/hyde/layouts/_default/baseof.html b/themes/hyde/layouts/_default/baseof.html new file mode 100644 index 0000000000000000000000000000000000000000..7f5133f4c8eb47d6950446f101e1be9a7a0157cf --- /dev/null +++ b/themes/hyde/layouts/_default/baseof.html @@ -0,0 +1,43 @@ +{{ partial "head.html" . }} + +
+ + + + +
+
+ + + + {{ partial "sidebar.html" . }} + + +
+
+ {{ block "main" . -}}{{- end }} +
+ + {{ if not .Site.IsServer }} + {{ template "_internal/google_analytics.html" . }} + {{ end }} +
+
+
+ +
+ + Copyright © 2003-2022 The GIMP Development Team. + + + webmaster@gimp.org + +
+
+
+ + Validate XHTML + +
+ + diff --git a/themes/hyde/layouts/_default/list.html b/themes/hyde/layouts/_default/list.html new file mode 100644 index 0000000000000000000000000000000000000000..47a6453ade6f8a19338e81685f9f6a7bd45c2d33 --- /dev/null +++ b/themes/hyde/layouts/_default/list.html @@ -0,0 +1,9 @@ +{{ define "main" -}} +
    +{{ range .Data.Pages -}} +
  • + {{ .Title }} +
  • +{{- end }} +
+{{- end }} diff --git a/themes/hyde/layouts/_default/single.html b/themes/hyde/layouts/_default/single.html new file mode 100644 index 0000000000000000000000000000000000000000..292e7fffe0dfc7764e3ff7a4bee868b0a9f9e77f --- /dev/null +++ b/themes/hyde/layouts/_default/single.html @@ -0,0 +1,7 @@ +{{ define "main" -}} +
+

{{ .Title }}

+ + {{ .Content }} +
+{{- end }} diff --git a/themes/hyde/layouts/index.html b/themes/hyde/layouts/index.html new file mode 100644 index 0000000000000000000000000000000000000000..ec6d2eb8b7daacf77c7c7a7ad46cbdb6ac9a4887 --- /dev/null +++ b/themes/hyde/layouts/index.html @@ -0,0 +1,18 @@ +{{ define "main" -}} +
+{{ range .Site.RegularPages -}} +
+

+ {{ .Title }} +

+ + {{ .Summary }} + {{ if .Truncated }} + + {{ end }} +
+{{- end }} +
+{{- end }} diff --git a/themes/hyde/layouts/partials/head.html b/themes/hyde/layouts/partials/head.html new file mode 100644 index 0000000000000000000000000000000000000000..72411100435bebf5430f3bf26d97ca70811bfdb4 --- /dev/null +++ b/themes/hyde/layouts/partials/head.html @@ -0,0 +1,33 @@ + + + + + + {{ hugo.Generator }} + + + + + {{ if .IsHome -}} + {{ .Site.Title }} + {{- else -}} + {{ .Title }} · {{ .Site.Title }} + {{- end }} + + + + + + + + {{ partial "head_fonts.html" . }} + + + + + + + {{ range .AlternativeOutputFormats -}} + {{ printf `` .Permalink .Rel .MediaType.Type $.Site.Title | safeHTML }} + {{ end -}} + diff --git a/themes/hyde/layouts/partials/head_fonts.html b/themes/hyde/layouts/partials/head_fonts.html new file mode 100644 index 0000000000000000000000000000000000000000..4729eb2355d4a40315bcc8c6c7ee70b184ea611d --- /dev/null +++ b/themes/hyde/layouts/partials/head_fonts.html @@ -0,0 +1 @@ + diff --git a/themes/hyde/layouts/partials/hook_head_end.html b/themes/hyde/layouts/partials/hook_head_end.html new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/themes/hyde/layouts/partials/sidebar.html b/themes/hyde/layouts/partials/sidebar.html new file mode 100644 index 0000000000000000000000000000000000000000..766f72a791df947bced3ad20136e1111279605e3 --- /dev/null +++ b/themes/hyde/layouts/partials/sidebar.html @@ -0,0 +1,8 @@ + + {{ range .Site.Menus.main -}} + + {{ .Name }} +
+
+ {{- end }} + diff --git a/themes/hyde/static/apple-touch-icon-144-precomposed.png b/themes/hyde/static/apple-touch-icon-144-precomposed.png new file mode 100644 index 0000000000000000000000000000000000000000..19323de1ee3aa16ca05e222a3aecdb5d6251b578 Binary files /dev/null and b/themes/hyde/static/apple-touch-icon-144-precomposed.png differ diff --git a/themes/hyde/static/css/hyde.css b/themes/hyde/static/css/hyde.css new file mode 100644 index 0000000000000000000000000000000000000000..597c8cd56136a58e95fa24a216ff8cb33abb86ac --- /dev/null +++ b/themes/hyde/static/css/hyde.css @@ -0,0 +1,300 @@ +/* This is the stylesheet of http://developer.gimp.org/ and should + * only be changed by the designer or the website maintainer. Remember + * that changes done here will change the appearance on the whole site + * so keep a backup of this file while working with it. Niklas */ + +/* Copyright (C) 2002-2006 by The GIMP Web Team - Contributions by: + * Ville Pätsi (drc), Henrik Brix Andersen (brix), Carol Spears + * (carol), Niklas Mattisson (scizzo), Raphaël Quinet (raphael), + * Branko Collin (branko), Sven Neumann (neo) and Øyvind Kolås + * (pippin) + * + * This style sheet and corresponding site layout are designed to be + * used on official GIMP web sites only. You may copy some parts of + * this file into your own style sheet as long as you create your own + * design that is significantly different from the one used on GIMP + * web sites (layout, colors, etc.) and you give appropriate credit if + * you copy more than a few lines from this file (do not claim that + * you wrote everything yourself). + */ + +body { + background: white; + color: black; + font-family: arial,helvetica,sans-serif; + margin: 0px; + padding: 0px; +} + +a { + background: transparent; + color: #566e41; + text-decoration: none; + font-weight: bold; +} + +a:hover { + background: transparent; + color: #991e1e; + text-decoration: underline; + font-weight: bold; +} + +img { + border: none; +} + +img.map { + margin: 0px; + padding: 0px; +} + +p { + margin-top: 1.33em; + margin-right: 1.33em; + text-align: justify; +} + +p.title { + font-size: 110%; +} + +p.images img { + border: solid black 2px; +} + +p.framelessimages, +p.images { + text-align: center; +} + +p.screenshot { + clear:both; + padding: 1em; +} + +p.screenshot .mediaobject { + float: left; + background: url(/images/shadow.png) no-repeat bottom right !important; + background: url(/images/shadow.gif) no-repeat bottom right; + margin: 0 0 6px 6px; + padding: 4px; +} + +p.screenshot .mediaobject img { + border: none; + margin: -6px 2px -2px -6px; +} + +li { + text-align: justify; +} + +td { + padding: 5px 5px 0px 0px; +} + +td.main { + padding: 10px; + padding-left: 40px; + padding-right: 40px; + vertical-align: top; + width: 100%; +} + +td.map { + margin: 0px; + padding: 0px; +} + +h1 { + background-color: #dce5d4; + color: black; + border: thin solid #a9b3a1; + padding: 5px; + margin-bottom: 30px; + margin-left: -30px; + margin-right: -30px; + font-weight: bold; + font-size: 110%; + text-align: center; +} + +h2 { + font-weight: bold; + clear: both; + font-size: 110%; +} + +h3 { + font-weight: bold; + clear: both; + font-size: 105%; +} + +td.menu { + background: #dce5d4; + color: black; + border-style: solid; + border-color: #a9b3a1; + border-top-width: 0px; + border-bottom-width: 0px; + border-left-width: 0px; + border-right-width: 1px; + padding: 10px; + font-weight: bold; + vertical-align: top; + white-space: nowrap; +} + +table.layout { + clear: both; + margin: 0px; + border: none; + padding: 0px; + border-collapse: collapse; + width: 100%; +} + +div.titlebar { + background-image: url("../images/developer-barbg.png"); + background-repeat: repeat-x; + height: 100px; +} + +div.informaltable table { + border-collapse: collapse; +} + +div.informaltable table tr td, div.informaltable table tr th { + padding: 5px; +} + +img.titlebarleft { + float: left; +} + +img.titlebarright { + float: right; +} + +div.linkbar, div.navbar { + clear: both; + background: #dce5d4; + color: black; + border: solid #a9b3a1; + border-width: 1px 0px 1px 0px; + padding: 5px 5px 5px 5px; + font-weight: bold; + text-align: center; +} + +span.footerleft { + float: left; + padding: 20px; +} + +span.footerright { + float: right; + padding: 20px; +} + +span.shrink1 { + padding-left: 10px; + font-size: 95%; +} + +span.shrink2 { + padding-left: 20px; + font-size: 90%; +} + +span.shrink3 { + padding-left: 30px; + font-size: 85%; +} + +div.rss { + margin-top: 1em; + margin-bottom: 2em; +} + +div.rss dd p { + white-space: pre; + border-width: 0px; + padding: 0px; + border: 2px solid red; +} + +div.rss img { + border: none; + float: right; + border: 2px solid red; +} + +div.rss p { + background-color: green; + display: inline; +} + +span.date { + display: block; + font-size: 75%; + padding-right: 1em; + font-style: italic; + background-color: #ddd; + text-align: right; + border-left: 1px solid #888; + border-top: 1px solid #888; + border-right: 1px solid #888; +} + +div.rss ul { + padding-right: 1em; + margin-top: -0.1em; + padding-left: 2.0em; +} + +div.rss strong { + font-weight: bold; + font-style: italic; + color: #566e41; +} +div.rss b { + font-weight : normal; + color: #000: +} + + +div.rss b { + font-weight: normal; +} + +div.rss ul li { + text-align: left; +} + +div.rss_entry { + margin-bottom: 1em; +} + +div.qandaset tr.question td { + padding-top: 15px; +} + +div.qandaset tr.question p { + margin: 0px; +} + +@media print { + +div.navbar, div.linkbar, td.menu { + display: none +} + +td.main { + padding-right: 0px; + padding-left: 0px; +} + +} diff --git a/themes/hyde/static/favicon.png b/themes/hyde/static/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..84cce4dd307a78a3a9455c4fed62b49b9c7e61ad Binary files /dev/null and b/themes/hyde/static/favicon.png differ diff --git a/themes/hyde/theme.toml b/themes/hyde/theme.toml new file mode 100644 index 0000000000000000000000000000000000000000..977fc14d11a5b090a8c73f91071dbbc9a9fa55b9 --- /dev/null +++ b/themes/hyde/theme.toml @@ -0,0 +1,17 @@ +name = "GIMP Developer Theme" +license = "MIT" +licenselink = "https://github.com/spf13/hyde/blob/master/LICENSE.md" +description = "A fork of the Hyde theme." +tags = ["blog", "company"] +features = ["blog", "themes", "disqus"] +min_version = 0.53 + +[author] + name = "spf13" + homepage = "http://spf13.com" + +# If Porting existing theme +[original] + author = "mdo" + homepage = "http://markdotto.com/" + repo = "https://www.github.com/mdo/hyde" diff --git a/writing-a-plug-in-1.xml b/writing-a-plug-in-1.xml deleted file mode 100644 index 591675462462f633534076bf20121535fd39e36b..0000000000000000000000000000000000000000 --- a/writing-a-plug-in-1.xml +++ /dev/null @@ -1,459 +0,0 @@ - - -]> - - - - - How to write a GIMP plug-in - Writing A Plug-In - Write your own - - - - Written By Dave Neary - - - - In this article, I present GIMP plug-ins basics and introduce the - libgimp API. I will also show how to use the PDB to make our - plug-in available to other script authors. - - -
- Introduction - - - New developers are often intimidated by The GIMP size and its - reputation. They think that writing a plug-in would be a - difficult task. The goal of these articles is to dumb this - feeling down, by showing how easily one can make a C plug-in. - - - - In this part, I present a plug-in's basic elements. We will see - how to install a plug-in and how to get data from an image and - directly manipulate it. - -
- -
- Architecture - - - - - - - - - Architecture - - - Architecture - - - - - The GIMP script interface is centered on the Procedural database - (PDB). At startup, The GIMP looks into a predefined set of - places for scripts and plug-ins, and asks each new script to - identify itself. - - - - The plug-in declares itself to the PDB at that time, and passes - informations like the position it wishes to get in the menu - hierarchy, input parameters, and output parameters. - - - - When a script or a plug-in wants to use our plug-in, it gets - through the PDB, which manages communicating parameters in one - direction and the other in a transparent way. - - - - Internal functions that wish to get exposed to plug-ins have to - be packaged first in the core, that will register them in the - PDB, and secondly in the libgimp that will allow the function to - be called as a normal one. - - - - This was the introduction - now, we will look closer at our - first plug-in, a "Hello, world!". - -
- -
- Compiling the plug-in - - - To be able to compile simple plug-ins for The GIMP, one needs - libgimp headers, as well as an associated utility named - gimptool. - - - - With that utility, one can install a plug-in either in a private - directory (~/.gimp-2.0/plug-ins), or in the global plug-in - directory. - - - - Syntax is - - - - - - - - This utility, with other options, can also be used to install - scripts, or uninstall plug-ins. - -
- -
- Behaviour - - - A GIMP plug-in can typically behave three different ways. It can - take image data, modify it, and send back the modified image, - like edge detection. It can generate an image and send it back, - like some script-fus, or file reading plug-ins like jpeg. Or it - can get an image, and process it without modifying its data, - like a file saver plug-in. - -
- -
- Essentials - - - - - - - This header makes all basic plug-in elements available to us. - - - - - - - - This structure has to have that name. It contains four pointers - to functions, which will be called at set times of the plug-in - life. init and quit are optional, and thus can hold NULL values, - but the last two functions, query and run, are mandatory. - - - - The init() function is called each time The GIMP starts up. This - function is not typically used. Some plug-ins use it to make a - secondary search that is not done by the core. This function is - not used by any standard GIMP plug-in, but could be useful for - example for a plug-in that would like to register some procedure - conditionally on some files presence. - - - - The quit() function is not used much either. It is called when - The GIMP is about to be closed, to allow it to free some - resources. It is used in the script-fu plug-in. - - - - The query() function is called the first time the plug-in is - present, and then each time the plug-in changes. - - - - The run() function is the plug-in's centrepiece. It is called - when the plug-in is asked to run. It gets the plug-in name (as a - plug-in can register several procedures), input parameters, and - a pointer to output parameters, then determines if it is - launched in a interactive way or by a script, and does all the - plug-in processing. Its prototype is - - - - - - -
- -
- MAIN () - - - MAIN is a C macro that holds a bit of dark magic to initialise - arguments. It also calls the appropriate PLUG_IN_INFO function - depending on the timing. Your plug-in needs it. - -
- -
- The query() function - - - query() deals with the procedure registration and input - arguments definition. These informations are saved to speed up - startup time, and refreshed only when the plug-in is modified. - - - - For our "Hello, world!" plug-in, the query function will look - like this: - - - - /Filters/Misc"); - } - ]]> - - - - GimpParamDef contains three things - the parameter type, its - name, and a string describing the parameter. - - - - gimp_install_procedure declares the procedure name, some - description and help strings, menu path where the plug-in should - sit, image types handled by the plug-in, and at the end, input - and output parameters number, as well as the parameters - descriptors. - - - - "RGB*, GRAY*" declares the image types handled. It can be RGB, - INDEXED or GRAY, with or without Alpha. So "RGB*, GRAY*" - describes RGB, RGBA, GRAY or GRAY image type. - - - - GIMP_PLUGIN declares this procedure to be external, and not to - be executed in The GIMP core. - - - - By adding a stub run function now, we can check that our plug-in - has all the essential elements, and test that it registers - itself in the PDB with the "Xtns->Plug-in Details" plug-in. - - - - - - - - - - Plug-in details - - - Plug-in details - - - - - - - - - - - Our plug-in is in the menus - - - Our plug-in is in the menus - - -
- -
- The run() function - - - The other required function for PLUG_IN_INFO is run. The core of - the plug-in stands there. - - - - Output values (return_vals in the prototype) must have at least - one value associated - the plug-in status. Typically, this - parameter will hold "GIMP_PDB_SUCCESS". - -
- -
- Run-modes - - - One can run a plug-in in several different ways, it can be run - from a GIMP menu if The GIMP is run interactively, or from a - script or a batch, or from the "Filters->Repeat Last" shortcut. - - - - The "run_mode" input parameter can hold one of these values: - "GIMP_RUN_INTERACTIVE", "GIMP_RUN_NONINTERACTIVE" or - "GIMP_RUN_WITH_LAST_VALS". - - - - "GIMP_RUN_INTERACTIVE" is typically the only case where one - creates an options dialog. Otherwise, one directly calls the - processing with values from input parameters or from memory. - - - - For our test plug-in, we will simply display a dialog containing - a "Hello, world!" message. Thankfully, this is really easy with - GTK+. Our run function could be: - - - - - - - - Now, when we run our plug-in, there is action: - - - - - - - - - Hello, world! - - - - - - Have a look at the full hello.c plug-in code. - -
- -
- Next part - - - In next part - we will go on, making a more useful plug-in that will get its - hands on image data. We will see how to use The GIMP image - architecture to make the plug-in perform better, processing the - image tile by tile. - -
- -
- - - - - - - - Creative Commons License - - - - - - - This work is licensed under a Creative - Commons Attribution-NonCommercial-ShareAlike 2.5 - License. - -
- -
- diff --git a/writing-a-plug-in-2.xml b/writing-a-plug-in-2.xml deleted file mode 100644 index bdf85b7d183a8d481c18c7ed4181ecf6d3e8cf5c..0000000000000000000000000000000000000000 --- a/writing-a-plug-in-2.xml +++ /dev/null @@ -1,582 +0,0 @@ - - - -]> - - - - - How to write a GIMP plug-in, part II - Part II - Write your own - - - - Written By Dave Neary - - - - In the first - part, I presented essential elements to build a plug-in - interface with The GIMP. Now we will produce a simple but useful - algorithm that we could use in our plug-in. - - -
- Introduction - - - The algorithm we are going to implement is a simple blur. It is - included in The GIMP as "Filters->Blur->Blur" with default - parameters. - - - - That algorithm is very simple. Each pixel in our image is - replaced by a mean value of its neighbours. For example, if we - look at the simplest case where the neighbourhood is 3x3 (see - figure 1), in that case the center value will be replaced with - 5, the mean of the 9 numbers in its neighbourhood. - - - - With this method, edge differences are splatted, giving a - blurred result. One can choose another radius, using a (2r + 1) - x (2r + 1) matrix. - -
- -
- Image structure - - - Last month, we wrote a run() function that did nothing useful. - Let's look again at run() prototype: - - - - - - - - We saw that for a filter (i.e. a plug-in that modifies the - image), the first three input parameters were the run mode, an - identifier for the image, and another one for the active - drawable (layer or mask). - - - - A GIMP image is a structure that contains, among others, guides, - layers, layer masks, and any data associated to the image. The - word "drawable" is often used in GIMP internal structures. A - "drawable" is an object where you can get, and sometimes modify, - raw data. So : layers, layer masks, selections are all - "drawables". - - - - - - - - - - Drawables - - - Drawables - - -
- -
- Accessing the data - - - To get a GimpDrawable from its identifier, we need the - gimp_drawable_get() function: - - - - - - - - From this structure, one can access drawable data through a - GimpPixelRgn structure, and one can check the drawable type - (RGB, gray level). The full listing of functions available for a - GimpDrawable can be found in - the API. - - - - Two very important functions for plug-ins are - gimp_drawable_mask_bounds() and gimp_pixel_rgn_init(). The first - gives the active selection limits on the drawable, and the - second initialises the GimpPixelRgn we will use to access the - data. - - - - As soon as we have a well initialised GimpPixelRgn, we can - access the image data in several different ways, by pixel, by - rectangle, by row or by column. The best method will depend on - the algorithm one plans to use. Moreover, The GIMP uses a - tile-based architecture, and loading or unloading data is - expensive, so we should not use it more than necessary. - - - - - - - - - - Tiles - - - Tiles - - - - - The main functions to get and set image data are: - - - - - - - - There is also another way to access image data (it's even used - more often), that allows to manage data at the tile level. We - will look at it in detail later. - -
- -
- Updating the image - - - At last, a plug-in that has modified a drawable data must flush - it to send data to the core, and to tell the application that - the display must be updated. This is done with the following - function: - - - - - -
- -
- Implementing blur() - - - To be able to try out several different processing methods, we - will delegate the job to a blur() function. Our run() is below. - - - - - - - - There are a few lines here that need to be explained a bit more. - The call to gimp_progress_init() initialises a progress - measurement for our plug-in. Later, if we call - gimp_progress_update(double percent), the percentage given as an - input parameter will be shown graphically. The run_mode tells us - whether the plug-in was launched in a way such as we can display - a graphical interface or not. Possible values are - GIMP_RUN_INTERACTIVE, GIMP_RUN_NONINTERACTIVE or - GIMP_RUN_WITH_LAST_VALS, which mean the plug-in was executed - from The GIMP, from a script, or from the "Repeat last filter" - menu entry. - - - - Regarding the blur algorithm itself, the first version using - gimp_pixel_rgn_(get|set)_pixel() is found below. Some functions - in it have not been explained yet. - - - - gimp_drawable_mask_bounds() allows calculation of the filter's - effect limits, excluding any region that is not in the active - selection. Limiting the processing this way allows an important - performance improvement. - - - - gimp_pixel_rgn_init() takes as input parameters the drawable, - its limits for the processing, and two booleans that - significantly modify the behaviour of the resulting GimpPixelRgn. - The first one tells that "set" operations must be done on shadow - tiles, in order to leave original data as is until - gimp_drawable_merge_shadow() is called, when all modified data - will be merged. The second one tells that modified tiles should - be tagged "dirty" and sent to the core to be merged. Most of the - time, to read data, one uses FALSE and FALSE for these two - parameters, and to write data, one uses TRUE and TRUE. Other - combinations are possible but seldom used. - - - - drawable_id, - &x1, &y1, - &x2, &y2); - channels = gimp_drawable_bpp (drawable->drawable_id); - - /* Initialises two PixelRgns, one to read original data, - * and the other to write output data. That second one will - * be merged at the end by the call to - * gimp_drawable_merge_shadow() */ - gimp_pixel_rgn_init (&rgn_in, - drawable, - x1, y1, - x2 - x1, y2 - y1, - FALSE, FALSE); - gimp_pixel_rgn_init (&rgn_out, - drawable, - x1, y1, - x2 - x1, y2 - y1, - TRUE, TRUE); - - for (i = x1; i < x2; i++) - { - for (j = y1; j < y2; j++) - { - guchar pixel[9][4]; - - /* Get nine pixels */ - gimp_pixel_rgn_get_pixel (&rgn_in, - pixel[0], - MAX (i - 1, x1), - MAX (j - 1, y1)); - gimp_pixel_rgn_get_pixel (&rgn_in, - pixel[1], - MAX (i - 1, x1), - j); - gimp_pixel_rgn_get_pixel (&rgn_in, - pixel[2], - MAX (i - 1, x1), - MIN (j + 1, y2 - 1)); - - gimp_pixel_rgn_get_pixel (&rgn_in, - pixel[3], - i, - MAX (j - 1, y1)); - gimp_pixel_rgn_get_pixel (&rgn_in, - pixel[4], - i, - j); - gimp_pixel_rgn_get_pixel (&rgn_in, - pixel[5], - i, - MIN (j + 1, y2 - 1)); - - gimp_pixel_rgn_get_pixel (&rgn_in, - pixel[6], - MIN (i + 1, x2 - 1), - MAX (j - 1, y1)); - gimp_pixel_rgn_get_pixel (&rgn_in, - pixel[7], - MIN (i + 1, x2 - 1), - j); - gimp_pixel_rgn_get_pixel (&rgn_in, - pixel[8], - MIN (i + 1, x2 - 1), - MIN (j + 1, y2 - 1)); - - /* For each layer, compute the average of the - * nine */ - for (k = 0; k < channels; k++) - { - int tmp, sum = 0; - for (tmp = 0; tmp < 9; tmp++) - sum += pixel[tmp][k]; - output[k] = sum / 9; - } - - gimp_pixel_rgn_set_pixel (&rgn_out, - output, - i, j); - } - - if (i % 10 == 0) - gimp_progress_update ((gdouble) (i - x1) / (gdouble) (x2 - x1)); - } - - /* Update the modified region */ - gimp_drawable_flush (drawable); - gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); - gimp_drawable_update (drawable->drawable_id, - x1, y1, - x2 - x1, y2 - y1); - } - ]]> - -
- -
- Row processing - - - Our function has a bug drawback: performance. On a 300x300 - selection, with the timing code uncommented, blur() took 12 - minutes on my K6-2 350MHz, well loaded with other stuff. To - compare, on the same selection, Gaussian blur took 3 seconds. - - - - If we modify our function to rather use - gimp_pixel_rgn_(get|set)_row() the result is far better. We - reduce the timing for the 300x300 selection from 760 seconds to - 6 seconds. blur() V2 is below: - - - - drawable_id, - &x1, &y1, - &x2, &y2); - channels = gimp_drawable_bpp (drawable->drawable_id); - - gimp_pixel_rgn_init (&rgn_in, - drawable, - x1, y1, - x2 - x1, y2 - y1, - FALSE, FALSE); - gimp_pixel_rgn_init (&rgn_out, - drawable, - x1, y1, - x2 - x1, y2 - y1, - TRUE, TRUE); - - /* Initialise enough memory for row1, row2, row3, outrow */ - row1 = g_new (guchar, channels * (x2 - x1)); - row2 = g_new (guchar, channels * (x2 - x1)); - row3 = g_new (guchar, channels * (x2 - x1)); - outrow = g_new (guchar, channels * (x2 - x1)); - - for (i = y1; i < y2; i++) - { - /* Get row i-1, i, i+1 */ - gimp_pixel_rgn_get_row (&rgn_in, - row1, - x1, MAX (y1, i - 1), - x2 - x1); - gimp_pixel_rgn_get_row (&rgn_in, - row2, - x1, i, - x2 - x1); - gimp_pixel_rgn_get_row (&rgn_in, - row3, - x1, MIN (y2 - 1, i + 1), - x2 - x1); - - for (j = x1; j < x2; j++) - { - /* For each layer, compute the average of the nine - * pixels */ - for (k = 0; k < channels; k++) - { - int sum = 0; - sum = row1[channels * MAX ((j - 1 - x1), 0) + k] + - row1[channels * (j - x1) + k] + - row1[channels * MIN ((j + 1 - x1), x2 - x1 - 1) + k] + - row2[channels * MAX ((j - 1 - x1), 0) + k] + - row2[channels * (j - x1) + k] + - row2[channels * MIN ((j + 1 - x1), x2 - x1 - 1) + k] + - row3[channels * MAX ((j - 1 - x1), 0) + k] + - row3[channels * (j - x1) + k] + - row3[channels * MIN ((j + 1 - x1), x2 - x1 - 1) + k]; - outrow[channels * (j - x1) + k] = sum / 9; - } - - } - - gimp_pixel_rgn_set_row (&rgn_out, - outrow, - x1, i, - x2 - x1); - - if (i % 10 == 0) - gimp_progress_update ((gdouble) (i - y1) / (gdouble) (y2 - y1)); - } - - g_free (row1); - g_free (row2); - g_free (row3); - g_free (outrow); - - gimp_drawable_flush (drawable); - gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); - gimp_drawable_update (drawable->drawable_id, - x1, y1, - x2 - x1, y2 - y1); - } - ]]> - - - - Have a look at the slow or - fast blur complete code. - -
- -
- Next part - - - In next part, - we will see how to process the image tile by tile. We will also - have a look at preferences, by modifying our algorithm so it can - take an input parameter. - -
- -
- - - - - - - - Creative Commons License - - - - - - - This work is licensed under a Creative - Commons Attribution-NonCommercial-ShareAlike 2.5 - License. - -
- -
- diff --git a/writing-a-plug-in-3.xml b/writing-a-plug-in-3.xml deleted file mode 100644 index ca168d23969d4bf6f4b4ffd636dc9d346d708673..0000000000000000000000000000000000000000 --- a/writing-a-plug-in-3.xml +++ /dev/null @@ -1,908 +0,0 @@ - - -]> - - - - - How to write a GIMP plug-in, part III - Part III - Write your own - - - - Written By Dave Neary - - - - In the second - part, I told you about manipulating image data by pixel or - row. This time, I will go farther and process data by tile, which - will improve our plug-in performance. I will also update our - algorithm to take larger radius into account, and build a - graphical interface to allow changing that parameter. - - -
- Introduction - - - Let's have a look at our simple algorithm: for each pixel, - generate a (2r+1)x(2r+1) neighbourhood and for each layer, - replace the layer's pixel value with the average value in the - neighbourhood. - - - - It's a bit more complex than that - we have to be careful near - image borders for example, but this algorithm makes a blur - effect that is not so bad in general. - - - - But until now, we wrote the algorithm for a 3x3 neighbourhood. - Time has come to generalise this part and to introduce the - radius as a parameter. - - - - First, a word on tiles. - -
- -
- Tile management - - - A tile is an image data block with a 64x64 size. Usually, tiles - are sent to the plug-in on demand one by one, by shared memory. - Of course this process needs huge resources and should be - avoided. - - - - Usually, one doesn't need any particular cache, each tile is - sent when one needs it and freed when one asks for another one. - Nevertheless, we can tell our plug-in to keep a tile cache to - avoid this constant round trip, by calling the function: - - - - - - - - In the second part example, we called gimp_pixel_rgn_get_row() - and gimp_pixel_rgn_set_row() but without using any cache. - - - - The number of tiles in a tile row will be the layer width - divided by the tile width, plus one. So, for a layer width of - 65, we will cache two tiles. As we usually also process shadow - tiles, we can double that number to compute the ideal cache size - for our plug-in. - - - - width / - gimp_tile_width () + 1)); - ]]> - - - - With the cache, our slow plug-in becomes fast. On a 300x300 - selection, our last blur took 3 seconds, but on a 2000x1500 - selection it was much slower - 142 seconds. - - - - Adding the above line of code, things are getting better: 11 - seconds. We still lose transition time when we reach tile - borders, we can go down to 10 seconds when multiplying by 4 - instead of 2 (meaning we cache two tiles rows), but the more - tiles we cache, the more hard disk access we make, which reduce - the time gain at a point. - -
- -
- Algorithm generalisation - - - We can modify the algorithm to take a parameter into account: - radius. With a radius of 3, the neighbourhood of a pixel will be - 7x7, instead of 3x3 with a radius of 1. To achieve this I modify - the previous algorithm: - - allocate space for 2r+1 tile rows - initialise this rows array, taking care of - borders - for each tile row - - for each pixel in the tile row - - compute the neighbourhood average, taking - care of borders - - - get a new tile row and cycle rows - - - - - - - This algorithm is more complex than the last one, because the - average computing will be a O(r²) algorithm. - - - - The modified code to get this behaviour is below. Most of the - work is done in the process_row function. init_mem and shuffle - are there to keep the blur code clean and small. - - - - drawable_id, - &x1, &y1, - &x2, &y2); - width = x2 - x1; - height = y2 - y1; - - channels = gimp_drawable_bpp (drawable->drawable_id); - - /* Allocate a big enough tile cache */ - gimp_tile_cache_ntiles (2 * (drawable->width / - gimp_tile_width () + 1)); - - /* Initialises two PixelRgns, one to read original data, - * and the other to write output data. That second one will - * be merged at the end by the call to - * gimp_drawable_merge_shadow() */ - gimp_pixel_rgn_init (&rgn_in, - drawable, - x1, y1, - width, height, - FALSE, FALSE); - gimp_pixel_rgn_init (&rgn_out, - drawable, - x1, y1, - width, height, - TRUE, TRUE); - - /* Allocate memory for input and output tile rows */ - init_mem (&row, &outrow, width * channels); - - for (ii = -radius; ii <= radius; ii++) - { - gimp_pixel_rgn_get_row (&rgn_in, - row[radius + ii], - x1, y1 + CLAMP (ii, 0, height - 1), - width); - } - - for (i = 0; i < height; i++) - { - /* To be done for each tile row */ - process_row (row, - outrow, - x1, y1, - width, height, - channels, - i); - gimp_pixel_rgn_set_row (&rgn_out, - outrow, - x1, i + y1, - width); - /* shift tile rows to insert the new one at the end */ - shuffle (&rgn_in, - row, - x1, y1, - width, height, - i); - if (i % 10 == 0) - gimp_progress_update ((gdouble) i / (gdouble) height); - } - - /* We could also put that in a separate function but it's - * rather simple */ - for (ii = 0; ii < 2 * radius + 1; ii++) - g_free (row[ii]); - - g_free (row); - g_free (outrow); - - /* Update the modified region */ - gimp_drawable_flush (drawable); - gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); - gimp_drawable_update (drawable->drawable_id, - x1, y1, - width, height); - } - - static void - init_mem (guchar ***row, - guchar **outrow, - gint num_bytes) - { - gint i; - - /* Allocate enough memory for row and outrow */ - *row = g_new (char *, (2 * radius + 1)); - - for (i = -radius; i <= radius; i++) - (*row)[i + radius] = g_new (guchar, num_bytes); - - *outrow = g_new (guchar, num_bytes); - } - - static void - process_row (guchar **row, - guchar *outrow, - gint x1, - gint y1, - gint width, - gint height, - gint channels, - gint i) - { - gint j; - - for (j = 0; j < width; j++) - { - gint k, ii, jj; - gint left = (j - radius), - right = (j + radius); - - /* For each layer, compute the average of the - * (2r+1)x(2r+1) pixels */ - for (k = 0; k < channels; k++) - { - gint sum = 0; - - for (ii = 0; ii < 2 * radius + 1; ii++) - for (jj = left; jj <= right; jj++) - sum += row[ii][channels * CLAMP (jj, 0, width - 1) + k]; - - outrow[channels * j + k] = - sum / (4 * radius * radius + 4 * radius + 1); - } - } - } - - static void - shuffle (GimpPixelRgn *rgn_in, - guchar **row, - gint x1, - gint y1, - gint width, - gint height, - gint ypos) - { - gint i; - guchar *tmp_row; - - /* Get tile row (i + radius + 1) into row[0] */ - gimp_pixel_rgn_get_row (rgn_in, - row[0], - x1, MIN (ypos + radius + y1, y1 + height - 1), - width); - - /* Permute row[i] with row[i-1] and row[0] with row[2r] */ - tmp_row = row[0]; - for (i = 1; i < 2 * radius + 1; i++) - row[i - 1] = row[i]; - row[2 * radius] = tmp_row; - } - ]]> - -
- -
- Adding a graphical interface and saving parameters - - - To let the user modify the radius, or let a non-interactive - script give it as a parameter, we now need to get back to our - run() function and settle some simple things. - - - - First we create a structure to allow saving and returning - options. Usually one does this even for plug-ins with only one - parameter. - - - - - - - - Next, we modify the run() function so that execution modes are - taken into account. In interactive mode and repeat last filter - mode, we try to get the last values used by the gimp_get_data() - function, which takes a unique data identifier as its first - input parameter. Usually, one uses the procedure's name. - - - - Finally, in interactive mode, we add a few lines that will build - the graphical interface allowing options modification. - - - - - -
- -
- The graphical interface - - - I won't detail GTK+ programming as this is done very well in - other places. Our first try will be very simple. We will use the - utility widget of GIMP, the GimpDialog, to create a window with - a header, a numeric control of type GtkSpinButton (associated - with a GtkAdjustment) and its label, nicely framed in a - GtkFrame. - - - - In the following parts, in order to show how easy one can do - such things, I will add a preview in the dialog to show real - time effects of the parameters. - - - - Our final dialog will look like this (tree generated with - Glade): - - - - - - - - - - Glade tree - - - Glade tree - - - - - In The GIMP 2.2, there is a number of widgets that come bundled - with parameters that allow a coherent behaviour, consistent with - GNOME Human Interface Guidelines. GimpPreview also appeared in - 2.2. Let's make a first try without it: - - - - - - - - - Blur dialog - - - - - - vbox), main_vbox); - gtk_widget_show (main_vbox); - - frame = gtk_frame_new (NULL); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER (frame), 6); - - alignment = gtk_alignment_new (0.5, 0.5, 1, 1); - gtk_widget_show (alignment); - gtk_container_add (GTK_CONTAINER (frame), alignment); - gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 6, 6, 6); - - main_hbox = gtk_hbox_new (FALSE, 0); - gtk_widget_show (main_hbox); - gtk_container_add (GTK_CONTAINER (alignment), main_hbox); - - radius_label = gtk_label_new_with_mnemonic ("_Radius:"); - gtk_widget_show (radius_label); - gtk_box_pack_start (GTK_BOX (main_hbox), radius_label, FALSE, FALSE, 6); - gtk_label_set_justify (GTK_LABEL (radius_label), GTK_JUSTIFY_RIGHT); - - spinbutton_adj = gtk_adjustment_new (3, 1, 16, 1, 5, 5); - spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton_adj), 1, 0); - gtk_widget_show (spinbutton); - gtk_box_pack_start (GTK_BOX (main_hbox), spinbutton, FALSE, FALSE, 6); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE); - - frame_label = gtk_label_new ("Modify radius"); - gtk_widget_show (frame_label); - gtk_frame_set_label_widget (GTK_FRAME (frame), frame_label); - gtk_label_set_use_markup (GTK_LABEL (frame_label), TRUE); - - g_signal_connect (spinbutton_adj, "value_changed", - G_CALLBACK (gimp_int_adjustment_update), - &bvals.radius); - gtk_widget_show (dialog); - - run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK); - - gtk_widget_destroy (dialog); - - return run; - } - ]]> - -
- -
- Adding a GimpPreview - - - Adding a GimpPreview is quite easy. First we create a GtkWidget - with gimp_drawable_preview_new(), then we attach an invalidated - signal to it, which will call the blur function to update the - preview. We also add a second parameter to MyBlurVals to - remember the activation state of the preview. - - - - A method to update easily the preview is to add a preview - parameter in the blur function, and if preview is not NULL, to - take GimpPreview limits. So when we call blur from run(), we set - the preview parameter to NULL. - - - - To take GimpPreview limits, we use gimp_preview_get_position() - and gimp_preview_get_size(), so we can generate only what will - be displayed. - - - - To achieve this the right way we'll tune some of the code - we - don't need to update the progress bar while generating the - preview, and we should tell at GimpPixelRgn init time that the - tiles should not be sent back to the core. - - - - Finally, we display the updated preview with the - gimp_drawable_preview_draw_region() function. We get a dialog - box that shows us in real time the plug-in effects. Moreover, - thanks to the GIMP core, our plug-in already takes selections - into account. - - - - - - - - - - Blur dialog, improved - - - Blur dialog, improved - - - - - - - - - - - Blur a selection - - - Blur a selection - - - - - Here are the two functions in their last version: - - - - drawable_id, - &x1, &y1, - &x2, &y2); - width = x2 - x1; - height = y2 - y1; - } - - channels = gimp_drawable_bpp (drawable->drawable_id); - - /* Allocate a big enough tile cache */ - gimp_tile_cache_ntiles (2 * (drawable->width / - gimp_tile_width () + 1)); - - /* Initialises two PixelRgns, one to read original data, - * and the other to write output data. That second one will - * be merged at the end by the call to - * gimp_drawable_merge_shadow() */ - gimp_pixel_rgn_init (&rgn_in, - drawable, - x1, y1, - width, height, - FALSE, FALSE); - gimp_pixel_rgn_init (&rgn_out, - drawable, - x1, y1, - width, height, - preview == NULL, TRUE); - - /* Allocate memory for input and output tile rows */ - init_mem (&row, &outrow, width * channels); - - for (ii = -bvals.radius; ii <= bvals.radius; ii++) - { - gimp_pixel_rgn_get_row (&rgn_in, - row[bvals.radius + ii], - x1, y1 + CLAMP (ii, 0, height - 1), - width); - } - - for (i = 0; i < height; i++) - { - /* To be done for each tile row */ - process_row (row, - outrow, - x1, y1, - width, height, - channels, - i); - gimp_pixel_rgn_set_row (&rgn_out, - outrow, - x1, i + y1, - width); - /* shift tile rows to insert the new one at the end */ - shuffle (&rgn_in, - row, - x1, y1, - width, height, - i); - if (i % 10 == 0 && !preview) - gimp_progress_update ((gdouble) i / (gdouble) height); - } - - for (ii = 0; ii < 2 * bvals.radius + 1; ii++) - g_free (row[ii]); - - g_free (row); - g_free (outrow); - - /* Update the modified region */ - if (preview) - { - gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview), - &rgn_out); - } - else - { - gimp_drawable_flush (drawable); - gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); - gimp_drawable_update (drawable->drawable_id, - x1, y1, - width, height); - } - } - - static gboolean - blur_dialog (GimpDrawable *drawable) - { - GtkWidget *dialog; - GtkWidget *main_vbox; - GtkWidget *main_hbox; - GtkWidget *preview; - GtkWidget *frame; - GtkWidget *radius_label; - GtkWidget *alignment; - GtkWidget *spinbutton; - GtkObject *spinbutton_adj; - GtkWidget *frame_label; - gboolean run; - - gimp_ui_init ("myblur", FALSE); - - dialog = gimp_dialog_new ("My blur", "myblur", - NULL, 0, - gimp_standard_help_func, "plug-in-myblur", - - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_OK, - - NULL); - - main_vbox = gtk_vbox_new (FALSE, 6); - gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox); - gtk_widget_show (main_vbox); - - preview = gimp_drawable_preview_new (drawable, &bvals.preview); - gtk_box_pack_start (GTK_BOX (main_vbox), preview, TRUE, TRUE, 0); - gtk_widget_show (preview); - - frame = gimp_frame_new ("Blur radius"); - gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); - gtk_widget_show (frame); - - alignment = gtk_alignment_new (0.5, 0.5, 1, 1); - gtk_widget_show (alignment); - gtk_container_add (GTK_CONTAINER (frame), alignment); - gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 6, 6, 6); - - main_hbox = gtk_hbox_new (FALSE, 12); - gtk_container_set_border_width (GTK_CONTAINER (main_hbox), 12); - gtk_widget_show (main_hbox); - gtk_container_add (GTK_CONTAINER (alignment), main_hbox); - - radius_label = gtk_label_new_with_mnemonic ("_Radius:"); - gtk_widget_show (radius_label); - gtk_box_pack_start (GTK_BOX (main_hbox), radius_label, FALSE, FALSE, 6); - gtk_label_set_justify (GTK_LABEL (radius_label), GTK_JUSTIFY_RIGHT); - - spinbutton = gimp_spin_button_new (&spinbutton_adj, bvals.radius, - 1, 32, 1, 1, 1, 5, 0); - gtk_box_pack_start (GTK_BOX (main_hbox), spinbutton, FALSE, FALSE, 0); - gtk_widget_show (spinbutton); - - g_signal_connect_swapped (preview, "invalidated", - G_CALLBACK (blur), - drawable); - g_signal_connect_swapped (spinbutton_adj, "value_changed", - G_CALLBACK (gimp_preview_invalidate), - preview); - - blur (drawable, GIMP_PREVIEW (preview)); - - g_signal_connect (spinbutton_adj, "value_changed", - G_CALLBACK (gimp_int_adjustment_update), - &bvals.radius); - gtk_widget_show (dialog); - - run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK); - - gtk_widget_destroy (dialog); - - return run; - } - ]]> - - - - Have a look at the tiled, - UI or - preview blur complete code. - -
- -
- Conclusion - - - In these articles, we saw basic concepts for several aspects of - a GIMP plug-in. We messed with image data treatment through a - simple algorithm, and followed a path that showed us how to - avoid performance problems. Finally, we generalised the - algorithm and added parameters to it, and we used some GIMP - widgets to make a nice user interface. - -
- -
- Thanks - - - Thanks to my wife Anne and to David Odin (preview master) for - helping me while I was writing this article. - -
- -
- - - - - - - - Creative Commons License - - - - - - - This work is licensed under a Creative - Commons Attribution-NonCommercial-ShareAlike 2.5 - License. - -
- -
- diff --git a/writing-a-plug-in/1/architecture-small.png b/writing-a-plug-in/1/architecture-small.png deleted file mode 100644 index 51b1bcd9644fa0a53276463cfdb06cdc4275aba3..0000000000000000000000000000000000000000 Binary files a/writing-a-plug-in/1/architecture-small.png and /dev/null differ diff --git a/writing-a-plug-in/1/architecture.png b/writing-a-plug-in/1/architecture.png deleted file mode 100644 index 6c834fc13c45d3d1bf5fdb0c3329a154157969a5..0000000000000000000000000000000000000000 Binary files a/writing-a-plug-in/1/architecture.png and /dev/null differ diff --git a/writing-a-plug-in/1/hello.c b/writing-a-plug-in/1/hello.c deleted file mode 100644 index 25c59525f09339cee70e30dff6e152b23a9b8c5b..0000000000000000000000000000000000000000 --- a/writing-a-plug-in/1/hello.c +++ /dev/null @@ -1,84 +0,0 @@ -#include - -static void query (void); -static void run (const gchar *name, - gint nparams, - const GimpParam *param, - gint *nreturn_vals, - GimpParam **return_vals); - -GimpPlugInInfo PLUG_IN_INFO = -{ - NULL, - NULL, - query, - run -}; - -MAIN() - -static void -query (void) -{ - static GimpParamDef args[] = - { - { - GIMP_PDB_INT32, - "run-mode", - "Run mode" - }, - { - GIMP_PDB_IMAGE, - "image", - "Input image" - }, - { - GIMP_PDB_DRAWABLE, - "drawable", - "Input drawable" - } - }; - - gimp_install_procedure ( - "plug-in-hello", - "Hello, world!", - "Displays \"Hello, world!\" in a dialog", - "David Neary", - "Copyright David Neary", - "2004", - "_Hello world...", - "RGB*, GRAY*", - GIMP_PLUGIN, - G_N_ELEMENTS (args), 0, - args, NULL); - - gimp_plugin_menu_register ("plug-in-hello", - "/Filters/Misc"); -} - -static void -run (const gchar *name, - gint nparams, - const GimpParam *param, - gint *nreturn_vals, - GimpParam **return_vals) -{ - static GimpParam values[1]; - GimpPDBStatusType status = GIMP_PDB_SUCCESS; - GimpRunMode run_mode; - - /* Setting mandatory output values */ - *nreturn_vals = 1; - *return_vals = values; - - values[0].type = GIMP_PDB_STATUS; - values[0].data.d_status = status; - - /* Getting run_mode - we won't display a dialog if - * we are in NONINTERACTIVE mode */ - run_mode = param[0].data.d_int32; - - if (run_mode != GIMP_RUN_NONINTERACTIVE) - g_message("Hello, world!\n"); -} - diff --git a/writing-a-plug-in/1/hello.png b/writing-a-plug-in/1/hello.png deleted file mode 100644 index 2a04996cd661187cc229adb093d4b9a83b23f6c6..0000000000000000000000000000000000000000 Binary files a/writing-a-plug-in/1/hello.png and /dev/null differ diff --git a/writing-a-plug-in/1/plug-in-details-small.png b/writing-a-plug-in/1/plug-in-details-small.png deleted file mode 100644 index 77241b46e9987521b8ad866d8bd037104f4c4140..0000000000000000000000000000000000000000 Binary files a/writing-a-plug-in/1/plug-in-details-small.png and /dev/null differ diff --git a/writing-a-plug-in/1/plug-in-details.png b/writing-a-plug-in/1/plug-in-details.png deleted file mode 100644 index b9de1b40581fdfb00eeeea3191da10ebf7797dde..0000000000000000000000000000000000000000 Binary files a/writing-a-plug-in/1/plug-in-details.png and /dev/null differ diff --git a/writing-a-plug-in/1/plug-in-menu-small.png b/writing-a-plug-in/1/plug-in-menu-small.png deleted file mode 100644 index 36442c94474d65fbf1aff0eba48db46e001b9499..0000000000000000000000000000000000000000 Binary files a/writing-a-plug-in/1/plug-in-menu-small.png and /dev/null differ diff --git a/writing-a-plug-in/1/plug-in-menu.png b/writing-a-plug-in/1/plug-in-menu.png deleted file mode 100644 index bb14d2a871107ac9f672025cb6c5e04d1f5d0e8b..0000000000000000000000000000000000000000 Binary files a/writing-a-plug-in/1/plug-in-menu.png and /dev/null differ diff --git a/writing-a-plug-in/2/GimpImage-small.png b/writing-a-plug-in/2/GimpImage-small.png deleted file mode 100644 index 0bbddf9367abebb021e4b6b6a4f2c323da82835c..0000000000000000000000000000000000000000 Binary files a/writing-a-plug-in/2/GimpImage-small.png and /dev/null differ diff --git a/writing-a-plug-in/2/GimpImage.png b/writing-a-plug-in/2/GimpImage.png deleted file mode 100644 index 3b7ce0d9ff4d343ea7993166a48e221d4326da51..0000000000000000000000000000000000000000 Binary files a/writing-a-plug-in/2/GimpImage.png and /dev/null differ diff --git a/writing-a-plug-in/2/myblur1.c b/writing-a-plug-in/2/myblur1.c deleted file mode 100644 index 2a7a82a7be2e1bd298c0fda0fb243c22dbd4a72f..0000000000000000000000000000000000000000 --- a/writing-a-plug-in/2/myblur1.c +++ /dev/null @@ -1,197 +0,0 @@ -#include - -static void query (void); -static void run (const gchar *name, - gint nparams, - const GimpParam *param, - gint *nreturn_vals, - GimpParam **return_vals); -static void blur (GimpDrawable *drawable); - -GimpPlugInInfo PLUG_IN_INFO = -{ - NULL, - NULL, - query, - run -}; - -MAIN() - -static void -query (void) -{ - static GimpParamDef args[] = - { - { - GIMP_PDB_INT32, - "run-mode", - "Run mode" - }, - { - GIMP_PDB_IMAGE, - "image", - "Input image" - }, - { - GIMP_PDB_DRAWABLE, - "drawable", - "Input drawable" - } - }; - - gimp_install_procedure ( - "plug-in-myblur1", - "My blur 1 (slow)", - "Blurs the image", - "David Neary", - "Copyright David Neary", - "2004", - "_My blur 1 (slow)", - "RGB*, GRAY*", - GIMP_PLUGIN, - G_N_ELEMENTS (args), 0, - args, NULL); - - gimp_plugin_menu_register ("plug-in-myblur1", - "/Filters/Blur"); -} - -static void -run (const gchar *name, - gint nparams, - const GimpParam *param, - gint *nreturn_vals, - GimpParam **return_vals) -{ - static GimpParam values[1]; - GimpPDBStatusType status = GIMP_PDB_SUCCESS; - GimpRunMode run_mode; - GimpDrawable *drawable; - - /* Setting mandatory output values */ - *nreturn_vals = 1; - *return_vals = values; - - values[0].type = GIMP_PDB_STATUS; - values[0].data.d_status = status; - - /* Getting run_mode - we won't display a dialog if - * we are in NONINTERACTIVE mode - */ - run_mode = param[0].data.d_int32; - - /* Get the specified drawable */ - drawable = gimp_drawable_get (param[2].data.d_drawable); - - gimp_progress_init ("My Blur..."); - - /* Let's time blur - * - * GTimer timer = g_timer_new time (); - */ - - blur (drawable); - - /* g_print ("blur() took %g seconds.\n", g_timer_elapsed (timer)); - * g_timer_destroy (timer); - */ - - gimp_displays_flush (); - gimp_drawable_detach (drawable); -} - -static void -blur (GimpDrawable *drawable) -{ - gint i, j, k, channels; - gint x1, y1, x2, y2; - GimpPixelRgn rgn_in, rgn_out; - guchar output[4]; - - /* Gets upper left and lower right coordinates, - * and layers number in the image */ - gimp_drawable_mask_bounds (drawable->drawable_id, - &x1, &y1, - &x2, &y2); - channels = gimp_drawable_bpp (drawable->drawable_id); - - /* Initialises two PixelRgns, one to read original data, - * and the other to write output data. That second one will - * be merged at the end by the call to - * gimp_drawable_merge_shadow() */ - gimp_pixel_rgn_init (&rgn_in, - drawable, - x1, y1, - x2 - x1, y2 - y1, - FALSE, FALSE); - gimp_pixel_rgn_init (&rgn_out, - drawable, - x1, y1, - x2 - x1, y2 - y1, - TRUE, TRUE); - - for (i = x1; i < x2; i++) - { - for (j = y1; j < y2; j++) - { - guchar pixel[9][4]; - - /* Get nine pixels */ - gimp_pixel_rgn_get_pixel (&rgn_in, - pixel[0], - MAX (i - 1, x1), MAX (j - 1, y1)); - gimp_pixel_rgn_get_pixel (&rgn_in, - pixel[1], - MAX (i - 1, x1), j); - gimp_pixel_rgn_get_pixel (&rgn_in, - pixel[2], - MAX (i - 1, x1), MIN (j + 1, y2 - 1)); - - gimp_pixel_rgn_get_pixel (&rgn_in, - pixel[3], - i, MAX (j - 1, y1)); - gimp_pixel_rgn_get_pixel (&rgn_in, - pixel[4], - i, j); - gimp_pixel_rgn_get_pixel (&rgn_in, - pixel[5], - i, MIN (j + 1, y2 - 1)); - - gimp_pixel_rgn_get_pixel (&rgn_in, - pixel[6], - MIN (i + 1, x2 - 1), MAX (j - 1, y1)); - gimp_pixel_rgn_get_pixel (&rgn_in, - pixel[7], - MIN (i + 1, x2 - 1), j); - gimp_pixel_rgn_get_pixel (&rgn_in, - pixel[8], - MIN (i + 1, x2 - 1), MIN (j + 1, y2 - 1)); - - /* For each layer, compute the average of the - * nine */ - for (k = 0; k < channels; k++) - { - int tmp, sum = 0; - for (tmp = 0; tmp < 9; tmp++) - sum += pixel[tmp][k]; - output[k] = sum / 9; - } - - gimp_pixel_rgn_set_pixel (&rgn_out, - output, - i, j); - } - - if (i % 10 == 0) - gimp_progress_update ((gdouble) (i - x1) / (gdouble) (x2 - x1)); - } - - /* Update the modified region */ - gimp_drawable_flush (drawable); - gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); - gimp_drawable_update (drawable->drawable_id, - x1, y1, - x2 - x1, y2 - y1); -} - diff --git a/writing-a-plug-in/2/myblur2.c b/writing-a-plug-in/2/myblur2.c deleted file mode 100644 index 3cb8f6361728ebdacc7f2194b625fc13d5b5117a..0000000000000000000000000000000000000000 --- a/writing-a-plug-in/2/myblur2.c +++ /dev/null @@ -1,193 +0,0 @@ -#include - -static void query (void); -static void run (const gchar *name, - gint nparams, - const GimpParam *param, - gint *nreturn_vals, - GimpParam **return_vals); -static void blur (GimpDrawable *drawable); - -GimpPlugInInfo PLUG_IN_INFO = -{ - NULL, - NULL, - query, - run -}; - -MAIN() - -static void -query (void) -{ - static GimpParamDef args[] = - { - { - GIMP_PDB_INT32, - "run-mode", - "Run mode" - }, - { - GIMP_PDB_IMAGE, - "image", - "Input image" - }, - { - GIMP_PDB_DRAWABLE, - "drawable", - "Input drawable" - } - }; - - gimp_install_procedure ( - "plug-in-myblur2", - "My blur 2 (fast)", - "Blurs the image", - "David Neary", - "Copyright David Neary", - "2004", - "_My blur 2 (fast)", - "RGB*, GRAY*", - GIMP_PLUGIN, - G_N_ELEMENTS (args), 0, - args, NULL); - - gimp_plugin_menu_register ("plug-in-myblur2", - "/Filters/Blur"); -} - -static void -run (const gchar *name, - gint nparams, - const GimpParam *param, - gint *nreturn_vals, - GimpParam **return_vals) -{ - static GimpParam values[1]; - GimpPDBStatusType status = GIMP_PDB_SUCCESS; - GimpRunMode run_mode; - GimpDrawable *drawable; - - /* Setting mandatory output values */ - *nreturn_vals = 1; - *return_vals = values; - - values[0].type = GIMP_PDB_STATUS; - values[0].data.d_status = status; - - /* Getting run_mode - we won't display a dialog if - * we are in NONINTERACTIVE mode - */ - run_mode = param[0].data.d_int32; - - /* Get the specified drawable */ - drawable = gimp_drawable_get (param[2].data.d_drawable); - - gimp_progress_init ("My Blur..."); - - /* Let's time blur - * - * GTimer timer = g_timer_new time (); - */ - - blur (drawable); - - /* g_print ("blur() took %g seconds.\n", g_timer_elapsed (timer)); - * g_timer_destroy (timer); - */ - - gimp_displays_flush (); - gimp_drawable_detach (drawable); - - return; -} - -static void -blur (GimpDrawable *drawable) -{ - gint i, j, k, channels; - gint x1, y1, x2, y2; - GimpPixelRgn rgn_in, rgn_out; - guchar *row1, *row2, *row3; - guchar *outrow; - - gimp_drawable_mask_bounds (drawable->drawable_id, - &x1, &y1, - &x2, &y2); - channels = gimp_drawable_bpp (drawable->drawable_id); - - gimp_pixel_rgn_init (&rgn_in, - drawable, - x1, y1, - x2 - x1, y2 - y1, - FALSE, FALSE); - gimp_pixel_rgn_init (&rgn_out, - drawable, - x1, y1, - x2 - x1, y2 - y1, - TRUE, TRUE); - - /* Initialise enough memory for row1, row2, row3, outrow */ - row1 = g_new (guchar, channels * (x2 - x1)); - row2 = g_new (guchar, channels * (x2 - x1)); - row3 = g_new (guchar, channels * (x2 - x1)); - outrow = g_new (guchar, channels * (x2 - x1)); - - for (i = y1; i < y2; i++) - { - /* Get row i-1, i, i+1 */ - gimp_pixel_rgn_get_row (&rgn_in, - row1, - x1, MAX (y1, i - 1), - x2 - x1); - gimp_pixel_rgn_get_row (&rgn_in, - row2, - x1, i, - x2 - x1); - gimp_pixel_rgn_get_row (&rgn_in, - row3, - x1, MIN (y2 - 1, i + 1), - x2 - x1); - - for (j = x1; j < x2; j++) - { - /* For each layer, compute the average of the nine - * pixels */ - for (k = 0; k < channels; k++) - { - int sum = 0; - sum = row1[channels * MAX ((j - 1 - x1), 0) + k] + - row1[channels * (j - x1) + k] + - row1[channels * MIN ((j + 1 - x1), x2 - x1 - 1) + k] + - row2[channels * MAX ((j - 1 - x1), 0) + k] + - row2[channels * (j - x1) + k] + - row2[channels * MIN ((j + 1 - x1), x2 - x1 - 1) + k] + - row3[channels * MAX ((j - 1 - x1), 0) + k] + - row3[channels * (j - x1) + k] + - row3[channels * MIN ((j + 1 - x1), x2 - x1 - 1) + k]; - outrow[channels * (j - x1) + k] = sum / 9; - } - } - - gimp_pixel_rgn_set_row (&rgn_out, - outrow, - x1, i, - x2 - x1); - - if (i % 10 == 0) - gimp_progress_update ((gdouble) (i - y1) / (gdouble) (y2 - y1)); - } - - g_free (row1); - g_free (row2); - g_free (row3); - g_free (outrow); - - gimp_drawable_flush (drawable); - gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); - gimp_drawable_update (drawable->drawable_id, - x1, y1, - x2 - x1, y2 - y1); -} - diff --git a/writing-a-plug-in/2/tiles-small.png b/writing-a-plug-in/2/tiles-small.png deleted file mode 100644 index c22c69ff3f27051b21dc58c3c501f132ce9ce7a1..0000000000000000000000000000000000000000 Binary files a/writing-a-plug-in/2/tiles-small.png and /dev/null differ diff --git a/writing-a-plug-in/2/tiles.png b/writing-a-plug-in/2/tiles.png deleted file mode 100644 index 09c74f40342fe600391f17dcb4736e9dccbde3e5..0000000000000000000000000000000000000000 Binary files a/writing-a-plug-in/2/tiles.png and /dev/null differ diff --git a/writing-a-plug-in/3/blur_dialog1.png b/writing-a-plug-in/3/blur_dialog1.png deleted file mode 100644 index 68b9f5e8be9b52e4e296065dc5b02156b51702bb..0000000000000000000000000000000000000000 Binary files a/writing-a-plug-in/3/blur_dialog1.png and /dev/null differ diff --git a/writing-a-plug-in/3/blur_dialog2-small.png b/writing-a-plug-in/3/blur_dialog2-small.png deleted file mode 100644 index 0f7f223e11b906e2404b7f50d3760281a6bcf460..0000000000000000000000000000000000000000 Binary files a/writing-a-plug-in/3/blur_dialog2-small.png and /dev/null differ diff --git a/writing-a-plug-in/3/blur_dialog2.png b/writing-a-plug-in/3/blur_dialog2.png deleted file mode 100644 index 09fbd1497efe3ae1762a78753ade73067872eab9..0000000000000000000000000000000000000000 Binary files a/writing-a-plug-in/3/blur_dialog2.png and /dev/null differ diff --git a/writing-a-plug-in/3/blur_select-small.png b/writing-a-plug-in/3/blur_select-small.png deleted file mode 100644 index 057b331f783ce1e8e046faaf1308de2a758f568f..0000000000000000000000000000000000000000 Binary files a/writing-a-plug-in/3/blur_select-small.png and /dev/null differ diff --git a/writing-a-plug-in/3/blur_select.png b/writing-a-plug-in/3/blur_select.png deleted file mode 100644 index 934bc53873e7f7f9421f283ecb68dca711943d45..0000000000000000000000000000000000000000 Binary files a/writing-a-plug-in/3/blur_select.png and /dev/null differ diff --git a/writing-a-plug-in/3/glade-tree-small.png b/writing-a-plug-in/3/glade-tree-small.png deleted file mode 100644 index bfe6b07aa34b86712207dec6843b42a20b092480..0000000000000000000000000000000000000000 Binary files a/writing-a-plug-in/3/glade-tree-small.png and /dev/null differ diff --git a/writing-a-plug-in/3/glade-tree.png b/writing-a-plug-in/3/glade-tree.png deleted file mode 100644 index d5bceb0c9e31861aec0fc42ba6effaff764646d4..0000000000000000000000000000000000000000 Binary files a/writing-a-plug-in/3/glade-tree.png and /dev/null differ diff --git a/writing-a-plug-in/3/myblur3.c b/writing-a-plug-in/3/myblur3.c deleted file mode 100644 index ded310d84de7f2b7be2334bf9629e7f821c81301..0000000000000000000000000000000000000000 --- a/writing-a-plug-in/3/myblur3.c +++ /dev/null @@ -1,282 +0,0 @@ -#include - -static void query (void); -static void run (const gchar *name, - gint nparams, - const GimpParam *param, - gint *nreturn_vals, - GimpParam **return_vals); - -static void blur (GimpDrawable *drawable); - -static void init_mem (guchar ***row, - guchar **outrow, - gint num_bytes); -static void process_row (guchar **row, - guchar *outrow, - gint x1, - gint y1, - gint width, - gint height, - gint channels, - gint i); -static void shuffle (GimpPixelRgn *rgn_in, - guchar **row, - gint x1, - gint y1, - gint width, - gint height, - gint ypos); - -/* The radius is still a constant, we'll change that when the - * graphical interface will be built. */ -static gint radius = 3; - -GimpPlugInInfo PLUG_IN_INFO = -{ - NULL, - NULL, - query, - run -}; - -MAIN() - -static void -query (void) -{ - static GimpParamDef args[] = - { - { - GIMP_PDB_INT32, - "run-mode", - "Run mode" - }, - { - GIMP_PDB_IMAGE, - "image", - "Input image" - }, - { - GIMP_PDB_DRAWABLE, - "drawable", - "Input drawable" - } - }; - - gimp_install_procedure ( - "plug-in-myblur3", - "My blur 3 (tiled)", - "Blurs the image", - "David Neary", - "Copyright David Neary", - "2004", - "_My blur 3 (tiled)", - "RGB*, GRAY*", - GIMP_PLUGIN, - G_N_ELEMENTS (args), 0, - args, NULL); - - gimp_plugin_menu_register ("plug-in-myblur3", - "/Filters/Blur"); -} - -static void -run (const gchar *name, - gint nparams, - const GimpParam *param, - gint *nreturn_vals, - GimpParam **return_vals) -{ - static GimpParam values[1]; - GimpPDBStatusType status = GIMP_PDB_SUCCESS; - GimpRunMode run_mode; - GimpDrawable *drawable; - - /* Setting mandatory output values */ - *nreturn_vals = 1; - *return_vals = values; - - values[0].type = GIMP_PDB_STATUS; - values[0].data.d_status = status; - - /* Getting run_mode - we won't display a dialog if - * we are in NONINTERACTIVE mode */ - run_mode = param[0].data.d_int32; - - /* Get the specified drawable */ - drawable = gimp_drawable_get (param[2].data.d_drawable); - - blur (drawable); - - gimp_displays_flush (); - gimp_drawable_detach (drawable); - - return; -} - -static void -blur (GimpDrawable *drawable) -{ - gint i, ii, channels; - gint x1, y1, x2, y2; - GimpPixelRgn rgn_in, rgn_out; - guchar **row; - guchar *outrow; - gint width, height; - - gimp_progress_init ("My Blur..."); - - /* Gets upper left and lower right coordinates, - * and layers number in the image */ - gimp_drawable_mask_bounds (drawable->drawable_id, - &x1, &y1, - &x2, &y2); - width = x2 - x1; - height = y2 - y1; - - channels = gimp_drawable_bpp (drawable->drawable_id); - - /* Allocate a big enough tile cache */ - gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1)); - - /* Initialises two PixelRgns, one to read original data, - * and the other to write output data. That second one will - * be merged at the end by the call to - * gimp_drawable_merge_shadow() */ - gimp_pixel_rgn_init (&rgn_in, - drawable, - x1, y1, - width, height, - FALSE, FALSE); - gimp_pixel_rgn_init (&rgn_out, - drawable, - x1, y1, - width, height, - TRUE, TRUE); - - /* Allocate memory for input and output tile rows */ - init_mem (&row, &outrow, width * channels); - - for (ii = -radius; ii <= radius; ii++) - { - gimp_pixel_rgn_get_row (&rgn_in, - row[radius + ii], - x1, y1 + CLAMP (ii, 0, height - 1), - width); - } - - for (i = 0; i < height; i++) - { - /* To be done for each tile row */ - process_row (row, - outrow, - x1, y1, - width, height, - channels, - i); - gimp_pixel_rgn_set_row (&rgn_out, - outrow, - x1, i + y1, - width); - /* shift tile rows to insert the new one at the end */ - shuffle (&rgn_in, - row, - x1, y1, - width, height, - i); - if (i % 10 == 0) - gimp_progress_update ((gdouble) i / (gdouble) height); - } - - /* We could also put that in a separate function but it's - * rather simple */ - for (ii = 0; ii < 2 * radius + 1; ii++) - g_free (row[ii]); - - g_free (row); - g_free (outrow); - - /* Update the modified region */ - gimp_drawable_flush (drawable); - gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); - gimp_drawable_update (drawable->drawable_id, - x1, y1, - width, height); -} - -static void -init_mem (guchar ***row, - guchar **outrow, - gint num_bytes) -{ - gint i; - - /* Allocate enough memory for row and outrow */ - *row = g_new (guchar *, (2 * radius + 1)); - - for (i = -radius; i <= radius; i++) - (*row)[i + radius] = g_new (guchar, num_bytes); - - *outrow = g_new (guchar, num_bytes); -} - -static void -process_row (guchar **row, - guchar *outrow, - gint x1, - gint y1, - gint width, - gint height, - gint channels, - gint i) -{ - gint j; - - for (j = 0; j < width; j++) - { - gint k, ii, jj; - gint left = (j - radius), - right = (j + radius); - - /* For each layer, compute the average of the - * (2r+1)x(2r+1) pixels */ - for (k = 0; k < channels; k++) - { - gint sum = 0; - - for (ii = 0; ii < 2 * radius + 1; ii++) - for (jj = left; jj <= right; jj++) - sum += row[ii][channels * CLAMP (jj, 0, width - 1) + k]; - - outrow[channels * j + k] = - sum / (4 * radius * radius + 4 * radius + 1); - } - } -} - -static void -shuffle (GimpPixelRgn *rgn_in, - guchar **row, - gint x1, - gint y1, - gint width, - gint height, - gint ypos) -{ - gint i; - guchar *tmp_row; - - /* Get tile row (i + radius + 1) into row[0] */ - gimp_pixel_rgn_get_row (rgn_in, - row[0], - x1, MIN (ypos + radius + y1, y1 + height - 1), - width); - - /* Permute row[i] with row[i-1] and row[0] with row[2r] */ - tmp_row = row[0]; - for (i = 1; i < 2 * radius + 1; i++) - row[i - 1] = row[i]; - row[2 * radius] = tmp_row; -} - diff --git a/writing-a-plug-in/3/myblur4.c b/writing-a-plug-in/3/myblur4.c deleted file mode 100644 index 077ce66ba056fc0a66d2794583d22dc61a6d2f20..0000000000000000000000000000000000000000 --- a/writing-a-plug-in/3/myblur4.c +++ /dev/null @@ -1,394 +0,0 @@ -#include -#include - -typedef struct -{ - gint radius; -} MyBlurVals; - -static void query (void); -static void run (const gchar *name, - gint nparams, - const GimpParam *param, - gint *nreturn_vals, - GimpParam **return_vals); - -static void blur (GimpDrawable *drawable); - -static void init_mem (guchar ***row, - guchar **outrow, - gint num_bytes); -static void process_row (guchar **row, - guchar *outrow, - gint x1, - gint y1, - gint width, - gint height, - gint channels, - gint i); -static void shuffle (GimpPixelRgn *rgn_in, - guchar **row, - gint x1, - gint y1, - gint width, - gint height, - gint ypos); - -static gboolean blur_dialog (GimpDrawable *drawable); - -/* Set up default values for options */ -static MyBlurVals bvals = -{ - 3 /* radius */ -}; - -GimpPlugInInfo PLUG_IN_INFO = -{ - NULL, - NULL, - query, - run -}; - -MAIN() - -static void -query (void) -{ - static GimpParamDef args[] = - { - { - GIMP_PDB_INT32, - "run-mode", - "Run mode" - }, - { - GIMP_PDB_IMAGE, - "image", - "Input image" - }, - { - GIMP_PDB_DRAWABLE, - "drawable", - "Input drawable" - } - }; - - gimp_install_procedure ( - "plug-in-myblur4", - "My blur 4 (UI)", - "Blurs the image", - "David Neary", - "Copyright David Neary", - "2004", - "_My blur 4 (UI)...", - "RGB*, GRAY*", - GIMP_PLUGIN, - G_N_ELEMENTS (args), 0, - args, NULL); - - gimp_plugin_menu_register ("plug-in-myblur4", - "/Filters/Blur"); -} - -static void -run (const gchar *name, - gint nparams, - const GimpParam *param, - gint *nreturn_vals, - GimpParam **return_vals) -{ - static GimpParam values[1]; - GimpPDBStatusType status = GIMP_PDB_SUCCESS; - GimpRunMode run_mode; - GimpDrawable *drawable; - - /* Setting mandatory output values */ - *nreturn_vals = 1; - *return_vals = values; - - values[0].type = GIMP_PDB_STATUS; - values[0].data.d_status = status; - - /* Getting run_mode - we won't display a dialog if - * we are in NONINTERACTIVE mode */ - run_mode = param[0].data.d_int32; - - /* Get the specified drawable */ - drawable = gimp_drawable_get (param[2].data.d_drawable); - - switch (run_mode) - { - case GIMP_RUN_INTERACTIVE: - /* Get options last values if needed */ - gimp_get_data ("plug-in-myblur", &bvals); - - /* Display the dialog */ - if (! blur_dialog (drawable)) - return; - break; - - case GIMP_RUN_NONINTERACTIVE: - if (nparams != 4) - status = GIMP_PDB_CALLING_ERROR; - if (status == GIMP_PDB_SUCCESS) - bvals.radius = param[3].data.d_int32; - break; - - case GIMP_RUN_WITH_LAST_VALS: - /* Get options last values if needed */ - gimp_get_data ("plug-in-myblur", &bvals); - break; - - default: - break; - } - - blur (drawable); - - gimp_displays_flush (); - gimp_drawable_detach (drawable); - - /* Finally, set options in the core */ - if (run_mode == GIMP_RUN_INTERACTIVE) - gimp_set_data ("plug-in-myblur", &bvals, sizeof (MyBlurVals)); - - return; -} - -static void -blur (GimpDrawable *drawable) -{ - gint i, ii, channels; - gint x1, y1, x2, y2; - GimpPixelRgn rgn_in, rgn_out; - guchar **row; - guchar *outrow; - gint width, height; - - gimp_progress_init ("My Blur..."); - - /* Gets upper left and lower right coordinates, - * and layers number in the image */ - gimp_drawable_mask_bounds (drawable->drawable_id, - &x1, &y1, - &x2, &y2); - width = x2 - x1; - height = y2 - y1; - - channels = gimp_drawable_bpp (drawable->drawable_id); - - /* Allocate a big enough tile cache */ - gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1)); - - /* Initialises two PixelRgns, one to read original data, - * and the other to write output data. That second one will - * be merged at the end by the call to - * gimp_drawable_merge_shadow() */ - gimp_pixel_rgn_init (&rgn_in, - drawable, - x1, y1, - width, height, - FALSE, FALSE); - gimp_pixel_rgn_init (&rgn_out, - drawable, - x1, y1, - width, height, - TRUE, TRUE); - - /* Allocate memory for input and output tile rows */ - init_mem (&row, &outrow, width * channels); - - for (ii = -bvals.radius; ii <= bvals.radius; ii++) - { - gimp_pixel_rgn_get_row (&rgn_in, - row[bvals.radius + ii], - x1, y1 + CLAMP (ii, 0, height - 1), - width); - } - - for (i = 0; i < height; i++) - { - /* To be done for each tile row */ - process_row (row, - outrow, - x1, y1, - width, height, - channels, - i); - gimp_pixel_rgn_set_row (&rgn_out, - outrow, - x1, i + y1, - width); - /* shift tile rows to insert the new one at the end */ - shuffle (&rgn_in, - row, - x1, y1, - width, height, - i); - if (i % 10 == 0) - gimp_progress_update ((gdouble) i / (gdouble) height); - } - - /* We could also put that in a separate function but it's - * rather simple */ - for (ii = 0; ii < 2 * bvals.radius + 1; ii++) - g_free (row[ii]); - - g_free (row); - g_free (outrow); - - /* Update the modified region */ - gimp_drawable_flush (drawable); - gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); - gimp_drawable_update (drawable->drawable_id, - x1, y1, - width, height); -} - -static void -init_mem (guchar ***row, - guchar **outrow, - gint num_bytes) -{ - gint i; - - /* Allocate enough memory for row and outrow */ - *row = g_new (guchar *, (2 * bvals.radius + 1)); - - for (i = -bvals.radius; i <= bvals.radius; i++) - (*row)[i + bvals.radius] = g_new (guchar, num_bytes); - - *outrow = g_new (guchar, num_bytes); -} - -static void -process_row (guchar **row, - guchar *outrow, - gint x1, - gint y1, - gint width, - gint height, - gint channels, - gint i) -{ - gint j; - - for (j = 0; j < width; j++) - { - gint k, ii, jj; - gint left = (j - bvals.radius), - right = (j + bvals.radius); - - /* For each layer, compute the average of the - * (2r+1)x(2r+1) pixels */ - for (k = 0; k < channels; k++) - { - gint sum = 0; - - for (ii = 0; ii < 2 * bvals.radius + 1; ii++) - for (jj = left; jj <= right; jj++) - sum += row[ii][channels * CLAMP (jj, 0, width - 1) + k]; - - outrow[channels * j + k] = - sum / (4 * bvals.radius * bvals.radius + 4 * bvals.radius + 1); - } - } -} - -static void -shuffle (GimpPixelRgn *rgn_in, - guchar **row, - gint x1, - gint y1, - gint width, - gint height, - gint ypos) -{ - gint i; - guchar *tmp_row; - - /* Get tile row (i + radius + 1) into row[0] */ - gimp_pixel_rgn_get_row (rgn_in, - row[0], - x1, MIN (ypos + bvals.radius + y1, y1 + height - 1), - width); - - /* Permute row[i] with row[i-1] and row[0] with row[2r] */ - tmp_row = row[0]; - for (i = 1; i < 2 * bvals.radius + 1; i++) - row[i - 1] = row[i]; - row[2 * bvals.radius] = tmp_row; -} - -static gboolean -blur_dialog (GimpDrawable *drawable) -{ - GtkWidget *dialog; - GtkWidget *main_vbox; - GtkWidget *main_hbox; - GtkWidget *frame; - GtkWidget *radius_label; - GtkWidget *alignment; - GtkWidget *spinbutton; - GtkObject *spinbutton_adj; - GtkWidget *frame_label; - gboolean run; - - gimp_ui_init ("myblur", FALSE); - - dialog = gimp_dialog_new ("My blur", "myblur", - NULL, 0, - gimp_standard_help_func, "plug-in-myblur", - - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_OK, - - NULL); - - main_vbox = gtk_vbox_new (FALSE, 6); - gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox); - gtk_widget_show (main_vbox); - - frame = gtk_frame_new (NULL); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER (frame), 6); - - alignment = gtk_alignment_new (0.5, 0.5, 1, 1); - gtk_widget_show (alignment); - gtk_container_add (GTK_CONTAINER (frame), alignment); - gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 6, 6, 6); - - main_hbox = gtk_hbox_new (FALSE, 0); - gtk_widget_show (main_hbox); - gtk_container_add (GTK_CONTAINER (alignment), main_hbox); - - radius_label = gtk_label_new_with_mnemonic ("_Radius:"); - gtk_widget_show (radius_label); - gtk_box_pack_start (GTK_BOX (main_hbox), radius_label, FALSE, FALSE, 6); - gtk_label_set_justify (GTK_LABEL (radius_label), GTK_JUSTIFY_RIGHT); - - spinbutton_adj = gtk_adjustment_new (3, 1, 16, 1, 5, 5); - spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton_adj), 1, 0); - gtk_widget_show (spinbutton); - gtk_box_pack_start (GTK_BOX (main_hbox), spinbutton, FALSE, FALSE, 6); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE); - - frame_label = gtk_label_new ("Modify radius"); - gtk_widget_show (frame_label); - gtk_frame_set_label_widget (GTK_FRAME (frame), frame_label); - gtk_label_set_use_markup (GTK_LABEL (frame_label), TRUE); - - g_signal_connect (spinbutton_adj, "value_changed", - G_CALLBACK (gimp_int_adjustment_update), - &bvals.radius); - gtk_widget_show (dialog); - - run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK); - - gtk_widget_destroy (dialog); - - return run; -} - diff --git a/writing-a-plug-in/3/myblur5.c b/writing-a-plug-in/3/myblur5.c deleted file mode 100644 index fadbabc8af73cef0c497f6fa7d83db27a6941ff6..0000000000000000000000000000000000000000 --- a/writing-a-plug-in/3/myblur5.c +++ /dev/null @@ -1,431 +0,0 @@ -#include -#include - -typedef struct -{ - gint radius; - gboolean preview; -} MyBlurVals; - -static void query (void); -static void run (const gchar *name, - gint nparams, - const GimpParam *param, - gint *nreturn_vals, - GimpParam **return_vals); - -static void blur (GimpDrawable *drawable, - GimpPreview *preview); - -static void init_mem (guchar ***row, - guchar **outrow, - gint num_bytes); -static void process_row (guchar **row, - guchar *outrow, - gint x1, - gint y1, - gint width, - gint height, - gint channels, - gint i); -static void shuffle (GimpPixelRgn *rgn_in, - guchar **row, - gint x1, - gint y1, - gint width, - gint height, - gint ypos); - -static gboolean blur_dialog (GimpDrawable *drawable); - -/* Set up default values for options */ -static MyBlurVals bvals = -{ - 3, /* radius */ - 1 /* preview */ -}; - -GimpPlugInInfo PLUG_IN_INFO = -{ - NULL, - NULL, - query, - run -}; - -MAIN() - -static void -query (void) -{ - static GimpParamDef args[] = - { - { - GIMP_PDB_INT32, - "run-mode", - "Run mode" - }, - { - GIMP_PDB_IMAGE, - "image", - "Input image" - }, - { - GIMP_PDB_DRAWABLE, - "drawable", - "Input drawable" - } - }; - - gimp_install_procedure ( - "plug-in-myblur5", - "My blur 5 (preview)", - "Blurs the image", - "David Neary", - "Copyright David Neary", - "2004", - "_My blur 5 (preview)...", - "RGB*, GRAY*", - GIMP_PLUGIN, - G_N_ELEMENTS (args), 0, - args, NULL); - - gimp_plugin_menu_register ("plug-in-myblur5", - "/Filters/Blur"); -} - -static void -run (const gchar *name, - gint nparams, - const GimpParam *param, - gint *nreturn_vals, - GimpParam **return_vals) -{ - static GimpParam values[1]; - GimpPDBStatusType status = GIMP_PDB_SUCCESS; - GimpRunMode run_mode; - GimpDrawable *drawable; - - /* Setting mandatory output values */ - *nreturn_vals = 1; - *return_vals = values; - - values[0].type = GIMP_PDB_STATUS; - values[0].data.d_status = status; - - /* Getting run_mode - we won't display a dialog if - * we are in NONINTERACTIVE mode */ - run_mode = param[0].data.d_int32; - - /* Get the specified drawable */ - drawable = gimp_drawable_get (param[2].data.d_drawable); - - switch (run_mode) - { - case GIMP_RUN_INTERACTIVE: - /* Get options last values if needed */ - gimp_get_data ("plug-in-myblur", &bvals); - - /* Display the dialog */ - if (! blur_dialog (drawable)) - return; - break; - - case GIMP_RUN_NONINTERACTIVE: - if (nparams != 4) - status = GIMP_PDB_CALLING_ERROR; - if (status == GIMP_PDB_SUCCESS) - bvals.radius = param[3].data.d_int32; - break; - - case GIMP_RUN_WITH_LAST_VALS: - /* Get options last values if needed */ - gimp_get_data ("plug-in-myblur", &bvals); - break; - - default: - break; - } - - blur (drawable, NULL); - - gimp_displays_flush (); - gimp_drawable_detach (drawable); - - /* Finally, set options in the core */ - if (run_mode == GIMP_RUN_INTERACTIVE) - gimp_set_data ("plug-in-myblur", &bvals, sizeof (MyBlurVals)); - - return; -} - -static void -blur (GimpDrawable *drawable, - GimpPreview *preview) -{ - gint i, ii, channels; - gint x1, y1, x2, y2; - GimpPixelRgn rgn_in, rgn_out; - guchar **row; - guchar *outrow; - gint width, height; - - if (! preview) - gimp_progress_init ("My Blur..."); - - /* Gets upper left and lower right coordinates, - * and layers number in the image */ - if (preview) - { - gimp_preview_get_position (preview, &x1, &y1); - gimp_preview_get_size (preview, &width, &height); - x2 = x1 + width; - y2 = y1 + height; - } - else - { - gimp_drawable_mask_bounds (drawable->drawable_id, - &x1, &y1, - &x2, &y2); - width = x2 - x1; - height = y2 - y1; - } - - channels = gimp_drawable_bpp (drawable->drawable_id); - - /* Allocate a big enough tile cache */ - gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1)); - - /* Initialises two PixelRgns, one to read original data, - * and the other to write output data. That second one will - * be merged at the end by the call to - * gimp_drawable_merge_shadow() */ - gimp_pixel_rgn_init (&rgn_in, - drawable, - x1, y1, - width, height, - FALSE, FALSE); - gimp_pixel_rgn_init (&rgn_out, - drawable, - x1, y1, - width, height, - preview == NULL, TRUE); - - /* Allocate memory for input and output tile rows */ - init_mem (&row, &outrow, width * channels); - - for (ii = -bvals.radius; ii <= bvals.radius; ii++) - { - gimp_pixel_rgn_get_row (&rgn_in, - row[bvals.radius + ii], - x1, y1 + CLAMP (ii, 0, height - 1), - width); - } - - for (i = 0; i < height; i++) - { - /* To be done for each tile row */ - process_row (row, - outrow, - x1, y1, - width, height, - channels, - i); - gimp_pixel_rgn_set_row (&rgn_out, - outrow, - x1, i + y1, - width); - /* shift tile rows to insert the new one at the end */ - shuffle (&rgn_in, - row, - x1, y1, - width, height, - i); - - if (! preview && i % 16 == 0) - gimp_progress_update ((gdouble) i / (gdouble) height); - } - - /* We could also put that in a separate function but it's - * rather simple */ - for (ii = 0; ii < 2 * bvals.radius + 1; ii++) - g_free (row[ii]); - - g_free (row); - g_free (outrow); - - /* Update the modified region */ - if (preview) - { - gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview), - &rgn_out); - } - else - { - gimp_drawable_flush (drawable); - gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); - gimp_drawable_update (drawable->drawable_id, - x1, y1, - width, height); - } -} - -static void -init_mem (guchar ***row, - guchar **outrow, - gint num_bytes) -{ - gint i; - - /* Allocate enough memory for row and outrow */ - *row = g_new (guchar *, (2 * bvals.radius + 1)); - - for (i = -bvals.radius; i <= bvals.radius; i++) - (*row)[i + bvals.radius] = g_new (guchar, num_bytes); - - *outrow = g_new (guchar, num_bytes); -} - -static void -process_row (guchar **row, - guchar *outrow, - gint x1, - gint y1, - gint width, - gint height, - gint channels, - gint i) -{ - gint j; - - for (j = 0; j < width; j++) - { - gint k, ii, jj; - gint left = (j - bvals.radius), - right = (j + bvals.radius); - - /* For each layer, compute the average of the - * (2r+1)x(2r+1) pixels */ - for (k = 0; k < channels; k++) - { - gint sum = 0; - - for (ii = 0; ii < 2 * bvals.radius + 1; ii++) - for (jj = left; jj <= right; jj++) - sum += row[ii][channels * CLAMP (jj, 0, width - 1) + k]; - - outrow[channels * j + k] = - sum / (4 * bvals.radius * bvals.radius + 4 * bvals.radius + 1); - } - } -} - -static void -shuffle (GimpPixelRgn *rgn_in, - guchar **row, - gint x1, - gint y1, - gint width, - gint height, - gint ypos) -{ - gint i; - guchar *tmp_row; - - /* Get tile row (i + radius + 1) into row[0] */ - gimp_pixel_rgn_get_row (rgn_in, - row[0], - x1, MIN (ypos + bvals.radius + y1, y1 + height - 1), - width); - - /* Permute row[i] with row[i-1] and row[0] with row[2r] */ - tmp_row = row[0]; - for (i = 1; i < 2 * bvals.radius + 1; i++) - row[i - 1] = row[i]; - row[2 * bvals.radius] = tmp_row; -} - -static gboolean -blur_dialog (GimpDrawable *drawable) -{ - GtkWidget *dialog; - GtkWidget *main_vbox; - GtkWidget *main_hbox; - GtkWidget *preview; - GtkWidget *frame; - GtkWidget *radius_label; - GtkWidget *alignment; - GtkWidget *spinbutton; - GtkObject *spinbutton_adj; - GtkWidget *frame_label; - gboolean run; - - gimp_ui_init ("myblur", FALSE); - - dialog = gimp_dialog_new ("My blur", "myblur", - NULL, 0, - gimp_standard_help_func, "plug-in-myblur", - - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_OK, - - NULL); - - main_vbox = gtk_vbox_new (FALSE, 6); - gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox); - gtk_widget_show (main_vbox); - - preview = gimp_drawable_preview_new (drawable, &bvals.preview); - gtk_box_pack_start (GTK_BOX (main_vbox), preview, TRUE, TRUE, 0); - gtk_widget_show (preview); - - frame = gtk_frame_new (NULL); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER (frame), 6); - - alignment = gtk_alignment_new (0.5, 0.5, 1, 1); - gtk_widget_show (alignment); - gtk_container_add (GTK_CONTAINER (frame), alignment); - gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 6, 6, 6); - - main_hbox = gtk_hbox_new (FALSE, 0); - gtk_widget_show (main_hbox); - gtk_container_add (GTK_CONTAINER (alignment), main_hbox); - - radius_label = gtk_label_new_with_mnemonic ("_Radius:"); - gtk_widget_show (radius_label); - gtk_box_pack_start (GTK_BOX (main_hbox), radius_label, FALSE, FALSE, 6); - gtk_label_set_justify (GTK_LABEL (radius_label), GTK_JUSTIFY_RIGHT); - - spinbutton = gimp_spin_button_new (&spinbutton_adj, bvals.radius, - 1, 32, 1, 1, 1, 5, 0); - gtk_box_pack_start (GTK_BOX (main_hbox), spinbutton, FALSE, FALSE, 0); - gtk_widget_show (spinbutton); - - frame_label = gtk_label_new ("Modify radius"); - gtk_widget_show (frame_label); - gtk_frame_set_label_widget (GTK_FRAME (frame), frame_label); - gtk_label_set_use_markup (GTK_LABEL (frame_label), TRUE); - - g_signal_connect_swapped (preview, "invalidated", - G_CALLBACK (blur), - drawable); - g_signal_connect_swapped (spinbutton_adj, "value_changed", - G_CALLBACK (gimp_preview_invalidate), - preview); - - blur (drawable, GIMP_PREVIEW (preview)); - - g_signal_connect (spinbutton_adj, "value_changed", - G_CALLBACK (gimp_int_adjustment_update), - &bvals.radius); - gtk_widget_show (dialog); - - run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK); - - gtk_widget_destroy (dialog); - - return run; -} - diff --git a/xsl/VERSION b/xsl/VERSION deleted file mode 100644 index 7dce21b345488fd18db926295baa9a9c08cfd790..0000000000000000000000000000000000000000 --- a/xsl/VERSION +++ /dev/null @@ -1,5 +0,0 @@ - - -2.4.1 - diff --git a/xsl/autolayout.xsl b/xsl/autolayout.xsl deleted file mode 100644 index c88b8c46e1063ad5223fd05814260c4ad9b3161a..0000000000000000000000000000000000000000 --- a/xsl/autolayout.xsl +++ /dev/null @@ -1,258 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - All toc entries must have a page attribute. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - All toc entries must have an href attribute. - - - - - - All href toc entries must have an id attribute. - - - - - off site: - - - - - - - - - - - - - - - - - - Off-site links must provide a title. - - - - - - - - - - - - - All toc entries must have a page attribute. - - - - - - - - - : missing ID. - - - - - - - - - - - - - - index.html - - - - - - - - - - - : missing filename. - - - - - - : - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <xsl:apply-templates select="$page/*[1]/head/title"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - / - - - - - - - - / - - - - - - - / - - - - - - diff --git a/xsl/chunk-common.xsl b/xsl/chunk-common.xsl deleted file mode 100644 index 83b6afc02442a89b2fe3f9ec4d85f7e0c9c310be..0000000000000000000000000000000000000000 --- a/xsl/chunk-common.xsl +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - Fail: tocentry has both page and href attributes. - - - - - - - - - index.html - - - - - - - - - - - - - - - - - - - - - does not exist. - - - - - - - - does not exist. - - - - - - - - - - - - - - - - - - / - - - - - - - - 0 - - - - 1 - - 0 - - - - - - 1 - - 0 - - - 1 - - - - - - - Update: - - : - - - - - - - - - - - - - - - - - - Up-to-date: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/xsl/chunk-tabular.xsl b/xsl/chunk-tabular.xsl deleted file mode 100644 index 3de75817e660be0923b9bd8c214dba2b47ca84cd..0000000000000000000000000000000000000000 --- a/xsl/chunk-tabular.xsl +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/xsl/chunk-website.xsl b/xsl/chunk-website.xsl deleted file mode 100644 index 44721e274aedc6882d0fabcf012f9e0ec47021b8..0000000000000000000000000000000000000000 --- a/xsl/chunk-website.xsl +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/xsl/head.xsl b/xsl/head.xsl deleted file mode 100644 index 645e84cfe12e4b9c57e68424d294f88350940c7b..0000000000000000000000000000000000000000 --- a/xsl/head.xsl +++ /dev/null @@ -1,299 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <xsl:value-of select="."/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - JavaScript - - - -