[Select]

Graphics


Index

 

Image File Render

Introduction

A number of graphics formats are supported natively by RISC OS. JPEG, DrawFiles and Sprites are directly renderable and PNGs are supported through a number of conversion calls. Each of these formats, however, is rendered using slightly different calls. The ImageFileRender module simplifies rendering these (and potentially other third party) image files.

Overview

All graphics formats have two things in common :

  1. They cover a region (even empty files must say what space they cover).
  2. They have a resolution at which they are drawn.

The region they cover is known as the 'bounding box'. For many graphics formats this will be aligned with the origin - for example a bitmap graphic. For others this bounding box may be elsewhere in the image - for example vector formats such as DrawFiles.

The resolution at which they have been drawn describes how accurately the images is stored. Usually this is stored in 'dots per inch' (DPI) along with the image itself. Screen resolution is usually (dependings on the eigenfactors for the screen mode in use) treated as 90 DPI. Some formats may use much more accurate internal representations than this; for example DrawFiles are stored at 2048 DPI.

For the purposes of rendering the image file we ignore the colour depth because the rendering process will generate its results in the most accurate manner possible for output depth.

Images may be rendered using a number of transformation types, allowing them to be rendered to fit a region, to a scale, or using a more general transformation.

Within each image file there may be a number of individual images. These can be accessed by a sequence number which indicates their logical location within the file. The images may be related - as would be the case with frames of an animation - or they may be unrelated - as would be the case with a collection of resources.

When accessing images, additional information may be provided to the renderer which may perform specific operations on the image. This extra data is specific to the renderer and cannot be handled generically.

Technical details

Sequence numbers

Graphics files may contain multiple logical images which may either be frames of an animation, alternate versions, or other image resources. These images are accessed through a sequence number which must be supplied to all images. A sequence number of 0 will render the 'default' image within the file. This may be the first image in some formats, the last in others, or some arbitrary image. A sequence number higher than that of the last image should be treated as the last image. A sequence number of 1 indicates the first image that should be processed.

Rendering quality

Image files may contain data which is more accurate than can be represented by the display. This is usually the case for images at high colour depths and almost always the case for bitmap images. In order to allow some control over the quality of the rendered image (and usually the rendering speed) a 'quality' parameter can be provided to the renderer. This is a value from 1 to a renderer specific limit (with a maximum of 15) and will be bounded to the maximum that the renderer supports. Thus, if the highest quality is required, a value of 15 should be supplied. If the lowest quality is required, a value of 1 should be supplied. In the majority of cases, however, the 'default' will be required. This is a value which the renderer feels is suitable for most operations and does not require excessive processing to complete. To specify the default quality, a value of 0 should be supplied as the quality.

Transformation types

Graphics files may be transformed in a number of ways. This allows us to provide a simpler interface for rendering based on the requirements of the application. At present, there are three transformation types provided by the module :

  1. - Render to fit
  2. - Render scaled
  3. - Render transformed

For all rendering types an x and y origin are supplied from which all operations will be based. This allows the same details to be used for the fit, scale or transform regardless of the images location on the screen.

Render to fit

When rendering to fit, a width and height must be supplied by the application. The image file will be scaled to fit within this region. In addition, a border and angle may be provided to specify an area around the image which should be left clear and to specify the angle through which the image should be rotated.

The fit block has the following structure :

      +0     width
      +4     height
      +8     border (to apply to all edges)
      +12   angle

width, height and border are in OS units. angle is in degrees clockwise, as a 16.16 fixed point value.

As the shape is scaled to fit the size specified the point about which rotation occurs is not important. It can be considered as the centre of the image.

Render scaled

When rendering scaled, a pair of multiplication and division factors should be supplied which describe the scale at which the image should be rendered. The scale block is a standard RISC OS scale block (as used by SpriteExtend)

The scaling block has the following structure :

      +0     x multiplication factor
      +4     y multiplication factor
      +8     x division factor
      +12   y division factor

Render transformed

Rendering images through a transformation matrix is the most flexible method of rendering that the ImageFileRender module provides. Transformation matrices are provided in standard RISC OS tranformation blocks (as used by SpriteExtend, Draw, DrawFile and others).

The transformation has the following structure :

      +0 m00

      +4     m10
      +8     m01
      +12   m11
      +16   m20
      +20   m21

where the matrix is constructed :

      {m00 , m01, 0 }
      {m10 , m11, 0 }
      {m20 , m21, 1 }

m00, m01, m10, and m11 are 16.16 fixed point values. m20 and m21 are 24.8 fixed point values.

Arbitrary transformations

Not all image formats support arbitrary transformations. Because of this, certain formats will be unable to render when a complex transformation is in use. A typical example of such limitations is that of JPEGs. The internal renderer can only render JPEGs as a scaled object. If rotation or other complex transformations are applied to files which are not capable of those transformations an error will be returned.

Clipping

All images will be clipped to the standard graphics rectangles. If an image must not pass outside a region a graphics window should be used. This can be set through a VDU 24 sequence.

Image file origins

Whilst most images are based at the origin, some images will have a bounding box which are not. When the image is rendered 'to fit', the image origin is implicitly ignored. When scaling and transforming however, the origin is maintained and will be scaled with the image itself. Because this can make manipulating such images more complex, this origin offset can be negated by the ImageFileRender module. In this mode, the image can be treated as if it does not have any offset from the origin.

Colour mapping

In order to provide highlighting and other colour manipulation on the image, the ImageFileRender module can use colour mapping functions (as used by SpriteExtend, DrawFile, and ColourTrans). These allow the colours in the image to be manipulated to provide effects such as highlighting or shading.

Extensions for more complex rendering

The operations that can be provided in a generic manner by the ImageFileRender module do not cover the full range of operations that might be applied to every image file format. Because of this extension data may be provided which is specific to the renderer in use. Because each renderer may provide specific data to enable it to render images, and there may be multiple providers of rendering facilities, a 'magic' identifier is allocated to each renderer. This is ensures the the renderer is not given data in a form which it does not understand.

Where a magic identifier is supplied and a suitable renderer is available, it will be used. If no suitable renderer can be found, the last registered renderer will be used. This ensures that the where extension data is used it is passed to the appropriate renderer, and falls back to using the most recent renderer installed.

The extension data block must be word aligned, and the first word contains the magic identifier for the render that it is intended for. The remainder of the extension data block is specific to the renderer in use.

The magic identifier may be any 32bit value, but we recommend that these are registered with 3QD Developments Ltd to ensure that there are no duplicated identifiers. At present, allocations are of the form &6699ccii, where cc indicates the company or individual producing the renderer, and ii is some image format number at the company or individual's discretion.

Sprite file extensions block

When rendering sprite files, by default the first sprite is rendered from the file. This covers the majority of the situations that will be required, but where different sprites are needed the extension block describes which to use. The identifier for the 3QD Developments Ltd sprite renderer is &66990101. The named sprite will only be used when the sequence number is left as 'default'.

      +0     &66990101
      +4     Sprite name, up to 12 characters

Custom renderers

Custom renderers may be registered with the ImageFileRender module. These renderers can provided additional rendering facilities for third party filetypes, or provide additional facilities over those of the standard renderers.

Renderers have four components :

  1. A routine which calculates the bounding box and resolution of an image
  2. A routine which renders an image
  3. A routine which declares fonts in a document (may be omitted)
  4. A routine which returns information about an image

In addition, they provide a number of informational fields which describe the renderers capabilities :

  • The filetype that the renderer applies to
  • The name of the renderer (including the version and author)
  • A flags word that describes the renderers capabilities
  • The renderers 'magic' identifier (or 0 if it provides no special operations)
Renderer name

The renderer name provides details about the renderer in order that diagnostics may be performed and information about the installed renderers is available. The renderer name consists of three, tab (ASCII 9) separated, fields :

  • The renderer name
  • The version number in the form x.xx
  • The authors (or publishers) name
Renderer flags

Not all renderers have the same capabilities, as stated earlier. The flags provide details to ImageFileRender of the capabilities of the renderer. This is a bit field, structured :

   bit 0-1 = Renderer transformation capabilities:
      0 - Renderer cannot draw anything but identity scaling and translation
      1 - Renderer can translate and scale, but scaling must be by identical factors
      2 - Renderer can translate and scale by any values in both axes
      3 - Renderer supports any form of transformation

These bits should be set to the capabilities of the renderer. Attempts to render files of which the capabilities word indicates are not possible by the renderer will be faulted by ImageFileRender module.

      bit 2 = Renderer supports colour mapping

This bit should be set if the renderer can perform colour mapping. If unset, attempts to use colour mapping on this file type will be faulted by ImageFileRender.

      bit 3 = Renderer can draw irregular shapes so must be called to calculate bounding boxes.

This bit should be set if transforming a shape using a complex matrix (eg skew or rotate) may result in a different bounding box than that which would be generated for a rectangular area. If unset, the renderer will be called to calculate the bounds of an identity transform only. ImageFileRender will perform the remainder of the calculations.

If a renderer can only render rectangular areas then leaving this bit clear simplifies the implementation.

      bits 4-7 = Maximum number of 'quality' levels supported (1-15)

The highest quality level which is supported by the renderer. If the quality level requested by a client exceeds this, the renderer will be called with this value.

      bits 8-11 = Default 'quality' level to use (1-15)

Where quality settings are omitted (ie when 'default' quality is selected) the default quality will be passed to the renderer. A value of 0 means that quality levels are ignored.

Services

Service_ImageFileRender_Started (&80D40)
On entry
   R0 = api version (102 at present)
   R1 = &80D40

This service is issued after the ImageFileRender module has initialised. Renderers should register themselves with the module.

Service_ImageFileRender_Dying (&80D41)
On entry
   R0 = api version (102 at present)
   R1 = &80D41

This service is issued as the ImageFileRender module finalises to notify clients that it is no longer providing rendering facilities.

Service_ImageFileRender_RendererChanged (&80D42)
On entry
   R0 = api version (102 at present)
   R1 = &80D42
   R2 = filetype affected

This service is issued when a renderer registers or deregisters with the ImageFileRender module. Clients which have cached details of other renderers should re-read any renderer values necessary after checking whether the filetype matches those which they are interested in.

SWIs

ImageFileRender_Render (&562C0)
On entry
   R0 = rendering flags :
         bits 0-2 = transformation type:
               0 = Render to fit
               1 = Render scaled
               2 = Render transformed
               3-7 = Reserved
         bit 3 = colour mapping function supplied
         bit 4 = ignore document origin
         bit 5 = reserved, must be 0
         bits 6=9 = quality to render at :
               0 = Use default quality
               1 = Lowest quality
               2-14 = Renderer specific values
               15 = Highest quality
         bits 10-16 = reserved for future expansion, must be 0
         bits 17-31 = reserved for future expansion, must be 0
   R1 = filetype
   R2 = pointer to data to render
   R3 = length of data
   R4 = pointer to extension data, or 0 if none
   R5 = image sequence number, or 0 for default image
   R6 = x co-ord for origin
   R7 = y co-ord for origin
   R8 = transformation data
         0. pointer to size
               +0 = width
               +4 = height
               +8 = border to use
               +16 = angle to use (degrees<<16)
               image file origin is ignored
         1. pointer to scale block
               +0 = x mult
               +4 = y mult
               +8 = x div
               +12 = y div
         2. pointer to transformation matrix:
               standard draw transformation matrix format
   R9 = pointer to colour map descriptor
On exit
   All registers preserved

This SWI is used to render an image file.

ImageFileRender_BBox (&562C1)
On entry
   R0 = rendering flags :
         bit 0-2 = transformation type:
               0 = Render to fit
               1 = Render scaled
               2 = Render transformed
               3-7 = Reserved
         bit 3 = reserved, must be 0
         bit 4 = ignore document origin
         bit 5 = return in OS units (otherwise bounding box will be returned in draw units)
         bits 6-31 = reserved, must be 0
   R1 = filetype
   R2 = pointer to data to render
   R3 = length of data
   R4 = pointer to extension data, or 0 if none
   R5 = image sequence number, or 0 for default image
   R6 = pointer to transformation data (see above)
   R7 = pointer to bounding box to fill in

This SWI is used to calculate the bounding box for a transformation operation. As a side effect, it also returns information about the DPI of the image and colour depth.

ImageFileRender_Transform (&562C2)
On entry

R0 = rendering flags :

         bits 0-2 = transformation type:
               0 = Render to fit
               1 = Render scaled
               2 = Render transformed
               3-7 = Reserved
         bit 3 = reserved, must be 0
         bit 4 = ignore document origin
         bits 5-31 = reserved, must be 0
   R1 = filetype
   R2 = pointer to data to render
   R3 = length of data
   R4 = pointer to extension data, or 0 if none
   R5 = image sequence number, or 0 for default image
   R6 = pointer to transformation data (see above)
   R7 = pointer to output transformation block to fill in
On exit
   R0 = x DPI
   R1 = y DPI

This SWI is used to calculate the transformation matrix that would be used for an operation without performing that operation.

ImageFileRender_DeclareFonts (&562C3)
On entry
   R0 = flags (reserved, must be 0)
   R1 = filetype
   R2 = pointer to data to render
   R3 = length of data
   R4 = pointer to extension data, or 0 if none
   R5 = image sequence number
   R6 = flags to pass to PDriver_DeclareFont

This SWI should be used when printing images using the ImageFileRender module before any printing operations begin. Refer to the section 'Declare the fonts your document uses' in the chapter on Printing for more details.

ImageFileRender_Info (&562C4)
On entry
   R0 = flags (reserved, must be 0)
   R1 = filetype
   R2 = pointer to data to render
   R3 = length of data
   R4 = pointer to extension data, or 0 if none
   R5 = image sequence number
   R6 = query type :
         &00000000: Base details
         &00000001-&00000FFF: Reserved for system use
         &00001000-&0000FFFF: Reserved for developers
         &00FF0000-&00FFFFFF: Reserved for private use
         Others reserved for future expansion
   R7 = pointer to query block
   R8 = length of query block
On exit
   R8 = if error returned:
         -length of block required
         or +ve value if length cannot be determined (or was not the error)
         length of block used

This SWI should be used to find out information which is not provided by the generic APIs. It may be used (for example) to read the time between frames for a custom renderer, or to read additional information about the image which would otherwise not be available.

Base details query (0)
   +0 = sequence number
   +4 = x DPI
   +8 = y DPI
   +12 = colour type :
         0  = unspecified colour type (usually 'free' colour selection)
         1 = 1bpp RGB
         2 = 2bpp RGB
         3 = 4bpp RGB
         4 = 8bpp RGB
         5 = 16bpp RGB
         6 = 24bpp RGB
         7 = CMYK
         Others reserved
   +16 = image flags :
         bit 0  if set, the image is solid and covers the entire bounding box described, if clear, the image may have sections which reflect the  background colour
         Others reserved

This query is used to get generic information on an image in the file which was not necessary for the rendering of the file. This call is most commonly used to find the sequence number of the default and last logical image within a file. The sequence number may be set to &FFFFFFFF to indicate that the sequence number is not known. This might be the case if the format has no indication of the number of images present.

The image flags provide additional information about the image which might be useful to renderers. The only defined flag at present is that indicating if the image is 'solid' or not. This can be used by clients to decide whether drawing a background behind the image is necessary or not.

ImageFileRender_RendererInfo (&562C5)
On entry
   R0 = flags (must be 0)
   R1 = filetype
   R2 = magic identifier (or 0 for information on the generic renderer)
On exit
   R0 = pointer to definition block
   R1 = pointer to renederer name

This SWI is used to return information about a renderer.

ImageFileRender_Register (&562C6)
On entry
   R0 = flags (reserved, must be 0)
   R1 = pointer to definition (all will be copied):
         +0 = API version (102)
         +4 = renderer flags
         +8 = filetype
         +12 = magic value, or 0 if none
         +16 = pointer to name in format <name><tab><version x.xx><tab><author>
         +20 = workspace value for r12
         +24 = pointer to 'start' entry point, or 0 if none
         +28 = pointer to 'stop' entry point, or 0 if none
         +32 = pointer to render entry point
         +36 = pointer to bounding box entry point
         +40 = pointer to declare fonts entry point, or 0 if none
         +44 = pointer to information entry point or 0 to return just the API version
On exit
   R1 = API version (even if an error occurs)
   All other registers preserved

This SWI is used to register a new renderer.

ImageFileRender_Deregister (&562C7)
On entry
   R0 = flags (reserved, must be 0)
   R1 = filetype
   R2 = pointer to name, to match that in ImageFileRender_Register
   R3 = magic value to match (must be the same as when registered)
On exit
   All registers preserved

This SWI is used to deregister a renderer.

Image renderers

Image descriptor block

The image descriptor block is provided to all image renderers and provides the core information required for all the processing routines. Before any calls are made to the major processing routines in the renderer, a call is made to the 'start' entry point. This allows clients to cache any relevant data in the image descriptor block such that processing by other routines may be performed without repeatedly requiring that such data be calculated. For example, a sprite renderer might cache a translation table, or a pointer to the sprite. The 'stop' entry point will be called to destroy the cached data held in the 'private image data' entry.

The image descriptor block has the following format :

      +0 = pointer to data to render
      +4 = length of data
      +8 = pointer to extension data, or 0 if no data
      +12 = image sequence number
      +16 = private image data

The first four of these entries will be supplied by the ImageFileRender module. The last will be initialised to zero and may be set to any value by the 'start' entry point. For certain image formats, the caching of data through the 'start' and 'stop' operations can improve the rendering speed by not requiring repeated calculation of values. A simple example might be the 'Render to fit' operation, which requires the calculation of a bounding box before the actual rendering. For a complex image, this information might be cached to aid rendering.

'Start' routine
On entry
   R0 = API version * 100 (102 in this version)
   R1 = pointer to image descriptor :
         +0 = pointer to data to render
         +4 = length of data
         +8 = pointer to extension data, or 0 if no data
         +12 = image sequence number
         +16 = private image data, 0 initially but may be updated
   R2 = 0
   R12 = workspace value on entry to ImageFileRender_Register

The 'start' routine is called before any operations are applied to a particular image. This allows clients to cache relevant data for an image.

'Stop' routine
On entry
   R0 = API version * 100 (102 in this version)
   R1 = pointer to image descriptor :
         +0 = pointer to data to render
         +4 = length of data
         +8 = pointer to extension data, or 0 if no data
         +12 = image sequence number
         +16 = private image data, 0 initially but may be updated
   R2 = 0
   R12 = workspace value on entry to ImageFileRender_Register

The 'stop' routine is called after any operations have been completed (even if one of the operations generated an error). This allows clients to release cached data.

Bounding box calculation routine
On entry
   R0 = API version * 100 (102 in this version)
   R1 = pointer to image descriptor
   R2 = pointer to bounding box descriptor :
         +0 = flags (0)
         +4 = transformation matrix to apply (standard format)
         +28 = bounding box to fill in (standard format)
   R12 = workspace value on entry to ImageFileRender_Register

The bounding box routine is called to calculate the bounding box for a given transformation. If the image data is not recognised it should be faulted. Errors should be reported by setting V and returning an error block in R0. The bounding box should be returned in draw coordinates for the images extent, that is, OS units * 256.

Rendering routine
On entry
   R0 = API version * 100 (102 in this version)
   R1 = pointer to image descriptor
   R2 = pointer to rendering descriptor :
         +0 flags :
               bits 0-2 = reserved, must be ignored
               bit 3 = colour mapping function supplied
               bits 4-5 = reserved, must be ignored
               bits 6-b9 = quality to render at :
                     0 = Use default quality
                     1 = Lowest quality
                     2-14 = Renderer specific values
                     15 = Highest quality
               bits 10-31 = reserved for future expansion, must be 0
         +4 = transformation matrix to apply (standard format)
         +28 = clipping rectangle in external coordinates (standard format)
         +44 = pointer to colour mapping routine
         +48 = workspace for colour mapping routine
   R12 = workspace value on entry to ImageFileRender_Register

The rendering routine is called to render an image using a given transformation. If the image data is not recognised, it should be faulted. Errors should be reported by setting V and returning an error block in R0.

Font declaration routine
On entry
   R0 = API version * 100 (102 in this version)
   R1 = pointer to image descriptor
   R2 = pointer to declare fonts descriptor :
         +0 = flags (0)
         +4 = flags to pass to PDriver_DeclareFont

The font declaration routine need only be provided by renderers which use fonts. The renderer should call PDriver_DeclareFont with the names of all fonts and the flags passed in R4. If the image data is not recognised, it should be faulted. Errors should be reported by setting V and returning an error block in R0.

Information routine
On entry
   R0 = API version * 100 (102 in this version)
   R1 = pointer to image descriptor
   R2 = pointer to declare fonts descriptor :
         +0 = query type
         +4 = query data length
         +8 = pointer to data block to take details from/fill in
On exit
   If VSet, R0 = pointer to error,
               or 1 for an 'invalid query type'
               or 2 for an 'invalid query length'

The information routine should be provided by renderers to query information about the images. The routine should fault invalid queries and invalid query lengths.

InverseTable

Inverse table provides 8bpp translation tables for graphical applications. As converting between 8bpp values and providing a mechanism to 'blend' between these is time consuming, the InverseTable module provides core functions to calculate the tables involved.

The module will generate two tables :

  • A RGB to colour number lookup table
  • A colour number to RGB lookup table

Because producing a full range RGB table would be a little extreme (requiring 16 M of RAM to store it) the tables are generated at 5 bit accuracy. Applications requiring greater accuracy than this in 8bpp modes may wish to use alternate means to perform their blending.

The RGB to Colour Number lookup table is a table of 32768 byte values which correspond to the relevant colour. To calculate the index into the table of the colour number closest an RGB value the RGB value should first be quantised to 5 bits per component. The values should then be laid out as follows :

      Bits       Component
      0-4           Red
      5-9           Green
      10-14       Blue

The resulting value can be used as an index into the RGB to colour number table.

The colour number to RGB lookup table is a table of 256 4-byte wide word values. Because the tables are used for speed, rather than for space, the values are not packed. The value read follows the same bit layout described above.

Example
REM Fade a colour to half its brightness via the inverse tables
   REM colour% is a colour number
   SYS "InverseTable_Calculate" TO rgbtable%,colourtable%
   rgb%=rgbtable%!(colour%*4)
   REM Now transform the colour (halve it and clear the shifted bits)
   rgb%=rgb%>>1
   rgb%=rgb% AND NOT ((1<<4) OR (1<<9))
   REM We now have :
   REM   %0BBBB0GGGG0RRRR
   colour%=colourtable%?rgb%
   REM colour% is the half brightness value
InverseTable_Calculate (SWI &4BF40)
On exit
   R0 = pointer to 5,5,5 RGB lookup table (colour number to RGB)
   R1 = pointer to colour number lookup table (RGB to colour number)

This SWI calculates a suitable pair of tables for the current destination (screen, or sprite). The tables are guaranteed to be static until the next mode change service is issued. Where necessary, the tables will be recalculated. This may take a number of seconds and so the hourglass will be displayed whilst this takes place. Pre-calculated tables may be used by the module for certain common palettes (presently, only the standard 256 colour palette is catered for in this manner). Where the table is already calculated, InverseTable will return the table values without recalculating them. Recalculation will be forced if the palette changes. Recalculation may take around two seconds on a StrongARM based machine, or around seven on an ARM 610 based machine.

InverseTable_SpriteTable (SWI &4BF41)
On entry
   R0 = pointer to 5,5,5 RGB lookup table (colour number to RGB), 1024 bytes
   R1 = pointer to colour number lookup table (RGB to colour number), 32768 bytes
   R2 = sprite area to use, or mode number (equivalent to parameter R0 to ColourTrans_ReadPalette)
   R3 = sprite pointer to use (equivalent to parameter R1 to ColourTrans_ReadPalette)
On exit
   R0 = pointer to 5,5,5 RGB lookup table (colour number to RGB)
   R1 = pointer to colour number lookup table (RGB to colour number)

This SWI calculates a suitable pair of tables for an arbitrary sprite. If the table has not been cached, it will be recalculated. If the table has been cached, R0 and R1 on exit may differ from those passed in. Where the destination is the current mode, it is strongly recommended that you call InverseTable_Calculate rather than this SWI as this will retain a cache of the table data.


This documentation is copyright 3QD Developments Ltd 2013 and may not be reproduced or published in any form without the copyright holders permission. RISC OS is subject to continuous development and improvement as such all information is reproduced by 3QD Developments Ltd in good faith and is believed to be correct at the time of publication E&OE. 3QD Developments Ltd cannot accept any liability for any loss or damage arising from the use of any information provided as part of the RISC OS Documentation.

HTML document version 1.03 3rd November 2015