SourceForge.net LogoLinuxFund.org Logo
Home Press Mailing List Documentation Screenshots People SourceForge Downloads

The Film Gimp Architecture Plan (FGAP)

Film Gimp is evolving. A team of developers, about twenty at last count, is contributing to that, with each member individually effecting what Film Gimp becomes. Sometimes I'm asked if leading a cooperative open source project isn't impossible because nobody can be ordered to do anything. From my experience with corporate and research university projects I've learned that leadership always requires persuasion. As my department chair used to say when I was a lecturer and research scientist at the Naval Postgraduate School, "Managing programmers is like herding cats". In writing down a plan for Film Gimp my goal is to define a vision, not to tell anyone what to do or limit our options.

What is Film Gimp?

Film Gimp is a paint and image retouching program that today is mainly used for dustbusting, that is, manually cleaning dust off 35mm film scans. The architecture of Film Gimp is a core program, a library of service routines, a procedural database (PDB) with a wire interface, and program resources. Resources include brushes, gradients, palettes, patterns, plug-ins, and scripts. There are rc settings control files for core, gtk, menus, and plug-ins. Fundamental to the core of Film Gimp is the frame buffer, and for scalability that is operated upon as tiles. Film Gimp has its own tile cache.

Film Gimp does not currently support motion picture editing, compositing, morphing, rotoscoping, or blue screen mattes. However, there are ideas in that direction.

Film Gimp seeks to support all popular operating systems including Linux, Macintosh, and Windows.

The Frame Manager

Film Gimp has features and controls comparable to Adobe Photoshop. A significant innovation in the workflow of Film Gimp is the frame manager. The frame manager considers a directory of numbered images to be a movie, and offers the typical movie controls including a Play button and a Next Frame button. That enables users to quickly advance frame-by-frame through a movie made up of scanned high resolution frames, to rapidly retouch frames using the clone tool to copy a region from an adjacent frame to cover an imperfection. Defects being retouched include dust and scratches, wire rig removal (e.g., flying actors), continuity (e.g., removing power lines and overhead aircraft from historicals), and animation errors (e.g., popped seams in NURBS).

Pixels

Pixels in Film Gimp are RGBA at 8-bit, 16-bit integer, and 16-bit float per channel bit depths internally. Although able to read logarithmic Cineon files, Film Gimp converts them internally. Formats such as Radiance HDR (which we can read but writing is missing) could be more efficiently manipulated in native form. Should Film Gimp be able to manipulate using any pixel layout internally without conversions?

Because supporting multiple formats internally is cumbersome in C (using "switch" statements), it is tempting to convert to 32-bit RGBA throughout. However, there can be an efficiency hit to doing that, and there can be truncation of data with log formats. A single-pixel approach also fails to address other color spaces such as CMYK and RGBAZ (laser-ranged Z-map). A more sophisticated approach is C++ templates combined with simple pixel object operators that can implicitly act in any algorithm to perform upon any format in its native form. That is the more desirable and flexible approach, but may be challenging to implement.

C++ Code

Before using C++ templates or other object-oriented design features, Film Gimp must first convert from C to C++. That change is scheduled for February 2003. Conversion to C++ may not be as trivial as some expect because C++ is more strict in interpretation of rules than C, not simply a language superset.

Will future Film Gimp design become more baroque after the C++ conversion? Will programmers inexperienced with C++ go overboard? In C++ there may be ten ways to do the same thing, and some programmers will try to use all ten ways -- missing the point that flexibility enables choosing the best way. Students especially are prone to want to prove they can use every C++ feature available, like a new chef gone wild with every spice in the kitchen spice rack. That result isn't very palatable. For simplicity and efficiency, C++ features need to be employed intelligently and sparingly.

Features of C++ that can improve program clarity without cost include classes (encapsulation), function overloading, and bool. Caution is necessary with inheritance, operator overloading, and templates. Those can impact efficiency, size, and even comprehension of what the code does. RTTI, namespaces, and exceptions should be avoided. RTTI and namespaces are rarely needed, add complexity, and can cause compiler portability problems. Exceptions can be a religious debate. It depends upon whether you believe in termination.

There are three fundamental approaches to handling errors in C++ programs: hope, termination, and limping. The hope system, which unfortunately many programmers became comfortable with in school, is to use no error checking at all. The program crashes or is erratic. Exceptions can prevent that by triggering a condition that must handled. Exceptions are based on the termination theory of program control, that any unexpected error must stop the program. A program that throws an exception can abort. If a second exception occurs as a side-effect of handling the first, the program immediately exits.

Would you embed an abort() call in your code? For academic research programs or batch programs yes you may be happy to do that. However, for professional grade GUI programs to abort isn't very nice. A GUI program such as Film Gimp should limp, that is, disable what's gone wrong and keep going. The user should keep control of when the program exits. This approach demands greater care from programmers. Every error condition needs to be accounted for, every return value checked.

The C++ language has an underservedly bad reputation for executable size compared to C. Avoiding poorly optimized C++ libraries is part of a strategy of preventing program size ballooning when converting to C++ from C. The standard template library (STL) needs to be avoided because of the code size risks inherent to the casual use of templates. There is also a significant learning curve for the STL that we don't want to inflict on every programmer. Another standard library to be avoided is iostream. That may seem shocking with it being the most popular C++ library and commonly used everywhere as a replacement for stdio. Replacing stdio seems very desirable because iostream is typesafe. That avoids difficult to trace stack fault bugs that programmers using printf can too easily create. However, iostream isn't particularly efficient, and it is redundant to carry around both iostream and stdio, which would be inevitable with legacy C code. I'm creating an iostream-like wrapper for stdio that I'm calling iostdio. Including that instead of iostream will grant programmers the most popular subset of the iostream interface but will actually route faked iostream calls into the highly optimized stdio library instead.

Plug-ins

The plug-in architecture in Film Gimp is changing. Traditionally that has used fork/spawn to launch a separate process, with communication between core and plug-in via pipes. This has the advantage that a crash or abort in a plug-in can't crash Film Gimp, but is very inefficient. Using dynamic link libraries is the new architecture -- thus far only in the prototype Windows version of Film Gimp. Using dlls means that many core functions, for instance handling the XCF file format, can become plug-ins. The plug-in architecture change makes Film Gimp a less monolithic design, and the core may over time be pared to just the frame buffer with the rest as plug-ins.

Wire Protocol

Plug-ins communicate with the core using the wire protocol. This is a marshalling protocol that swizzles data to make it travel over a pipe. The marshalling data tells the receiver how to unpack the data into a struct. In the new architecture pipes are dispensed with, and the protocol is read directly from common memory. With dlls, everything is shared common memory and there is no need to use system shared memory. That will help the Mac OS X version of Film Gimp. Inter-process shared memory doesn't work on that platform because Apple didn't implement it. Film Gimp uses system shared memory optionally now to try to improve performance in frame buffer operations. In converting to dlls we will eliminate system shared memory calls.

Procedural Database

At the other end of the wire interface in the core is the PDB. The procedural database exports functions from the core or other plug-ins so that commands coming down the wire will do something. Many exports are missing from the PDB, such as access to the frame manager. Consequently, you can't presently write a plug-in that will handle manipulating a frame sequence. When that is fixed it will be feasible to write a plug-in that manages any other plug-in over a sequence. A user will be able to do an operation to the first frame and last frame of a sequence, and the sequence plug-in could smoothly interpolate that operation across the frames in between.

GUI Design

Film Gimp operations require too many clicks. Film Gimp branched from GIMP 1.0.4 in 1998 and inherited that questionable interface. Pulldown menus differ Film Gimp from GIMP, but It is generally conceded that the interface of Adobe Photoshop is still better. However, there are many complaints about Photoshop also. Aping the Photoshop user interface is not the answer. We have to be better than Photoshop.

Layers and channels are a critical problem. It is way too hard to get at the alpha channel. After finishing the Windows port of Film Gimp (which is now overdue as I write this on February 7, 2003) that is my next burning issue. The new design will employ a "layer of layers" approach to manipulate channels. This architecture will make it easy write on the alpha channel and make channels generally as powerful as layers. Channels will become sub-layers named r, g, b, and a. Layer locking will bring together channels to be one layer again. This design should enable any set of layers to be locked together to act as one.

***More to come, back to Windows porting….


Questions to rower@movieeditor.com
Created February 7, 2003; updated February 7, 2003