1 (edited by AnrDaemon 2016-09-15 05:21:29 am)

Topic: Idea: Extensible scheme for image manipulation syntax.

This is a followup of an IRC conversation concerning image resource extraction from different formats and image layers alignment.

The idea is to introduce unambiguous, extensible pattern to describe image resources to extract, combine and present the desired results.

Current state
Right now, LiteStep offers two conventions to specify an image as visible element of the interface.
1. A resource location scheme, which demands a path to a file of the supported image type (such as BMP or PNG, or other recognized format) or a macro ".extract=<path>[,<number>]" to retrieve icon images from Win32 resources. Some sources mention a ".none" macro to specify absence of an image (i.e. transparent and/or click-through area), but I don't know, if this is a core functionality or module-specific.
2. An image layering scheme "<image resource2>|<image resource1>", allowing to compound (overlay) multiple image sources into a single image.

Issues observed with current state
1. Ambiguity of the ".extract=" macro syntax. The macro definition is split in three parts, where two last can't be reliable distinguished one from another, since the comma symbol is allowed in file names. While this issue is usually solved by quoting the relevant parts of variable value, using extra quoting inside a string (the image resource is defined as quoted string in the configuration file) is undesirable. This complicates parsing and overall make you look in different places to get concise information.
2. Ambiguity of the results of ".extract=" macro. The size of the returned image can be anything from the available range, depends on a number of factors, like availability of image sizes for current display color depth and their ordering (i.e. TeamViewer.exe has 32-16-48 order).
3. Positioning issues when layering. Layers all located at the (0;0) (top-left corner of the image), which often makes results look undesirable in case not all of your image resource have the same size.
4. Imaginary issues, like support for more/different image formats, such as SVG, but the proposal below do consider them as well.

While all of the outlined issues can be worked around by creating copies of the required resource and applying simple transformations (conversion to supported formats, canvas cropping or resizing, image repositioning) to better fit into the desired results, this is extra work, that is tedious and easily automated.
Computers were invented to do the tedious automated work. This proposal outlines the idea of an extensible resource specification, which could help resolve the outlined issues and a number of other.

Summary of the current state analysis
While resource location seems to suffer from numerous issues, resource combination (layering) only appears in one, and can easily be averted by applying simple, easily automated transformations to the resource.

The proposal
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119].

  • 1. Resource location.
    Define the resource location scheme as follows:
    Resource location is

    1. a string containing a path to a file in one of the recognized formats or

    2. a function call (macro), that returns an image context in DIB format.

    Path string (form A) MUST NOT start with a period ("."). If the name of your image located in default LS image folder starts with a period (seriously, why?), specify an absolute path using substitution variable "$LSImageFolder$/.yourstrangepath".

  • Examples of valid path-based locations:

    • "MyIcon.png" (Image location is relative to $LSImageFolder$.)

    • "C:\Windows\Web\Wallpaper\Windows\img0.jpg" (Absolute path.)

    • "$USERPROFILE$\Themes\MyAvatar.jpg" (Image is specified with full path using an environment variable.)

  • Function call (macro, form B) MUST start with a period ("."), following with a macro name, optional macro parameters in parenthesis, and equal sign, following with resource location specifier, to which the function is applied.
    The scheme in ABNF format is

resource = transformation | pathstring
transformation = "." transformation_name [ parameters_list ] "=" resource
parameters_list = "(" transformation_parameters ")"

  • Examples of valid resource transformations:

    • ".extract=C:\Windows\regedit.exe" (Extracts the first available icon from Win32 resource, in implementation-dependent size and color depth.)

    • ".extract(16)=$ICONS$\folders.icl" (Extracts 16'th icon from a library.)
      This is a compatibility break; transitional period will be required to convert themes to a new standard. See below for implementation notes.

    • ".align=.extract(16)=$ICONS$\folders.icl" (Extracted DIB image from previous example is aligned on the current canvas. The specifics of alignment are left to be decided by called function.)

    • ".svg($ResolutionX$x$ResolutionY$ fitheight)=$USERPROFILE$\Themes\ElasticBackground.svg" (The imaginary SVG converter transformation is called to create background image for current monitor resolution with additional restriction to manintain aspect ratio while adapting the image to the specified height.)

  • 2. Resource combination.
    Image resource combination is a process of fusing miltiple images together to create single result.
    Multiple image resources (as defined above) could be combined to form a single result.
    The ABNF syntax for such merge is

combined_resource = overlayresource "|" baseresource
baseresource = resource
overlayresource = resource

  • The product of the combination is an image resource, which can be further merged with other resources, but cannot be transformed (the reasons are actually lexical rather than technical, see implementation notes below).
    In the merge process, baseresource define final dimensions of the combination process. If overlayresource has different dimensions, both resources SHOULD be aligned by the top-left corner, and then cropped to the dimensions of the baseresource.

  • The resource combination can benefit from addition of merge modes. I withdraw this proposal. It could easily be implemented as function calls, with much better precision. I.e.
    "$FolderOverlay$|.darken(70%)=resource|$FolderBackground$" (Apply 70% uniformly filled grey overlay with multiplication transform to some image, then insert it between background and overlay in a simple natural join.)
    "$FolderOverlay$|.darken(overlay)=resource|$FolderBackground$" (Apply the same multiplication transformation using custom image, which will colorize the resource, if overlay is not monochromatic.)
    In both cases, the alpha channels of the resource and the overlay are processed separate from the image, thus avoiding the appearance of bogus half-transparent areas where there was nothing in original resource. Or only making necessary areas transparent, if desired by the theme author.
    The only possible issue with latter example is the unbalanced parenthesis. LS parser SHOULD account for the possbility of inclusion of resource strings into transformation_parameters and keep the parser running until it see the matching closing parenthesis, and assign the string in between them literal to the transformation_parameters.

  • Addendum. Implementation notes

  1. General parsing consideration.
    When parsing image resource string, the string MUST be split by the combination marks first, producing the list of resource location strings ordered as they appear in the string.
    The locations list is then processed starting from the last (base) element.
    Each location string is read from the beginning and transformation functions are extracted to form an ordered list similar to the previous step.
    If opening parenthesis is found within transformation_parameters, the parser should assign it and the remaining of the resource string to the transformation_parameters, up to the first closing parenthesis evenly matching an opening one.
    The list is then processed from the last element, similarly to the combination list.

  2. Transformation implementation requirements.

    • Transformation function MUST be prepared to receive pathstring instead of image resource.

    • Transformation function SHOULD have implementation to receive image resource.

    • Transformation provider MUST clearly specify, if its implementation can accept image resource.

    • Transformation function MUST be able to receive desired image size from calling application.

    • Transformation function MAY ignore passed desired image size.

  3. Extensible interface implementation

    • LiteStep core SHOULD provide interface to register and overload transformation functions.

    • If an external provider is trying to override existing transformation, it MUST provide compatible operational parameters to existing implementation.
      I.e. if provider is trying to register a replacement that is unable to receive image resource, while current implementation claims to be capable, the registration MUST NOT succeed.

    • If any transformation is found when processing resource string, the very first (in processing order, last in reading order) transformation MUST be called with pathstring value without LS trying to access the path by itself.
      This requirement will, to an extent, alleviate the issue of backward compatibility break with .extract macro, as well as allow to implement transformations, that access non-file based resources (i.e. data: URL).

    • transformation_parameters, if present, MUST be passed literal to the transformation function. It is up to called function to interpret parameters, extract literal and numeric values etc.
      Note: It is assumed that normal LiteStep evaluator ($whatever$) is already run over the string in question, before it passed to the image factory, thus additional work is not needed from image builder or transformation function side.

    • If transformation, being unable to process image resource, is called in a context, that require the transformation to accept DIB context, LS core MUST prevent such call and notify the user.

    • LiteStep image builder function SHOULD allow calling applications to specify desired size of an image it return.

    • LiteStep MUST pass the values of desired image size down to every transformation it calls without modification.

    • If transformation provider is calling another transformation recursively, it SHOULD NOT modify the desired size values.

    • The calling application MUST be prepared to receive resource of different size than specified by desired size.

    • If the dimensions of resources before combination or before returning to the caller process is larger than requested by the caller, LS image builder MUST crop the resource to fit within desired dimensions (originating from the top-left corner), but MUST NOT resize it. (i.e. the result of 56x32 must be cropped to 48x32 to fit within 48x48 requested size.)

    • The calling application MUST be prepared to receive resource of different size than specified by desired size.

If anyone have questions after reading this wall 'o text, please post 'em.


Re: Idea: Extensible scheme for image manipulation syntax.

Version 2 is up. Typos cleared, orders cleaned a little.
SHOULD be more… mmm… orderly now.