Functions are the part of the FXScript language that does the actual
work. Some functions might perform a basic blur on an image, others might
color correct based on user input.
This page discusses a few basic ideas about functions, and talks about
a few of the FXScript functions I've used. Most functions are very similar,
and the definition of one leads to understanding of another. Not every functions is covered here, but these explanations should provide
a basic understanding of how all FXScript functions work.
The basic anatomy of a function starts with the name of the function
followed by parentheses containing a value or values. Whatever is included
in the parentheses is the value the function will start with. Different
functions require different types of data.
Some FXScript functions return a result immediately, some place results
into target variables. Functions with a specified destination can not
be used in place of a value. Functions with only one input can usually
be used in place of a value. For example the function Integer(3.14)
will return 3 and can be used anywhere a number would appear.
In a way, mathematical parentheses are the simplest functions, and also
demonstrate the way a single-value function can be used while scripting:
(3+4) could be used instead of 7, and (Integer(3.14)
+ 4) would also return 7.
Everything in FXScript seems to happen twice. Functions are applied to
each frame, first for the desktop display and then again for the video
output. On older machines (like mine, unfortunately) the time between
previewing to the desktop and video output is quite nautical.
Though this might seem completely lacking in common sense, there is something
of a logical explanation for working like this. Depending on zoom settings,
interlacing and several other factors, the dimensions of the desktop preview
and the video output are different. Because of this difference, raw values
determined by the script will change. Also, if FireWire preview is disabled
or a different final format is being used, why bother wasting the processor
cycles on rendering the extra output? (I'm not sure if that is true or
not). I wonder if on dual-processor machines the desktop preview is sent
to one processor and the DV frame is sent to the other?
Still, I wonder if this is something of a hack, introduced after Apple
purchased Final Cut Pro and remade it into a firewire-DV editor. Would
things be faster if Final Cut Pro only rendered the full-size frame and
then used QuickTime to down-scale it onto the screen? Oh well, it's still
a great program, and the programmers obviously knew what they were doing.
Viewing at 100% with non-square pixels is the most accurate way of previewing
filter results. All other viewing combinations will not show exactly what
is on the video monitor. With these viewing settings most all of the more
problematic dual-values match up between the video monitor and the desktop.
I'm not really into benchmarks, but I wonder if this setting increases
The math functions are largely self-explanatory, generally identical to a standard scientific calculator.
Returns a positive integer for a given numerical value, essentially stripping the sign from the number. Abs(-4)
Rounds towards zero, this has the effect of removing decimal amounts from numbers, returning only their whole integers.
The results of rounding towards zero mean that Integer(9.97)
and Integer(9.01) will both return 9. Most programming languages seem to offer many methods of rounding (up, down, towards zero, nearest integer) but FXScript seems limited to this method. Thankfully, every FXScript function requiring an integer seems to default to this behavior. If you need to round to a specific decimal place, multiply by a factor of ten, apply the integer function, then divide by the same power of ten.
Returns the square root of the value.
The value is raised to the power in the exponent. Power(3, 2) would be the same as 32 and would return 9.
This is used to return positive or negative based on the value. It will return -1, 0 or 1, depending on the input.
All of these work just like the buttons on a calculator.
DimensionsOf(image, width, height)
This function assigns the height and width of the contents of an
image buffer into two floating point variables. Replace the width
and height placeholders with floating point variables. Dest,
Src1, Src2 or any other image buffer can
replace the image placeholder, this will be the image whose dimensions
are measured. The numeric values for height and width will replace
the contents of whatever variables the script specifies.
Returns the dimensions of an image buffer as a four-point array. The variable for result must be a four-point array, meaning a point variable which will hold four points. These points describe the corners of the image. Four-point dimensions are very useful for BlitRect and Region copying. The corner-points map as follows:
This returns a single value representing the pixel aspect ratio
of the image specified. Replace the image placeholder
with the name of an image buffer. AspectOf can be used anywhere in
the script just like a float variable. I've used this in combination
with the integer() function to determine if the output
is interlaced or not to sync duration on my Text
Bugger script. Interlaced NTSC video output (all I have to test
with) returns a value of 2.2. This is one of the values revealed by
Joe's Multi-Value Tester.
Returns the angle between two points. This is the compliment to DistTo, measuring the angle of the triangle connecting two points. AngleTo is demonstrated in Joe's Point Value Tester.
Interpolate(p1, p2, percent, result)
Interpolate returns a point at the specified percentage between the two point values. P1 and p2 are point values, percent is a number between 0 and 1. The result must be placed into a point variable. Interpolate is demonstrated in Joe's Point Value Tester.
Functions not covered: CenterOf, Grid, Mesh,
This function does exactly what it sounds like it would do, it draws dots in varying shapes and colors. I found that the softness setting was a little strange. It seems to mix in the full opacity color component of whatever color the target image is, creating a halo of sorts around the shape. Most of the attributes of this function are self-explanatory, dest is the target image buffer, point/poly is where the shape will appear. Shape uses one of the three shape constants, kRound, kSquare or kDiamond. Size, softness and substeps are all integer values, substeps refers to the number of steps used to create soft edges.I haven't experimented much with DrawSoftDot and poly variables, so I can't comment on how those work. Examples of DrawSoftDot can be seen in Building Joe's Pixelizer and Joe's Point Value Tester.
This blurs all channels of an image buffer including the alpha channel.
The source (srcImage) and destination(destImage)
image buffers can not be the same or visual feedback will occur. Radius
sets the amount of blur, and aspect defines the square
relationship of the pixels. Values seem to work between 0.1 and 5.
numbers below 1 will distort the blur vertically, numbers between
1 and 5 will distort horizontally. Vertical distortion seems capable
of a much more extreme effect.
This allows for selective blurring of specific channels in an image.
SrcImage, destImage, radius and
aspect are the same as the basic Blur function.
DoAlpha, doRed, doGreen and
doBlue are Boolean switches which tell BlurChannel
to process those channels or not. Boolean values are either off or
on, represented by a 0 or a 1. To blur only
the alpha channel from the image in src1 to dest,
the code would look like this: BlurChannel(src1, dest, radius, 1, 0, 0, 0, Aspect)
SrcImage and destImage are the same as
in the other two blur functions. hDist and vDist
set how far in each direction the function will blur the source image.
I don't know why this isn't just an angle, but the explanation
of Joe's Motion Blur contains a simple way to convert angle information
into horizontal and vertical values. Steps sets how smooth
the blur will be, increasing this value will add substantial render
times to any filter using the MotionBlur function.
This function is not one of Final Cut Pro's shining examples of greatness.
Most digital imaging MotionBlurs work by shifting the source image
equal distances from the center and mixing those offset images back
into the source. This is usually done once for each step of the blur.
For whatever reason, Final Cut Pro's Motion Blur seems really slow
A 3x3 Matrix adjustment, this function uses a 3x3 matrix to adjust the intensite of channels in srcImage, placintg hthe result into destImage. Matrix is a 3x3 array containing adjustment values. The two float arrays are offsets which are added to the source and destination image buffers when performing the transformation. The Final Cut Pro manual indicates the offset values should be 0 for RGB to RGB conversions.
Level maps are used to apply tonal and color corrections to images. The four 256-index array maps each contain values between 0 and 1. Src is the original image, dest is where the resulting image will go. Use the FXScript Constant LinearRamp to leave a channel unchanged. For much more information about LevelMap operations, see Building Joe's Levels.
This moves image data between channels. The placeholders src and dest refer to the source and destination image buffers. ChannelCopy can pull from the same image buffer it's targeting or can move data between two different image buffers.
The listed channel indicators (copyAlpha, copyRed, copyGreen & copyBlue) are target channels, their sources are specified with the FXScript Constantskalpha, kred, kgreen, kblue, knone. Whatever constant appears in a target position will be copied in the destination image. To fill a destination image with the red channel of the source, try:
ChannelCopy(src, dest, knone, copyRed, copyRed, copyRed)
Applies a convolution kernel to the to srcImage, placing the result of the convolution into srcImage. Kernel is a 3x3 matrix array which determines the effect of the convolution. Convolution kernels can be used to create all sorts of classic digital effects including sharpening, blurring, edge-enhancement. See Joe's Convolve Matrix Tester to try some convolution effects and read more about 3x3 matrix operations at the bottom of the FXScript Variables page.
This function fills an image buffer with the color specified. alphaValue, redValue, greenValue & blueValue are integer values from 0-255.
One great thing about ChannelFill is that it can be used to fill some channels while leaving others untouched. To skip a channel during the fill operation, specify it's value as knone instead of a number.
Functions not covered:Diffuse, DiffuseOffset,
RadialBlur, Blend, ChannelMultiply
This is a row and column offset, which can shift rows left and right, and columns up and down. The areas to be offset are defined by an array which matches the height and width of the image. Numeric values in these arrays specify the amount to offset each row.
Functions not covered: Cylinder, Fisheye, Whirlpool,
Ripple, Wave, PondRipple, Displace
Matte simply overlays one image onto another using opacity as the
blending method. OverImage and baseImage are the two source images
that will be mixed, destImage is where the result will go. The result
image can be placed directly into either of the two source buffers.
Amount is a decimal value between 0 and 1, corresponding to percentages
of opacity. Type is sets whether the filter will consider an alpha
channel or not when mixing the image buffers. While the manual says
values can be kAlpha, kWhite, kBlack,
I've only gotten results with kAlpha.
Multiply, Screen, Overlay,
These are the standard set of composite modes available. The order
for these modes is the opposite of Matte, the top image (Photoshop orientation)
comes second in the required parameters.
Difference, Add and Subtract
These seem to only work with RGB images, YUV Images will color shift
and act unpredictably. These also seem to affect the alpha channel and
can lead to unwanted transparency, though this behavior is infuriatingly inconsistent. Check the source code for Final Cut Pro's Unsharp Mask filter, there is evidence that even the programmers working on FXScript at Apple had problems with the Subtract mode. Difference mode does not offer an
opacity slider and only applies at 100%. I created a solution which
is featured on the FXScript page for Joe's
Not much to say about this one, it simply inverts the image in srcImage and places the result into destImage. This function can use the same image as both source and destination.
This function selectively inverts one or more channels from srcImage and places the result into destImage. DoAlpha, doRed, doGreen and doBlue are Boolean switches which tell the function which channels to invert. These switches can be triggered with true/false or the binary integers 1 and 0.
ImageAND, ImageOR, ImageXOR
These three logical operators combine image pixels according to simple logical rules: AND: When both inputs are the true, the result is true. OR: When either of the inputs is true, the result is true. XOR: When only one of the inputs is true, the result is true. (exclusive OR)
The functions work in either direction, results are not changed by switching the order of the input image buffers. The following table illustrates the logic used to determine the result pixel (1 = white/true, 0 = black/false):
Often one of the input images may need to be inverted to achieve the desired result. Inverting everything (including the output) may produce results equal to using a different operation (i.e.. invert both inputs and the output and AND becomes OR).
Unfortunately the results of these operations usually have hard tonal breaks and other visual artifacts. The compositing methods Add, Subtract and Difference are perform very similarly to And, Or and Xor, however the results are usually smoother. The following list of substitutions can be used instead of AND, OR and XOR:
ImageAnd - Use Subtract and pre-invert the second image.
ImageOr - Basically the same effect as Add
ImageXor - Difference produces a smoother result.
I had some problems getting Subtract and Difference to work dependably on alpha channels, so I sometimes
The Hypermedia Image Processing Reference section on Logical Operators was a great help in figuring out how these work.
I found grayscale results from these functions to be hard to anticipate and full of artifacts (a known side-effect of logical operations). If you are interested in trying to get a handle on how these operations work beyond 1-bit images, this Hexadecimal Logic Table might help.
SrcImage and destImage are the same as in all
the other filters. The colorTarget values of 0 - 255 correspond
to the pixel color components upon which the keying will be based. The
colorPass values set the tolerance of how close a source
color can be before it will be included in the keyed area. I noticed that
Final Cut Pro's built-in filters all used a value range of 0 - 511 for
colorPass values. In Joe's
Color Glow I used one variable slider for tolerance and applied it
equally to all three colorPass values. Softness
defines up to 255 levels of selection in the keying result. A high softness
value will produce a very gentle transition to the keyed areas, a value
of zero will produce a hard-edged (aka bitmapped, aliased or binary) selection
that is only on and off. FillRGB is a Boolean switch that
will fill the RGB channels in addition to the alpha channel. Switching
this to false (or 0) restricts the keying result to only the alpha channel.
For some reason, I got the best results with this filter when the
the FXScript was YUVAware.
I think it might have something to do with converting to the RGB color
space before keying, but whatever the reason, my results would not
line up between the desktop and video output unless I started in YUV,
converted to RGB and then applied RGBColorKey().
Functions not covered: BlueScreen, GreenScreen,
BGDiff and YUVColorKey.
NumToString(number, string, format)
This function translates a number variable (float, see FXScript Variables) to a string. The result might look similar, but this is necessary to include a numeric variable value in a text string such as a reporting filter. Number refers to a float variable, or one element of a point or color. String is the predefined variable which will hold the translated string equivalent of number. Format is the numeric format to use for the translation (see FXScript Constants).
Functions not covered: StringToNum, Length,
CharsOf, ASCIIOf, ASCIIToString,
CountTextLines, FindString, MeasureString,
MeasureStringPlain and ResetText.
getVideo(srcClip, timeOffset, destImage)
This is the Clip function which has the most useful result. GetVideo fills the image buffer destImage with a frame from srcClip. The frame is specified by timeOffset, which is the frame count starting at the absolute beginning of srcClip, in and out points do not affect the offset value.
This function places the Reel name of srcClip into the string variable string. Unfortunately there doesn't seem to be anyway to get the clip name or any other information besides the original reel the clip was captured from.
GetLimits(srcClip, duration, offset)
Despite what the FXScript documentation says, this function places two items of information about srcClip, duration and offset, into predefined float variables. The total frame count of the clip, ignoring in and out points, will be placed into the duration variable.
The frame count of the clip's in point will be assigned to the variable offset. If the clip is placed in the timeline (clip1 or clip2, see FXScript Constants), the inpoint of the current usage will be returned. If the clip is in the browser with an in point defined, the position of the current in point will be returned, if no in point is specified in the clip, offset will be assigned zero.
Functions not covered: getTimeCode.
Returns a random number between min and max. The number returned can equal either the minimum or maximum value (x >= min && x <= max). Read RandomSeed below for a brief note on psuedo-random numbers and how to affect the random values returned by Random.
This determines how a script will generate all random values. The default, unspecified value is zero, which tells Final Cut Pro to generate a different set of random values for every random function throughout the script. Any value besides zero will generate a specific set of random values which can be repeated between frames. Joe's Pixelizer uses RandomSeed() to control placement of randomly spaced blocks between frames.
Computers usually only generate pseudo-random numbers. Explaining true random numbers requires more math than I'm willing to commit to right now. Psuedo-random numbers are generated from a random seed which will produce a repeatable set of numbers. Changing the random seed will select from a different set of numbers.
ColorOf(image, point, color)
Measures the color of the pixel at the coordinates point in image and places those values into color. I used this function to capture the colors of an image in Joe's Pixelizer before drawing the shapes with DrawSoftDot.
This function fills destImage with a bilinear gradation centered on centerPoint and crossing angle. This type of gradation extends from a center axis equally in two opposite directions. Width refers to the width of the centerline, not the length of the gradation, specified by softness. Dither and gaussian are binary switchesl dither dithers the gradation, gaussian uses a gaussian curve intead of a linear ramp when drawing the softness. ForeColor and backColor are the two colors which define the colors used in the final gradation. Aspect is the current pixel aspect ratio of the destination image buffer. An explanation of how to prevent color banding and create transparent gradations is explained on the Building Joe's Gradients page.
This function fills the destImage buffer with random pixel noise between the specified colors. Each of the channel pairs specify the minimum and maximum range of values the function will use to generate the noise. The makeColors is a binary switch, setting it to 1 will fill each of the four channels with different noise patterns. Setting makeColors to zero will cause all of the channels to use the same noise pattern, which results in a monochrome image with transparent darks areas.
CircleLight is nearly identical to Highlight, described above. The only difference is that, because this function draws a circular gradation, there is no need for an angle measurement. Other than that, the position of the attributes is ordered differently.
Functions not covered: SysTime, RamdomTable, Truncate,
PointTrack and Assert.