Digikam/GSoC2010/NonDestructiveEditing
"Never touch the original"
Use Cases
Jean
Jean takes his photos as JPEG. For selected pictures he makes some color adjustments and often uses levels adjust. The result looks better than the original picture, closer to what he remembers the colors looked like to his eyes. When showing his images to his friends, he wants of course to show the new version and not the original one. But he still likes to keep the original data around. When editing, he wants to quickly make his adjustments and be done. No need to click on "save as" and select a different filename. (He used to choose his filenames in an attempt that he knows which operations he did to improve the picture. He likes his computer to remember this for him).
Lena
Lena is taking snapshots of her friends. Sometimes she likes to play with color effects, charcoal or distortion effects. So from one picture (she shoots JPEG, but is indifferent about this fact) she will create multiple different results, also in different albums (she is also indifferent about in which format these images are stored. But she wants to share them with her friends and upload to facebook). The original photo stays in the album where it is, it's not changed.
Pedro
Pedro shoots RAW. He invests a good deal of time to convert certain RAW images. For others he uses the batch tool. After conversion, he does not like to see two versions for each original image in his albums. Instead, he wants to see the result of his conversion, but of course preserve the raw image. Sometimes, he will try a second conversion from the original RAW with different settings and achieve an alternative result. For storing, he needs lossless 16bit compression. He is using PNG but thinking about PGF. The result of RAW conversion is often kept as is, sometimes he plays with some of digikam's filters. For these operations, he likes to start from the result of RAW conversion and may fork alternative versions from there.
Ian
Ian is interested in panorama stitching and HDR images. He's taking photos dedicated for making a panorama - they are not good photos on their own - and then using hugin to compose them. Afterwards, he is willing to teach digikam (if it's easy enough to do) that he created a panorama from selected pictures, pointing to the new file, and then expects to be asked if the original images shall be hidden afterwards. It's similar for HDR. He is either using QtPfsGui, and later tells digikam what he did. Or he uses the enfuse integration in digikam. In this case, of course, he expects that digikam automatically knows what he did.
Parts needed in the foundation:
- The format to store changes
- Adapting digiKam's plugins and filters
- Storing change information in image metadata and internal database
- Naming scheme for versions of new (modified) images
Parts needed in the UI:
- No more Save/Save As in the image editor, automatically save as new version
- Some sort of menu to choose the image version - original, modified, modified_2 etc.
- Menu/button for exporting the modified image
- Stacks of images (original/current version) in the album icon view --needs some thinking
- Widget to display version history - a tree view with buttons to show information would be nice
Details of foundation parts
1. The format to store changes
- Basically XML file in image metadata (using XMP)
- Use OpenRaster specification as a basepoint for changes description - http://create.freedesktop.org/wiki/OpenRaster
- A changeset (editing operation) will classify into one of these categories:
- Reproducible/Repeatable: when given the set of stored parameters and the original data, an identical result will be produced. (majority of digikam's image plugins)
- Complex: The operation is documented and a number of parameters may be known, but the identical result cannot be reproduced. (strictly, any operation involving random data, like raindrop, distortion, blurfx and filmgrain. Possibly also any operation involving a very complex algorithm, like inpainting or local contrast, where new versions are likely to alter results)
- Documented History: The source images are known, a textual description may be added, but there is no way to automatically replay (typically, editing with external tools like Gimp or panorama stitching. Relation may need to be added manually by the user)
- see below for some thoughts on how to refer to existing files in this format
2. Adapting digiKam's plugins and filters
- We need to have an interface in EditorTool to get the serialized operation that has been applied
- From an image plugin, we need a list of filter names that are supported, and a way to execute a described operation on a given image
- Plugins will have to have unique name composed of filter name and some unique part (as there can be two plugins with same name) and also plugin version will be stored (as newer versions can have different parameters)
- Naming like < ... name="digikam:charcoal-hbr9Gh" version="2" > with version stored as another parameter for better parsing
3. Storing change information in image metadata and internal database
- Use XMP - defining a custom namespace and writing our changes
- Use OpenRaster specification as a basepoint for changes description - http://create.freedesktop.org/wiki/OpenRaster
- Always store the latest version (the current) in a normal file - good for thumbnailing and editing with external apps like Gimp
- If user edits some exotic format or unsupported RAW, or if he edits a read-only file on a read-only device, ask him, where to store the changed file
- Create some small wrapper classes to read/write that format
4. Naming scheme for versions of new (modified) images
- New files will be put next to the original with just modified name
- Names will be without spaces and not a translatable string if possible (because of possible non-ascii chars, which may cause problem on some other systems)
- For example image01.jpg (original), image01_v1.jpg (first version), image01_v2.jpg (second version) and so on
- See below for detailed suggestions
- note the requirement of a "two-dimensional" naming - lines of development (alternative edited versions), and revisions (steps, versions) in this line of development
File storage
- the original is stored, untouched. (if metadata access is allowed, write unique ids of type 1+2, see below)
- A format is selected as "workspace format". By recommendation a lossless format: PGF, PNG, TIFF; if really wanted, also JPEG.
- From any original, multiple lines of development/alternative edited versions can be started. Each of these lines has a current version and optionally intermediate versions stored on disk.
- Language usability problem: what is a version - a full line of development, or a single revision in this line? Need native speaker input.
- Each file on disk records in its metadata all changes leading from the original to itself. The original contains no versioning metadata, the current version all applied operations.
- The current version is always stored on disk in workspace format.
- intermediate revisions are generally not stored, unless necessary; that is, results of "Reproducible" editing operations are not stored, results of "Complex" and "Documented History" operations are optionally stored (setup option, need to decide on default value: Off?)
- special case Raw import: The result is the current version. When downloading RAW+JPEG from a camera, the relation must be recorded. Raw import is a "Complex" operation. When editing this current version, the case is similar to intermediate revisions above, but we should think about a different config option.
- Original and intermediate files on disk are hidden in digikam's UI
How to refer to a file?
- In a format describing changes from an original file over intermediate results to a current version, the previous files need to be uniquely referred to
- for intermediate versions we can expect to be able to write to the metadata. For original images, we cannot guarantee this.
- full-file hashes as used by git are very elegant for version management, but fail in our case: We modify the metadata all the time, changing the hash. For the same reason, the smaller uniqueHash currently in use by digiKam is not suited for this purpose. A hash on only the image pixel data is currently technically not available (and would require support for each image format separately)
- there can be metadata fields with unique ids (Exif.Photo.ImageUniqueId). These can have two different meanings:
- 1) showing that a group of different pictures result from the same original (simplest case, groups a RAW with the corresponding JPEG)
- 2) uniquely identifying a single picture version
- Suggesting a combined approach:
- Use a unique id (type 2), added to the metadata on modification, or, if allowed, on import of original. Caveat: Will not be changed when editing externally.
- Use filename, creationDate or unique id (type 1) for identifying original pictures
Versioning
GUI for managing the versions
- The widget will be placed in editor's sidepanel (that one on the right) under new tab
- Versions will be represented by a list of all versions, starting with the original on the top and all individual versions below, like Gimp's history. Between two particular versions should be a list of all changes that lead to this version. Probably collapsed by default and padded to the right little bit. These changes can be removed (or maybe even moved for different order of execution, but that would lead to discarding all the following versions).
- When some version was forked to another version, there will be a little hint showing from which version this was forked.
- There will be a button for creating new version from the current image.
Versions in library view
- Displayed is the latest version of image
- But also every version, that has been forked off, will be displayed
- Also a button for resetting the image to the original state is needed, which leads to a need to mark the image as changed from original and that the original is available
Format for storing changes
- Each changeset will start with some root element called <history> (some better idea?). Right after history, there will be an element identifying the original image, a <file> tag with properties as child nodes, <param .. />. Afterwards there will be <filter .. > element (same level as <file>, which will identify the used filter. This will have child nodes <param name="" value="" /> for storing the used parameters with the filter.
TODO
- specify details of the format for storing changes
- think more about the UI changes (would be great to involve usability team)
- email Krita mailing-list for their opinion?