Class rtk.Image

Utility class to manage REAPER images.

Note that this isn't a widget and rtk.Image objects can't be added to containers. For that, use rtk.ImageBox instead. This is just a utility class to manipulate REAPER-backed images at a low level.

Images are automatically freed as part of Lua garbage collection, with the underlying REAPER buffer released for use by future rtk.Image objects.

Drawing Mode Constants

These constants are used with the mode arguments in the various drawing methods. They can be bitwise-ORed together.

rtk.Image.DEFAULT

Default blending mode which considers both source and destination alpha channels. Most of the time this is what you want.

rtk.Image.ADDITIVE_BLEND

Blends source and destination by summing their color values together.

rtk.Image.SUBTRACTIVE_BLEND

Blends source and destination by subtracting the source color from the destination color.

rtk.Image.NO_SOURCE_ALPHA

Ignores the alpha channel from the source image treating all pixels as fully opaque when blitting onto the destination. Unless you need alpha blending, you should use this mode for improved performance.

rtk.Image.NO_FILTERING

When scaling images, filtering provides pixel interpolation to improve the quality but comes at a cost. This disables filtering so the scaling algorithm is nearest neighbor.

rtk.Image.FAST_BLIT

A combination of NO_SOURCE_ALPHA and NO_FILTERING which is the most efficient drawing mode but obviously is only useful in certain circumstances.

Static Class Functions

Synopsis

Functions
icon() static

Create a new image either from an rtk.ImagePack image name that was registered, or, if not found, search for a png file located in any of the image paths added via rtk.add_image_search_path()

make_placeholder_icon() static

Returns an icon with a red question mark that can be used to indicate icon load failure without aborting the program

rtk.Image.icon(name, style) static

Create a new image either from an rtk.ImagePack image name that was registered, or, if not found, search for a png file located in any of the image paths added via rtk.add_image_search_path().

The style argument dictates the requested icon luminance (namely, dark or light). and if not specified defaults to the current theme's icon style. Icons registered via an rtk.ImagePack can be assigned a style, and likewise image paths added with rtk.add_image_search_path() can indicate the style of icons found within that path.

If no icon is found for the requested style, then the other style will be searched as a fallback method. In this case, the icon will be recolored to be black if style is dark, or white if style is light. But note in this case colored icons will be turned monochromatic.

If ultimately no suitable icon can be located, an error is logged and nil is returned. The caller can choose to use make_placeholder_icon() in a pinch.

ImagePacks and size qualifiers

Icons previously registered via rtk.ImagePack can also be accessed by this function.

If the rtk.ImagePack contains multiple size variants of the icon, you can qualify the icon name by adding a :<size> suffix. For example, error:huge would return the huge variant of the error icon (assuming such a variant had been added to the ImagePack). See rtk.ImagePack:get() for more details.

Example
local img = rtk.Image.icon('undo', 'light')
Parameters
name (string)

Filename of the icon. If the file extension is omitted (which is preferred but not required) then .png is assumed.

style (string or nil)

Either dark or light indicating the icon luminance. If nil then the current theme icon style will be assumed.

Return Values
(rtk.Image or nil)

newly loaded image, or nil if icon could not be found (in which case an error is logged to the console)

rtk.Image.make_placeholder_icon(w, h, style) static

Returns an icon with a red question mark that can be used to indicate icon load failure without aborting the program.

local img = rtk.Image.icon('undo', 'light')
if not img then
    img = rtk.Image.make_placeholder_icon(24, 24, 'light')
end
Parameters
w (number or nil)

desired image width, nil implies 24

h (number or nil)

desired image height, nil implies 24

style (string or nil)

dark or light to indicate desired icon brightness. If nil, then dark is assumed.

Return Values
(rtk.Image)

the new image

Class API

Synopsis

Attributes
x number

read-only

The x offset within the underlying REAPER image as set by viewport() (default 0)

y number

read-only

The y offset within the underlying REAPER image as set by viewport() (default 0)

w number or nil

read-only

The width in pixels of the image as set by create() or load() (default nil)

h number or nil

read-only

The height in pixels of the image as set by create() or load() (default nil)

density number

read/write

The pixel density factor of the image, which controls how the image is drawn relative to rtk.scale

path string or nil

read-only

The image path that was passed to load() or nil if load() wasn't called (default nil)

rotation number

read-only

The current rotation of the image in degrees as passed to rotate()

id number or nil

read-only

The numeric id that represents the image buffer within REAPER

Methods
rtk.Image()

Constructor to create a new image resource

create()

Assigns a new image buffer with the specified dimensions

load()

Loads an image from disk

pushdest()

Pushes this image's buffer onto the stack for off-screen drawing

popdest()

Pops this image's buffer off the stack for off-screen drawing

clone()

Clones the current image contents into a new rtk.Image object with a new image buffer

resize()

Resizes the current image to new dimensions

scale()

Returns a new image with the current image scaled to the given resolution

clear()

Clears the image either to the given color or to fully transparent

viewport()

Creates a new rtk.Image that is a viewport into the current image

draw()

Draws the full image to the current drawing target

blit()

Draws a region of the image onto a drawing target, or another image onto this image

recolor()

Changes all pixels in the image to the given color while respecting the alpha channel

filter()

Applies an effect to the image by multiplying or adding values to individual channels

rect()

Draws a rectangle on the image in the given color

blur()

Blurs a region of the image

flip_vertical()

Flips the image vertically in place

rotate()

Rotates the image

refresh_scale()

Widgets using rtk.Image objects invoke this whenever rtk.scale.value has changed

Attributes

rtk.Image.x number read-only

The x offset within the underlying REAPER image as set by viewport() (default 0).

rtk.Image.y number read-only

The y offset within the underlying REAPER image as set by viewport() (default 0).

rtk.Image.w number or nil read-only

The width in pixels of the image as set by create() or load() (default nil). Will be nil until one of those methods is called.

rtk.Image.h number or nil read-only

The height in pixels of the image as set by create() or load() (default nil). Will be nil until one of those methods is called.

rtk.Image.density number read/write

The pixel density factor of the image, which controls how the image is drawn relative to rtk.scale. Specifically, rtk.scale.value is divided by density when drawn, so a pixel density of 1.0 (default) is scaled directly by rtk.scale.value, while a density of 2.0 is drawn at half rtk.scale.value.

This can be used to define high-DPI or "retina" images. Note that w and h are not adjusted according to density and will reflect the image's true/intrinsic size. It is most useful when combined with rtk.MultiImage, which can represent many DPI variants of the same image.

rtk.Image.path string or nil read-only

The image path that was passed to load() or nil if load() wasn't called (default nil).

rtk.Image.rotation number read-only

The current rotation of the image in degrees as passed to rotate().

rtk.Image.id number or nil read-only

The numeric id that represents the image buffer within REAPER. This value is auto-generated and is unique to the image buffer, although multiple rtk.Image objects can share the same id if viewport() is used.

Methods

rtk.Image(w, h, density)

Constructor to create a new image resource.

If the dimensions are specified, the image will be reserved from REAPER and sized accordingly, where all pixels will default to transparent. Otherwise, the object will be inert until either create(), load(), or resize() are explicitly called.

-- Creates a new image and immediately loads from file
local img = rtk.Image():load('image.jpg')

-- Creates a new blank 24x24 image
local img2 = rtk.Image(24, 24)
-- This is equivalent
img = rtk.Image():create(24, 24)
Parameters
w (number or nil)

if specified, creates a new image with the given width

h (number or nil)

if specified, creates a new image with the given height

density (number or nil)

the image's pixel density (defaults to 1.0 if nil)

Return Values
(rtk.Image)

the new instance

rtk.Image:create(w, h, density)

Assigns a new image buffer with the specified dimensions.

After this method returneds, a new id will be assigned to the image. The alpha channel of image will be fully transparent by default.

Parameters
w (number)

the width of the image buffer in pixels

h (number)

the height of the image buffer in pixels

density (number or nil)

the image's pixel density (defaults to 1.0 if nil)

Return Values
(rtk.Image)

Returns self for method chaining. A new rtk.Image object is not created here, rather the existing object is updated to use a new buffer.

rtk.Image:load(path, density)

Loads an image from disk.

After this method returns, a new id will be assigned to the image if necessary, and path, w, and h will be updated to reflect the newly loaded image. If the load fails, those attributes will be set to nil.

If no file is found at the given path, it is treated as a path that's relative to the current script path or any non-icon image paths previously registered with rtk.add_image_search_path(), and they will be searched in that order. Unlike icon(), the file extension isn't assumed to be .png -- so it's required -- and the image will not be recolored if it's found in the icon path that doesn't correspond to the active theme.

Example
local img = rtk.Image():load('/path/to/image.jpg')
if not img then
   log.error('image failed to load')
end
Parameters
path (string)

the path to the image file to load

density (number or nil)

the image's pixel density (defaults to 1.0 if nil)

Return Values
(rtk.Image or nil)

returns self if the load was successful for method chaining, otherwise if the load failed then nil is returned.

rtk.Image:pushdest()

Pushes this image's buffer onto the stack for off-screen drawing.

All subsequent drawing operations will be directed to the image's buffer. The image must have a valid id, which means create() or load() must first have been called.

You must call popdest() after you're done drawing. Failure to do so will result in either a blank window or, more likely, a runtime error.

rtk.Image:popdest()

Pops this image's buffer off the stack for off-screen drawing. It must be the current drawing target or a runtime error will occur.

After this method returns, the previous image buffer from before pushdest() was called will be restored as the current drawing target.

rtk.Image:clone()

Clones the current image contents into a new rtk.Image object with a new image buffer.

Return Values
(rtk.Image)

a new rtk.Image object with a copy of the current image contents.

rtk.Image:resize(w, h, clear)

Resizes the current image to new dimensions.

If necessary, create() is implicitly called.

Parameters
w (number)

the desired width in pixels of the image

h (number)

the desired height in pixels of the image

clear (boolean or nil)

if true or not provided then clear() is called after resizing, otherwise if false then the image is not cleared. After resizing any existing image data will become corrupt (due to stride changes) so you almost certainly want to clear, but if you plan to draw over the entire image after resizing you can pass false here as a small optimization.

Return Values
(rtk.Image)

returns self for method chaining

rtk.Image:scale(w, h, mode, density)

Returns a new image with the current image scaled to the given resolution.

Example
local scaled = rtk.Image.icon('32-delete'):scale(18)
Parameters
w (number or nil)

the target width in pixels, or nil to use the h parameter and preserve aspect

h (number or nil)

the target height in pixels, or nil to use the w parameter and preserve aspect

mode (modeconst or nil)

the drawing mode used to blit the scaled image (default when nil is DEFAULT).

density (number or nil)

the pixel density of the new scaled image, or nil to retain the source image's density

rtk.Image:clear(color)

Clears the image either to the given color or to fully transparent.

If a color is provided, the image will be filled with that color, otherwise the alpha channel is fully set to 0.

Parameters
color (colortype or nil)

the color to clear the image to, or nil to clear the image to transparency (where all pixels have an alpha of 0)

Return Values
(rtk.Image)

returns self for method chaining

rtk.Image:viewport(x, y, w, h, density)

Creates a new rtk.Image that is a viewport into the current image.

This allows you take a slice of the current image to create a smaller view within it, without needing to create a new image buffer and copy the image over.

A typical use case is having a single image that contains multiple icons (i.e. a sprite) and you want to use a specific region of the sprite, for example as a button icon.

The returned new rtk.Image will have the same id as the current image because they share the same underlying image buffer.

Parameters
x (number or nil)

the x offset within the source image (nil is 0)

y (number or nil)

the y offset within the source image (nil is 0)

w (number or nil)

the width of new image (nil extends to the right edge of the source)

h (number or nil)

the height of the new image (nil extends to the bottom edge of the source)

density (number or nil)

the pixel density the new image (defaults to current image's density if nil)

Return Values
(rtk.Widget)

a new image object that represents the slice within the source image

rtk.Image:draw(dx, dy, a, scale, clipw, cliph, mode)

Draws the full image to the current drawing target.

This is a convenience method for blit() that offers positional parameters for the most common drawing operations.

Parameters
dx (number or nil)

the x offset within the current drawing target (defaults to 0)

dy (number or nil)

the y offset within the current drawing target (defaults to 0)

a (number or nil)

the opacity level to blend the image onto the current target from 0.0 to 1.0 (defaults to 1.0)

scale (number or nil)

the scale multiplier for the target image (defaults to 1.0)

clipw (number or nil)

the width beyond which the image will be clipped (default to no clipping)

cliph (number or nil)

the height beyond which the image will be clipped (defaults to no clipping)

mode (modeconst or nil)

a bitmap of drawing mode constants (defaults to DEFAULT).

Return Values
(rtk.Image)

returns self for method chaining

rtk.Image:blit(attrs)

Draws a region of the image onto a drawing target, or another image onto this image.

Whereas draw() satisfies the most common use cases, blit() provides a more comprehensive interface, abstracting REAPER's native gfx.blit() function with additional features and conveniences.

This method takes a table of attributes where every possible field has some sane default. In fact, calling this method without any arguments will default to drawing the image to the top left of the current drawing target.

The attrs table can contain the following fields, all of which are optional:

  • src (rtk.Image or numeric image id): the source image that is to be drawn. If not specified, the rtk.Image that blit() is called upon is the image source, but if src is another image, then the current image is used as the drawing target. In other words, if src is defined, it draws onto us, otherwise we draw onto the current drawing target.
  • sx: x offset within the source image (defaults to x)
  • sy: y offset within the source image (defaults to y)
  • sw: the width of the source image to draw (defaults to w)
  • sh: the height of the source image to draw (defaults to h)
  • dx: x offset within the drawing target where sx begins (defaults to 0)
  • dy: y offset within the drawing target where sy begins (defaults to 0)
  • dw: the target width for the destination. If this different than sw then the image width is scaled to fit dw. (Defaults to sw * scale.)
  • dh: the target height for the destination. If this different than sh then the image height is scaled to fit dh. (Defaults to sh * scale.)
  • scale: the scale of the destination image, which is only used if dw or dh are not defined (defaults to 1.0)
  • clipw: clips the drawn image to this width (defaults to no clipping of width)
  • cliph: clips the drawn image to this height (defaults to no clipping of height)
  • mode: a bitmap of mode constants (defaults to DEFAULT)
Example
-- Draws the image at 50,100 in the current drawing target at 50% opacity
-- and scaled 150%.
local img = rtk.Image():load('portrait.jpg')
img:blit{dx=50, dy=100, alpha=0.5, scale=1.5}

-- Draws whatever is on the current drawing target to the image.  This
-- trick is used by widgets like rtk.Viewport to support translucent
-- overlays.
--
-- In this example, we're calling from within a hypothetical widget's
-- _draw() function where the calculated geometry attributes are available.
local img = rtk.Image:create(self.calc.w, self.calc.h)
img:blit{src=gfx.dest, sx=self.calc.x, sy=self.calc.y, mode=rtk.Image.FAST_BLIT}
Parameters
attrs (table or nil)

a table of fields as described above

Return Values
(rtk.Image)

returns self for method chaining

rtk.Image:recolor(color)

Changes all pixels in the image to the given color while respecting the alpha channel.

The image is mutated in situ. If you don't want that you can clone() it first. This uses filter() under the hood, by first multiplying all pixels (except alpha) with 0, and then adding the supplied color.

Parameters
color (colortype)

the color to change all pixels to

Return Values
(rtk.Image)

returns self for method chaining

rtk.Image:filter(mr, mg, mb, ma, ar, ag, ab, aa)

Applies an effect to the image by multiplying or adding values to individual channels.

The image is mutated in situ. If you don't want that you can clone() it first.

Parameters
mr (number)

the amount to multiply all pixels in the red channel

mg (number)

the amount to multiply all pixels in the green channel

mb (number)

the amount to multiply all pixels in the blue channel

ma (number)

the amount to multiply all pixels in the alpha channel

ar (number)

the value to add to all pixels in the red channel

ag (number)

the value to add to all pixels in the green channel

ab (number)

the value to add to all pixels in the blue channel

aa (number)

the value to add to all pixels in the alpha channel

Return Values
(rtk.Image)

returns self for method chaining

rtk.Image:rect(color, x, y, w, h, fill)

Draws a rectangle on the image in the given color.

Parameters
color (colortype)

the color of the rectangle

x (number)

the x offset within the image for the left edge of the rectangle

y (number)

the y offset within the image for the top edge of the rectangle

w (number)

the width of the rectangle

h (number)

the height of the rectangle

fill (boolean or nil)

whether the rectangle should be filled (defaults to false)

Return Values
(rtk.Image)

returns self for method chaining

rtk.Image:blur(strength, x, y, w, h)

Blurs a region of the image.

REAPER's blur capability is a bit crap, being both slow and ugly, but this can be useful in certain circumstances. Just don't expect the same quality you get from a Gaussian blur.

Parameters
strength (number or nil)

the number of passes, where large values increase the level of blur (default 20)

x (number or nil)

the x offset within the image to start blurring (default 0)

y (number or nil)

the y offset within the image to start blurring (default 0)

w (number or nil)

the width of the blur region (default full image width)

h (number or nil)

the height of the blur region (default full image height)

Return Values
(rtk.Image)

returns self for method chaining

rtk.Image:flip_vertical()

Flips the image vertically in place.

The image is mutated in situ. If you don't want that you can clone() it first.

Return Values
(rtk.Image)

returns self for method chaining

rtk.Image:rotate(degrees)

Rotates the image.

The rotation is non-destructive: it only applies to how the image is blitted.

Not fully implemented

This is a work-in-progress and doesn't work properly in all cases. For example, it doesn't work with scaling or cloning. The usefulness is very limited at the moment. Expect weird behavior.

Parameters
degrees (number)

the rotation in degrees

Return Values
(rtk.Image)

returns self for method chaining

rtk.Image:refresh_scale()

Widgets using rtk.Image objects invoke this whenever rtk.scale.value has changed. This is a no-op with rtk.Image itself, but subclasses may use this to implement adaptive behaviors. For example, rtk.MultiImage implements this method to switch images based on current DPI requirements.