Miniwindows in MUSHclient - Drawing images
Written by Nick Gammon - July 2008. Updated September 2010.
On this page:
- Image examples
- WindowCreateImage
- WindowDrawImage
- WindowDrawImageAlpha
- WindowFilter
- WindowGetImageAlpha
- WindowImageFromWindow
- WindowImageInfo
- WindowImageList
- WindowImageOp
- WindowLoadImage
- WindowTransformImage
See also:
- Introduction
- Creating miniwindows
- Drawing shapes
- Drawing text
- Hotspots
- Helpful graphics functions
- Blending images
Examples on this page
Most of the examples on this page are drawn in a 200 x 200 pixel window, with a grid drawn every 20 pixels to make it clearer the effect of the example code. The code for producing the grid is described in Creating miniwindows.
Introduction to images
The MUSHclient miniwindows let you load bitmap images (or create small ones yourself) and then display them in various ways. You can also turn other miniwindows into images to be used in further miniwindows.
Getting started with images - loading the image
Before images can be drawn to the miniwindow, the image must be "loaded". This specifies that this miniwindow is going to use this image. Later on you simply refer to the "image id" you gave when loading the image.
WindowLoadImage function prototype:
long WindowLoadImage(BSTR Name, BSTR ImageId, BSTR FileName);
This loads the specified image into the miniwindow, and remembers it by the nominated "image id". The image id is later used for drawing this image. Loading does not draw it, it simply reads it from disk ready for drawing later.
- Name - the name of an existing miniwindow. Names are case-sensitive.
- ImageId - the image id to be associated with this particular image. Image ids are case-sensitive.
- FileName - the disk file to load the image from. It should be a BMP or PNG file, not a GIF, TIF or other file type. PNG files may have an "alpha" mask which can be used when drawing with WindowDrawImageAlpha.
Example of loading an image
WindowLoadImage (win, "im1", "C:/program files/mushclient/leaf.bmp")
In Lua you can also use WindowLoadImageMemory which loads an image from a memory buffer. Only PNG file types are supported for WindowLoadImageMemory. For example:
local f = assert (io.open ("sword.png", "rb")) -- open read-only, binary mode
local image_data = f:read ("*a") -- read all of it
f:close () -- close it
WindowLoadImageMemory (win, "im", image_data) -- load image from memory
WindowDrawImage (win, "im", 20, 20, 0, 0, miniwin.image_copy) -- draw it
List all images
WindowImageList function prototype:
VARIANT WindowImageList(BSTR Name);
This returns a list of all images loaded into this miniwindow. You could use this to find which images have been loaded, and then use WindowImageInfo to find information about each one.
Example:
-- show all images
images = WindowImageList(win)
if images then
for _, v in ipairs (images) do
Note (v)
end
end -- if any
Get information about an image
WindowImageInfo function prototype:
VARIANT WindowImageInfo(BSTR Name, BSTR ImageId, long InfoType);
This returns information about a loaded image. You need to specify the name of the miniwindow, and the image id you used when loading the image.
- Name - the name of an existing miniwindow. Names are case-sensitive.
- ImageId - the image id you used when you loaded the image. Image ids are case-sensitive.
- InfoType - the information you want:
- 1: Type - Specifies the bitmap type.
- 2: Width - Specifies the width, in pixels, of the bitmap.
- 3: Height - Specifies the height, in pixels, of the bitmap.
- 4: WidthBytes - Specifies the number of bytes in each scan line.
- 5: Planes - Specifies the count of color planes.
- 6: BitsPixel - Specifies the number of bits required to indicate the color of a pixel.
Drawing images
WindowDrawImage function prototype:
long WindowDrawImage(BSTR Name, BSTR ImageId, long Left, long Top, long Right, long Bottom, short Mode, long SrcLeft, long SrcTop, long SrcRight, long SrcBottom);
This copies an image to the miniwindow. Also see WindowMergeImageAlpha which lets you copy an image to a miniwindow based on a second image which is the alpha mask. Also see WindowDrawImageAlpha which lets you copy an image to a miniwindow, respecting the alpha channel of theimage.
- Name - the name of an existing miniwindow. Names are case-sensitive.
- ImageId - an image id that you have loaded.
- Left, Top, Right, Bottom - describes the rectangle to be drawn to.
- Mode - the method of drawing the image:
Value Purpose Lua symbol 1 Copy without stretching to the destination position. The image is not clipped, so only the Left and Top parameters are used - the full image is copied to that position. miniwin.image_copy 2 Stretch or shrink the image appropriately to fit into the rectangle: Left, Top, Right, Bottom. miniwin.image_stretch 3 Copy without stretching to the position Left, Top. However this is a transparent copy, where the pixel at the left,top corner (pixel position 0,0) is considered the transparent colour. Any pixels that exactly match that colour are not copied. miniwin.image_transparent_copy - SrcLeft, SrcTop, SrcRight, SrcBottom - the source rectangle in the original image (use 0,0,0,0 to get the whole image). Negative numbers for the SrcRight and SrcBottom parameters represent an offset from the bottom or right edge.
The intention of allowing sub-images was so that you could make up a map by having lots of small images (eg. houses, trees, rocks). Now instead of having to load hundreds of tiny image files into memory, which would doubtless take a while to open all those files, you open a single, larger, file in which the various sub-images are "tiled". For example, you might allocate a 32 x 32 pixel square for each image. Now by selecting the appropriate tile you can copy the sub-image from the main image.
Examples of drawing images
WindowLoadImage (win, "im", "/Windows/Zapotec.bmp")
WindowDrawImage (win, "im", 20, 20, 0, 0, miniwin.image_copy) -- straight copy

WindowLoadImage (win, "im", "/Windows/Zapotec.bmp")
WindowDrawImage (win, "im", 20, 20, -20, -20, miniwin.image_stretch) -- stretch

WindowLoadImage (win, "im", "/Windows/Zapotec.bmp")
WindowDrawImage (win, "im", 20, 20, -20, -20, miniwin.image_transparent_copy) -- transparent

The transparent image doesn't look particularly exciting here, but in practice you would use transparency to copy odd-shaped things (like an image of a tree) onto a landscape.
Drawing images with an alpha channel
WindowDrawImageAlpha function prototype:
long WindowDrawImageAlpha(BSTR Name, BSTR ImageId, long Left, long Top, long Right, long Bottom, double Opacity, long SrcLeft, long SrcTop);
This copies an image to the miniwindow, respecting the alpha channel in the image. At present only PNG images can have alpha channels. The alpha channel effectively is a 4th byte per pixel (the others being the red, green and blue components of the pixel). This 4th byte specifies the transparency of the pixel, from fully transparent (0) to fully opaque (255), in the range 0 to 255. As you can see from the mask in the image below the black parts (which have a value of 0) are transparent, so the background shows through. The white parts (which have a value of 255) are opaque, so you do not see the background. The grey parts (somewhere between 1 and 254) let the background image show through partially.
- Name - the name of an existing miniwindow. Names are case-sensitive.
- ImageId - an image id that you have loaded.
- Left, Top, Right, Bottom - describes the rectangle to be drawn to.
- Opacity - this lets you draw semi-transparent images (apart from any extra transparency introduced by the alpha mask). So for example, by specifying an opacity of 0.5 you would have a "ghostly" image drawn on top of the background.
- SrcLeft and SrcTop let you specify to pull out a sub-image from the loaded image. Thus, a loaded image could be a "tiled" set of icons, and by specifying the left and top of each tile, you would get part of the image.
The intention of allowing sub-images was so that you could make up a map by having lots of small images (eg. houses, trees, rocks). Now instead of having to load hundreds of tiny image files into memory, which would doubtless take a while to open all those files, you open a single, larger, file in which the various sub-images are "tiled". For example, you might allocate a 32 x 32 pixel square for each image. Now by selecting the appropriate tile you can copy the sub-image from the main image.
Example:
win = "A" .. GetPluginID () -- get a unique name
WindowCreate (win, 0, 0, 365, 285, miniwin.pos_center_all, 0, ColourNameToRGB("white")) -- create window
-- Grid
for i = 1, math.max (WindowInfo (win, 3), WindowInfo (win, 4)) / 20 do
WindowLine (win, i * 20, 0, i * 20, WindowInfo (win, 4), 0xC0C0C0, miniwin.pen_solid, 1)
WindowLine (win, 0, i * 20, WindowInfo (win, 3), i * 20, 0xC0C0C0, miniwin.pen_solid, 1)
end -- for
WindowLoadImage (win, "im", "C:/alpha_test.png")
WindowDrawImageAlpha (win, "im", 20, 20, 0, 0, 1) -- opacity 1 (full)
WindowShow (win, true) -- show it
Original image:

Alpha mask in Photoshop:

Resulting image in Photoshop (checkerboard shows transparent area):

Resulting miniwindow in MUSHclient drawn using code above:

Get the alpha channel of an image
WindowGetImageAlpha function prototype:
long WindowGetImageAlpha(BSTR Name, BSTR ImageId, long Left, long Top, long Right, long Bottom, long SrcLeft, long SrcTop);
This copies the alpha channel of an image to the miniwindow, showing the alpha information as grayscale.
The alpha channel could be used when copying an image onto the miniwindow using the WindowMergeImageAlpha function. Only PNG images potentially have alpha channels.
Thus you could use WindowGetImageAlpha to create a scratch window (one not visible to the player) which holds the alpha information. This could then be turned into another image by using WindowImageFromWindow. This image is now available for use with WindowMergeImageAlpha to selectively copy the image to another miniwindow (this image would be used as the MaskId).
- Name - the name of an existing miniwindow. Names are case-sensitive.
- ImageId - an image id that you have loaded.
- Left, Top, Right, Bottom - describes the rectangle to be drawn to.
- SrcLeft, SrcTop - the source offset in the original image (use 0,0 to get the whole image).
Filling Ellipses, Filled Rectangles, Round Rectangles with an image
WindowImageOp function prototype:
long WindowImageOp(BSTR Name, short Action, long Left, long Top, long Right, long Bottom, long PenColour, long PenStyle, long PenWidth, long BrushColour, BSTR ImageId, long EllipseWidth, long EllipseHeight);
This draws an ellipse, rectangle, round rectangle, controlled by the Action parameter. The specified shape is filled with a previously-loaded image.
- Name - the name of an existing miniwindow. Names are case-sensitive.
- Action - what sort of shape to draw, as follows:
Value Purpose Lua symbol 1 Ellipse miniwin.image_fill_ellipse 2 Rectangle miniwin.image_fill_rectangle 3 Round Rectangle miniwin.image_fill_round_fill_rectangle - Left, Top, Right, Bottom - describes the rectangle into which the shape must fit.
- PenColour, PenStyle, PenWidth - the pen colour, style, and width as described at Drawing shapes
- BrushColour - the colour used for drawing the background, when displaying monochrome bitmaps.
- ImageId - an image id that you have loaded.
- EllipseWidth, EllipseHeight - the dimensions of the ellipse in the corner of a round rectangle, if applicable.
Examples of drawing ellipses and other shapes
Resulting image is under the corresponding code.
WindowLoadImage (win, "im", "/Windows/Zapotec.bmp")
WindowImageOp (win, miniwin.image_fill_ellipse, -- circle
20, 20, 150, 150, -- Left, Top, Right, Bottom
ColourNameToRGB("blue"), miniwin.pen_solid, 2, -- pen width 2
ColourNameToRGB("cyan"), "im")

WindowLoadImage (win, "im", "/Windows/Zapotec.bmp")
WindowImageOp (win, miniwin.image_fill_rectangle, -- rectangle
0, 0, 0, 0, -- Left, Top, Right, Bottom
ColourNameToRGB("blue"), miniwin.pen_null, 1, -- no pen
ColourNameToRGB("cyan"), "im")

WindowLoadImage (win, "im", "/Windows/Zapotec.bmp")
WindowImageOp (win, miniwin.image_fill_round_fill_rectangle, -- round rectangle
20, 20, 160, 160, -- Left, Top, Right, Bottom
ColourNameToRGB("blue"), miniwin.pen_solid, 3, -- pen width 3
ColourNameToRGB("cyan"), "im",
20, 20) -- amount of roundness

Creating small images
WindowCreateImage function prototype:
long WindowCreateImage(BSTR Name, BSTR ImageId, long Row1, long Row2, long Row3, long Row4, long Row5, long Row6, long Row7, long Row8);
This creates a small image (bitmap) by specifying the bit pattern for an 8 x 8 bit image. This is primarily intended for making patterns for use with WindowImageOp, described above. By designing suitable patterns you could make grass, waves, or other landscape effects for use in maps.
- Name - the name of an existing miniwindow. Names are case-sensitive.
- ImageId - the image id to store this image under. Image ids are case-sensitive.
- Row1, Row2, Row3, Row4, Row5, Row6, Row7, Row8 - the bit pattern for each row
The easiest way of making your own pattern is to use Lua's tonumber function and work in binary. When doing that, each '1' represents a bit that is set (and is thus in the PenColour) and each '0' represents a bit that is clear (and is thus in the BrushColour).
Examples of creating pattern images and displaying them
Resulting image is under the corresponding code.
WindowCreateImage (win, "im2",
tonumber ("11001100", 2), -- row 1
tonumber ("11001100", 2), -- row 2
tonumber ("00110011", 2), -- row 3
tonumber ("00110011", 2), -- row 4
tonumber ("11001100", 2), -- row 5
tonumber ("11001100", 2), -- row 6
tonumber ("00110011", 2), -- row 7
tonumber ("00110011", 2)) -- row 8
WindowImageOp (win, 2, 20, 20, 180, 180, -- rectangle
ColourNameToRGB("blue"), miniwin.pen_null, 0, -- pen
ColourNameToRGB("cyan"), "im2")

WindowCreateImage (win, "im3",
tonumber ("00000100", 2),
tonumber ("00000100", 2),
tonumber ("00000100", 2),
tonumber ("11111111", 2),
tonumber ("00000001", 2),
tonumber ("00000001", 2),
tonumber ("00000001", 2),
tonumber ("11111111", 2))
WindowImageOp (win, miniwin.image_fill_rectangle, -- rectangle
20, 20, 180, 180, -- Left, Top, Right, Bottom
ColourNameToRGB("sienna"), miniwin.pen_null, 0, -- pen
ColourNameToRGB("moccasin"), "im3")

Turn a miniwindow into an image
WindowImageFromWindow function prototype:
long WindowImageFromWindow(BSTR Name, BSTR ImageId, BSTR SourceWindow);
This uses an existing miniwindow's offscreen bitmap, to make an image that can be loaded into another miniwindow. This lets you set up offscreen windows (that you may never plan to actually show with WindowShow) as "work areas" for creating text or images, that can be loaded or blended into other windows.
- Name - the name of an existing miniwindow. Names are case-sensitive.
- ImageId - the image id to store its image under. Image ids are case-sensitive.
- SourceWindow - the miniwindow name that is the source of the image.
Example of making an image from another window
-- create another window
WindowCreate ("map2window", 0, 0, 150, 150, miniwin.pos_top_left, 0, 0x000000) ) -- top left corner
-- pull in map window as "map" from mapping plugin
WindowImageFromWindow("map2window", "map", "86810b755a33169f0f1d9585")
-- draw our small map into "map2" window
WindowDrawImage ("map2window", "map", 0, 0, 0, 0, miniwin.image_stretch);
-- show smaller map
WindowShow ("map2window", true)

In this example the original map from the mapping plugin was turned into "map" image for the second window "map2window", and displayed by compressing it, into 150 x 150 pixels in the top-left corner.
Note that the image is a static copy, if the map changed you would need to re-obtain a copy of it.
Run a filter function over part of a miniwindow
WindowFilter function prototype:
long WindowFilter(BSTR Name, long Left, long Top, long Right, long Bottom, short Operation, double Options);
This takes a copy of the specified rectangle in a miniwindow, filters it according to the operation specified, and replaces the filtered version back in place. Also see Blending images for other things you can do with images.
- Name - the name of an existing miniwindow. Names are case-sensitive.
- Left, Top, Right, Bottom - describes the rectangle to be filtered.
- Operation - the filter operation. At present, one of:
Value Purpose Lua symbol 1 Apply colour noise miniwin.filter_noise 2 Apply monochrome noise miniwin.filter_monochrome_noise 3 Blur miniwin.filter_blur 4 Sharpen miniwin.filter_sharpen 5 Find edges miniwin.filter_find_edges 6 Emboss miniwin.filter_emboss 7 Adjust Brightness (additive) miniwin.filter_brightness 8 Adjust Contrast miniwin.filter_contrast 9 Adjust Gamma miniwin.filter_gamma 10 Adjust Brightness for red channel only (additive) miniwin.filter_red_brightness 11 Adjust Contrast for red channel only miniwin.filter_red_contrast 12 Adjust Gamma for red channel only miniwin.filter_red_gamma 13 Adjust Brightness for green channel only (additive) miniwin.filter_green_brightness 14 Adjust Contrast for green channel only miniwin.filter_green_contrast 15 Adjust Gamma for green channel only miniwin.filter_green_gamma 16 Adjust Brightness for blue channel only (additive) miniwin.filter_blue_brightness 17 Adjust Contrast for blue channel only miniwin.filter_blue_contrast 18 Adjust Gamma for blue channel only miniwin.filter_blue_gamma 19 Convert to grayscale - mix red/green/blue equally miniwin.filter_grayscale 20 Convert to grayscale - mix 30% red + 59% green + 11% blue for normal perception miniwin.filter_normal_grayscale 21 Adjust Brightness (multiply) miniwin.filter_brightness_multiply 22 Adjust Brightness for red channel only (multiply) miniwin.filter_red_brightness_multiply 23 Adjust Brightness for green channel only (multiply) miniwin.filter_green_brightness_multiply 24 Adjust Brightness for blue channel only (multiply) miniwin.filter_blue_brightness_multiply 25 Blur (less) miniwin.filter_lesser_blur 26 Blur (minor) miniwin.filter_minor_blur 27 Average - calculates the average colour of all the pixels in the selected area miniwin.filter_average Single channel operations - the modes which specify a single channel (10 to 18) operate on that colour channel only (red, green or blue) leaving the others untouched. Thus by, say, increasing brightness on the red channel you add to the red pixel values, but leave green and blue alone, making the image look redder. However decreasing brightness on the red channel would make the image look more cyan (as cyan is the complementary colour to red).
The complementary colours are:
- red <--> cyan
- green <--> magenta
- blue <--> yellow
- Options - filtering options.
For the Noise filter:
- A number from about 0 to 255 indicating how much noise to add.
For the Blur, Sharpen, Find Edges and Emboss filters:
- 0 - both directions
- 1 - horizontal only
- 2 - vertical only
For the Brightness (additive) filters:
- A number from -255 to +255 to indicate the amount to increase (or decrease) the value of each pixel. A negative number will make it darker, a positive number will make it brighter.
For the Brightness (multiply) filters:
- A number to be multiplied by each pixel. A value of 1 will have no effect, greater than one will make the image brighter, and less than one will make it less bright. This has a different effect to the additive brightness, because black stays black (zero multiplied by anything is still zero) whereas the additive brightness will always make things brighter.
For the Contrast filters:
- A number to indicate the amount to multiply by the value of each pixel. Zero will make the picture zero contrast, that is totally grey. If you use 1 the pixel will be normal contrast (as each pixel is multiplied by 1). A value between 0 and 1 will be lower contrast. A value above 1 will increase contrast. Negative numbers will have the effect of making the image look negative.
Technically the pixel value first has 128 subtracted from it (to "center" it), then the multiplication is done, then 128 is added back. This has the effect of altering contrast, because if you multiply by a number > 1, then bright colours become brighter (because they are > 128) and darker colours become darker (because they are < 128 and are negative when the multiply is done). This "stretches" the brighness away from the center. However a contrast multiplier of < 1 tends to squash the colours towards 128, making them have lower contrast.
For the Gamma filters:
- A number to indicate the amount of Gamma adjustment. Mathematically each pixel is raised to the power of this number. Thus, a gamma of 1 will result in no change. A gamma of 2 will darken the image somewhat. A gamma of 0.5 will lighten the image. A gamma of zero will make the image totally white.
The difference between gamma and brightness is that increasing brightness simply adds to the value of each pixel, so that black becomes gray, and bright pixel become clipped. Similarly, decreasing brightness means that white pixels become grey, and dark ones are clipped.
However because gamma is a power function, black stays black, and white stays white, with the biggest change in the mid range. A higher gamma value results in a darker image with more contrast. A lower gamma value (between 0 and 1) results in a lighter image with less contrast.
Warning - filtering is quite computation-expensive. For example, for a 600 x 600 pixel image, the program has to apply a calculation to 600 x 600 x 3 bytes (one for each of red, green and blue), which would be 1,080,000 calculations. In addition, most of the filtering operations (except noise) need to do a calculation on a "window" of adjoining pixels (2 on each side of each pixel), effectively multiplying the number of calculations by a further 5.
If possible, apply a filter once, and use the filtered image many times. As you can use miniwindows as image sources for other miniwindows, consider setting up a filtered image once, and then just copying it in when needed (eg. draw an elaborate background once, and then just copy in the result when needed).
Examples of filtering
Some examples below use a picture to illustrate the various modes, this is the original image:

Resulting image is under the corresponding code.
Noise
WindowFilter (win, 0, 0, 0, 0, miniwin.filter_noise, 100) -- colour noise in whole window - level 100


WindowFilter (win, 0, 0, 0, 0, miniwin.filter_noise, 50) -- colour noise in whole window - level 50


WindowFilter (win, 0, 0, 0, 0, miniwin.filter_monochrome_noise, 100) -- monochrome noise in whole window - level 100


Blurring
WindowFilter (win, 10, 10, 90, 90, miniwin.filter_blur, 0) -- blur both directions


WindowFilter (win, 10, 10, 90, 90, miniwin.filter_blur, 1) -- blur horizontal

WindowFilter (win, 10, 10, 90, 90, miniwin.filter_blur, 2) -- blur vertical

Sharpening
WindowFilter (win, 10, 10, 90, 90, miniwin.filter_sharpen, 0) -- sharpen in both directions

Edge detection
WindowFilter (win, 10, 10, 90, 90, miniwin.filter_find_edges, 0) -- edge detect

Emboss
WindowFilter (win, 10, 10, 90, 90, miniwin.filter_emboss, 0) -- emboss

Brightness
WindowFilter (win, 10, 10, 90, 90, miniwin.filter_brightness, -100) -- lower by 100

WindowFilter (win, 10, 10, 90, 90, miniwin.filter_brightness, 100) -- raise by 100

Contrast
WindowFilter (win, 10, 10, 90, 90, miniwin.filter_contrast, 0.5) -- reduce

WindowFilter (win, 10, 10, 90, 90, miniwin.filter_contrast, 2) -- increase

WindowFilter (win, 10, 10, 90, 90, miniwin.filter_contrast, 10) -- increase a lot

WindowFilter (win, 10, 10, 90, 90, miniwin.filter_contrast, -2) -- make negative

Gamma
WindowFilter (win, 10, 10, 90, 90, miniwin.filter_gamma, 0.3) -- brighter, lower contrast

WindowFilter (win, 10, 10, 90, 90, miniwin.filter_gamma, 1.5) -- darker, higher contrast

WindowFilter (win, 10, 10, 90, 90, miniwin.filter_gamma, 5) -- very dark and contrasty

Scale/rotate/reflect/shear images
WindowTransformImage function prototype:
long WindowTransformImage(WindowName, ImageId, Left, Top, Mode, Mxx, Mxy, Myx, Myy);
This lets you copy a loaded image onto any miniwindow (similar to WindowDrawImage) however it lets you:
- Translate
- Scale
- Rotate
- Shear
- Reflect
For details on matrix multiplication: Matrix_multiplication (Wikipedia)
The translation is done by applying a mathematical operation to the location of each pixel during the copy operation. For each original x and y pixel, the new location x' and y' is determined as follows:
x' = (x * Mxx) + (y * Mxy) + Left
y' = (x * Myx) + (y * Myy) + Top
- Name - the name of an existing miniwindow. Names are case-sensitive.
- ImageId - an image id that you have loaded. Image ids are case-sensitive.
- Left - the value to be added to the X position for each pixel
- Top - the value to be added to the Y position for each pixel
- Mode - the method of drawing the image:
Value Purpose Lua symbol 1 Copy without stretching to the destination position. The image is not clipped, so only the Left and Top parameters are used - the full image is copied to that position. miniwin.image_copy 3 Copy without stretching to the position Left, Top. However this is a transparent copy, where the pixel at the left,top corner (pixel position 0,0) is considered the transparent colour. Any pixels that exactly match that colour are not copied. miniwin.image_transparent_copy - Mxx - the value to be multiplied by the old X position to give the new X position
- Mxy - the value to be multiplied by the old Y position to give the new X position
- Myx - the value to be multiplied by the old X position to give the new Y position
- Myy - the value to be multiplied by the old Y position to give the new Y position
For a lengthy discussion about this, with screenshots, see Forum posting: WindowTransformImage
Summary of transformations:
| Action | Mxx | Mxy | Myx | Myy |
|---|---|---|---|---|
| Identity (copy) | 1 | 0 | 0 | 1 |
| Reflection on X | -1 | 0 | 0 | 1 |
| Reflection on Y | 1 | 0 | 0 | -1 |
| Reflection on both | -1 | 0 | 0 | -1 |
| Rotation clockwise | cosine | -sine | sine | cosine |
| Rotation counter clockwise | cosine | sine | -sine | cosine |
| Shear vertically RH side down | 1 | 0 | 1 | 1 |
| Shear vertically RH side up | 1 | 0 | -1 | 1 |
| Shear horizontally bottom to right | 1 | 1 | 0 | 1 |
| Shear horizontally bottom to left | 1 | -1 | 0 | 1 |
| Scale by 1.5 (larger) | 1.5 | 0 | 0 | 1.5 |
| Scale by 0.5 (smaller) | 0.5 | 0 | 0 | 0.5 |
Note: Some actions may cause the image to move sideways (eg. reflection) in which case you may need to compensate by modifying the Top and Left parameters to return it back to where you want it. In the case of the rotation actions you need to take the sine and cosine of the desired angle of rotation (eg. using math.sin and math.cos in Lua). You may also need to use math.rad to convert degrees to radians.
For a lengthier treatment on matrices (and indeed, why I am using the word) see Matrix (mathematics) (Wikipedia).
A little way down the page, in the section "Linear transformations", it demonstrates the various ways that the matrix elements accomplish the various transformations described above.
In particular, the arguments would be represented as a matrix like this:
[ Mxx Myx 0 ]
[ Mxy Myy 0 ]
[ Left Top 1 ]
If you want to combine actions (eg. scale and rotate) then you would need to do a matrix multiplication, based on the suggested values above, to arrive at the 6 values for the combined action.
This image used above is Thanks to solea by jam343. It is licensed for royalty-free use under the Attribution 2.5 Generic License. It was obtained from the web site http://www.everystockphoto.com/.
Other pages about miniwindows
- Introduction
- Creating miniwindows
- Drawing shapes
- Drawing text
- Hotspots
- Helpful graphics functions
- Blending images