RISC User Volume 2 Issue 6 contained a program to convert a screen from one mode to another. However, this program was relatively simple, and only really worked when changing to a mode with at least as high a resolution and number of colours. The program described here, called ChangeFSI (explained later), is much more intelligent, and will do its best to retain as much information about the image and its colours as possible. There are a number of cases when such a program can be useful:
1. Simply displaying an image in different screen modes on the Archimedes, where the pixels have different aspect ratios or there are different numbers of bits per pixel. And, indeed, even when there are more bits per pixel, on the Archimedes going from 4 bits per pixel to 8 bits per pixel involves a complete change in the way colour is represented.
2. Moving an image from one computer to another, in this case to the Archimedes.
3. Printing out an image.
4. Changing the size of an image.
The modules SpriteExtend (in the ROM) and ColourTrans (in the !System directory) in RISC OS do provide some capabilities for displaying pictures in different screen modes. ColourTrans can look at the palette which a sprite uses and return a list of the equivalent closest colours in the current screen mode. SpriteExtend can paint sprites using the list of equivalent colours, and can change the size of the image into the bargain. Indeed, it is these two modules that were used by the earlier screen converter. However, these facilities are rather simplistic: ColourTrans makes no effort to use dithering (the practice of putting patterns of different coloured pixels together to represent other colours) and SpriteExtend simply discards additional information if reducing the picture in size (and together they make no attempt to enhance the picture when making it larger). The reason for these shortcomings is quite simple: speed. The algorithm used in the program described here uses 105 ARM instructions per pixel - and that's apart from any instructions used to read the image in, change its size and write the result out. Processing a mode 15 picture thus takes several seconds, making it impractical for use in a real-time desktop environment.
Before explaining how to use ChangeFSI we will look at how it improves the situation, and why it takes so long! One can immediately draw up some desirable properties for any solution to the image changing problem:
1. Maximising the volume of the colour cube. Colour represented in the Red, Green and Blue computer graphics system can be thought of as a point in a 3D cube whose axes are the red, green and blue values. Whatever clever approximations, dithering or error diffusion techniques are used, the colour volume spanned by the r, g and b axes in the target should be large enough to contain the source volume. If not, then the picture will appear faded in some way compared to the original ("the red doesn't seem quite the same"). For a single picture a colour volume only as large as the input could be chosen; alternatively for an arbitrary set of input pictures, the colour volume on the output system has to be made as large as possible. Where animation is required the colour volume has to be consistent for all the pictures. When generating the largest volume, it is important to use the system hardware to the limit: for example, if one has two bits of control over the Archimedes 4 bit D to A converters, the largest range is covered by values 0, 5, 10 and 15 (rather than 0, 4, 8 and 12).
2. Giving hue consistency at different saturations. For example, with a palette with different numbers of bits of r, g and b it may be impossible to have a consistent set of colours representing derived colours at different levels of intensity. Shades of white and secondary colours (cyan, magenta and yellow) are particularly difficult.
3. Working with the multi-tasking Desktop. Acorn are very keen for all new applications to be written to work within the Desktop environment. This constrains the choice of available colours to those set up using the Palette Manager.
The Desktop (default) palette in the 256 colour modes (e.g. modes 13, 15, 21, 24 and 28) is quite well designed. It does have the properties of 1 and 2 (it even has 16 shades of grey) and automatically satisfies 3. It is used by many Acorn programs (Draw, Paint) and by external programs (Euclid, ProArtisan, Atelier, etc.) to great effect and is a safe choice for ChangeFSI.
With the 16 colour modes (e.g. modes 9, 12, 16, 20 and 27) the default palette does not satisfy 1 and 2 unless the output is purely shades of grey. ChangeFSI has two alternatives for colour representation in 16 colour modes:
1) use 1 bit of red, 2 bits of green and 1 bit of blue. This uses up all the available bits and spans the colour cube, but it doesn't have full hue consistency and it can't be displayed on the Desktop (via ColourTrans and SpriteExtend) without using a 256 colour mode (which would allow the use of 256 colour images anyway!). Extra information is usually put into green since the human eye is most sensitive to green light. This option is selected by a "c" suffix to the mode argument (see later).
2) use 1 bit of red, 1 bit of green and 1 bit of blue. This spans the colour cube and is hue consistent, but doesn't use the full range of bits provided in the format. ColourTrans can map this to the Desktop with the standard palette with fair success, except for the lack of magenta (full red+full blue) in the palette. A better result can be achieved by setting six of the colours in the palette to red, green, yellow, blue, magenta and cyan. Since ColourTrans will map the colours anyway, it doesn't matter which six, but the most consistent values are 8=blue, 9=yellow, 10=green, 11=red, 13=cyan, 14=magenta (leaving 0-7, 12 and 15 unchanged). The file 'RGBColPal' on the disc contains a palette like this (plus my own preferred mouse pointer colours). This option is selected by a "d" (digital RGB) suffix to the mode argument.
With the 4 colour modes (e.g. modes 8, 11, 19 and 26) ChangeFSI is really pushed. Shades of grey output is done with the 0, 5, 10, 15 level palette. But how can colour be done? For example, each pixel can display only one of (say) black, red, green or blue. This fails to span the colour cube (it does only half of it), however, so black, cyan, magenta and yellow are used instead. The rest has to be left to luck: there is no way it can approximate to pure shades of red, green or blue. Four bit colour pictures can be seen on the Desktop in 16 colour modes with the above palette or in 256 colour modes. This option is also selected by a "c" suffix.
With 2 colour modes (e.g. modes 0, 18, 23 and 25) pixels are either ON or OFF, ChangeFSI will only do shades of grey output.
So that's the canvas ChangeFSI has to work on. How does it display the input range of colours on these outputs? The answer is, as stated above, dithering: the process of approximating intensity variations with patterned areas. There are two basic types of dithering technique: that used to print colour magazines and newspaper photographs "clustered dot dither", in which the size of the dot is changed according to the desired intensity; and that used on dot matrix displays, for example the grey level patterns used by 1 bit per pixel mode on the Desktop, "dispersed dot dither", where the average number of dots in the area gives the intensity. Since ChangeFSI's output is to raster devices it uses a dispersed dot dither. An approximation to a colour will produce an error (which might possibly be zero if ChangeFSI is very lucky). ChangeFSI tracks these errors and ensures that over wide areas there is no overall error using a technique called "error diffusion", first devised by R.W. Floyd and L. Steinberg in 1975. In this technique the approximation is made and the error is distributed to nearby pixels in the ratios shown in figure 1.
Obviously this assumes that the output is being generated row by row left to right and top to bottom. The 'error' pixels would be reflected for other directions.
ChangeFSI gets some of its name from Floyd and Steinberg. Additionally, ChangeFSI scans through the picture in a serpentine fashion, doing a row of pixels left to right followed by the next row right to left. This reduces the probability of regular patterns which the eye is sensitive to. The final I of the name is for Integer: ChangeFSI does all its work in 32 bit fixed point integer arithmetic (with the point at bit 28) instead of floating point.
The conversion from one colour range to another is made at the same time as a change in size of the image. Size is changed by ratios of areas between the input and output: the total weight of r, g, and b in the source area is calculated using the fixed point arithmetic, and this result is then approximated to the output using error diffusion to preserve information (for example, consider halving in size an image with adjacent pixels of intensities 1 and 2; the output pixel needs to be value 1.5, so the 0.5 error is sent to adjacent pixels to keep the overall colour the same).
Conversion from colour to monochrome shades of grey is done with the CIE luminance weights for r, g and b (0.30, 0.59, 0.11) which is the standard conversion for broadcast television. Altering these values (rwt, gwt and bwt) in the program allows production of colour separations of the original picture.
ChangeFSI can take RISC OS sprites from 16 or 256 colour modes. If there is a palette it will be used, otherwise the standard 16 and 256 colour Desktop palettes are used. There is an example picture 'Acorn_21' on the disc just in case you haven't any large colour pictures. The program can also handle a number of proprietary formats, and these are explained later.
There are two ways of using ChangeFSI. Firstly, it can be run as a normal program in which case it will prompt for the various parameters it needs. Secondly, it can be copied to your library and invoked using *ChangeFSI followed by the parameters. The command *ChangeFSI -help will print out details of the command's function, its syntax, and the various image formats supported. The format for the command line version is:
*ChangeFSI <source> <dest> <mode>[c|d|t] [<xscale> [<yscale>]]
Source and dest are the filenames of the source image and the destination image respectively. Mode is the mode to convert the image into. If you wish to specify the c or d options explained above, then the appropriate letter should follow the mode number with no space, for example 20d. The t option causes the image to be converted using no tints in 256 colour modes, or sixteen grey levels in 16 colour modes.
Xscale and yscale are the scale factors for mapping from the input to output images. These are in the form x:y where x is the multiplier and y the divider. They are automatically reduced to the lowest form, so you can specify the values which are most convenient. For example, when going from a multi-sync to a normal mode you could use the factors 640:640 and 256:512. If no scale factors are specified then 1:1 is assumed, while if a single factor is given then it is used for both the x and y directions.
ChangeFSI reads the image from disc as it is needed, and builds the output image in memory. This is then saved once the entire image has been converted. A percentage indicator is displayed during the conversion, and mode 0 is selected to reduce the video bandwidth and hence increase the speed. A further substantial speed increase can be achieved by using *RMFaster Basic before running the program.
Here are some examples of what ChangeFSI can be used for, together with the appropriate parameters:
Make "standard palette" versions of existing 256 colour images (for example the Watford digitiser plus colour board doesn't use the standard palette).
ChangeFSI pic pic 13
for a coloured Watford picture.
Or convert a colour picture to something you can see on your high res mono monitor.
ChangeFSI in out 18
Or convert a colour picture to grey scale.
ChangeFSI in out 20
Or change a 512 by 480 image to the standard aspect ratio.
ChangeFSI in out 15 640:512 512:480
Or change the Acorn screen (on the disc) to digital r, g, b
ChangeFSI Acorn_21 tt 20d
There are of course many more uses such as making miniatures of pictures, animated sequences of pictures changing size, converting Artisan pictures to the Desktop (try looking at the Artisan Garden with the Desktop in 256 colours and ChangeFSI's version - the stripes on the lawn vanish with the standard version). Obviously you will need to have captured input as a sprite first!
One point to note is that ChangeFSI has built-in to it the concept of RISC OS pixel shape, so when translating between modes where the pixels have different shapes you don't have to specify scale factors, as this is done automatically.
ChangeFSI can also convert from non RISC OS sprite formats while doing all of the above processing. It currently understands the Video Electronics ArVis format (5 bits of r, g and b), the CadSoft/Millipede Prisma format (256 colours from 224), the CompuServe GIF format (also 256 colours from 224) (rather slow, this one), PC .PIC files and 224 colour displays obtained from ray tracers like QRT and RT (indeed, this is how the Acorn_21 picture was obtained in the first place!). Future versions of the program will cater for other formats such as TIFF and IFF. Adding a new format involves additional code for three distinct operations:
1) The program must be changed to correctly recognise the format of the image, either by some key in the filename, or by the contents of the file itself.
2) A routine must be written to extract the image size and colour palette mapping from the image file.
3) PROCiprow has to be modified to allow a complete row of pixels to be read from the source image.
By studying the program it is possible to see how the extra code needs to be structured. If you do implement any extra formats, then please send them either to RISC User, or me, Roger Wilson, directly at Acorn, so that they can be included in a future version of the program.
Further information on dithering can be found in the book "Digital Halftoning" by Robert Ulichney published by the MIT Press, ISBN 0-262-21009-6, a book which I wish I'd had when I started writing the program, rather than when it was nearly finished!