[Home] [Downloads] [Search] [Help/forum]

Miniwindows in MUSHclient - Drawing images

Written by Nick Gammon - July 2008. Updated September 2010.

On this page:

See also:

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:

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.

Example of loading an image

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:


List all images

WindowImageList function prototype:

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:


Get information about an image

WindowImageInfo function prototype:

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.


Drawing images

WindowDrawImage function prototype:

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.

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:

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.

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:

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).


Filling Ellipses, Filled Rectangles, Round Rectangles with an image

WindowImageOp function prototype:

This draws an ellipse, rectangle, round rectangle, controlled by the Action parameter. The specified shape is filled with a previously-loaded image.

Examples of drawing ellipses and other shapes

Resulting image is under the corresponding code.


Creating small images

WindowCreateImage function prototype:

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.

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.


Turn a miniwindow into an image

WindowImageFromWindow function prototype:

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.

Example of making an image from another window

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:

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.

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


Blurring


Sharpening


Edge detection


Emboss


Brightness


Contrast


Gamma


Scale/rotate/reflect/shear images

WindowTransformImage function prototype:

This lets you copy a loaded image onto any miniwindow (similar to WindowDrawImage) however it lets you:

These operations can be combined by judicious choices of parameters. In particular you would need to do a matrix multiplication (eg. multiply the rotate matrix by the reflect matrix).

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:

For a lengthy discussion about this, with screenshots, see Forum posting: WindowTransformImage

Summary of transformations:

ActionMxxMxyMyxMyy
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:

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


[Home]

Written by Nick Gammon - 5K

Comments to: Gammon Software support
[RH click to get RSS URL] Forum RSS feed ( http://www.gammon.com.au/rss/forum.xml )

[Best viewed with any browser - 2K]    [Internet Contents Rating Association (ICRA) - 2K]    [Hosted at HostDash]