| MENU
- Intro To Imageing
Lingo
- SETPIXEL FUNCTION:
- COLOR DATA TYPE:
- GETPIXEL FUNCTION:
- DRAW FUNCTION:
- FILL FUNCTION:
- COPYPIXELS AND DUPLICATE:
Intro To Imaging Lingo:
Basic Imaging Lingo
Provided by Zevan Renteren
Loosely defined, imaging
lingo is a set of functions
that allow you to alter
the image data of the stage, image objecs, cast members and RealMedia sprites.
If you already feel comfortable with imaging lingo,take a look at the next
tutorial "Optimizing
Imaging Lingo".
Lets start off by creating a simple director file:
Go to the property inspector (CTRL+ALT+S), select the movie tab and change
the stage size to 640 x 480. Then, set your framerate to 60fps by going to
your Control
Panel (CTRL+2).
Now create a frame script that looks like this:
on beginSprite me
end
on prepareFrame me
end
It is important to note that beginSprite on a framescript works the same way
as it would on a regular behavior. It is also important to note that when working
with imaging lingo, the best place to do your drawing is on prepareFrame not
exitFrame or enterFrame.
The first thing you need to understand in order to use imaging lingo is the image
object. Every bitmap,text or vector castmember has an image object. This is where
the graphical information is stored, width, height, bitdepth, alpha information
etc... We can access the image object of a castmember as follows:
member("myMember").image
We can also create an image object on the fly and store it inside a variable:
myImage = image(100,100,32)
The above line of code creates a 100px by 100px image with a bit depth of 32.
So the agruments are:
image(width, height,
bitdepth)
There isn't much that an image object can do alone, but with a few functions
its possible to create some great effects and do things that would be tedius
to do with just sprites.
Just as we can access the image object of a castmember, we can access the image
object of the stage:
(the stage).image
SETPIXEL FUNCTION:
We can use a function called setPixel to set the color of a pixel inside any
image object. To set a pixel on the stage to red at point(100,100), we would
do as follows:
(the stage).image.setPixel(100,100,rgb(255,0,0))
The setPixel function takes parameters for location of the pixel and color of
the pixel. So the arguments are:
myImage.setPixel(locH,locV,color)
If you aren't familiar with the color data type "rgb(255,0,0)", don't worry,
I'll explain it in a moment. For now, add a line of code to your frame script:
on beginSprite me
end
on prepareFrame me
(the stage).image.setPixel(the mouseH, the mouseV,rgb(255,0,0))
end

Now run the movie and move your mouse around the stage. The reason it doesn't
draw one continuous line is because the mouse refresh rate is somewhat slow...
I think 40 times per second (not sure if thats the exact number). When your done,
make sure to stop your movie.
COLOR DATA TYPE:
The color data type is very simple to understand. The rgb stands for red green
blue and the parameters for the rgb data type are in that order. Each parameter
has a range from 0 to 255. So, black is rgb(0,0,0), white is rgb(255,255,255),
green is rgb(0,255,0) etc... The color data type can also take a hexidecimal
argument like this:
rgb("FF0000")
GETPIXEL FUNCTION:
The GetPixel function simply returns the value of a pixel at a given coardinate:
myColor = (the stage).image.getPixel(100,100)
This example sets the variable myColor to the rgb value of point(100,100) of
the stage. So, the arguments are:
myImage.getPixel(locH,locV)
To test out the getPixel function:
Import any colorful image into your cast and then place it on sprite channel
1. Now Enter this code into your prepareFrame handler:
put (the stage).image.getPixel(the mouseH,the mouseV)
Your code should look like this:
on beginSprite me
end
on prepareFrame me
put (the stage).image.getPixel(the mouseH,the mouseV)
end

When you run the script, move your mouse over the sprite. The color directly
under the mouse is shown in the message window.
DRAW FUNCTION:
Imaging lingo's draw function can draw lines, ovals, rectangles etc... If we
want to draw a red line from point(0,0) to point(100,100) on the stage we would
do as follows:
(the stage).image.draw(point(0,0),point(100,100),rgb(255,0,0))
or
(the stage).image.draw(0,0,100,100,rgb(255,0,0))
Those two lines do the exact same thing. I preffer using the latter syntax.
So the arguments are:
(the stage).image.draw(point 1, point 2, color)
Throw that line of code into your prepareFrame handler and take a look at the
result:
on beginSprite me
end
on prepareFrame me
(the stage).image.draw(point(0,0),point(100,100),rgb(255,0,0))
end

The draw function normally takes a property list as its last argument. The reason
we didn't need to do that above is because the default shape type for the draw
function is a line. If we want to draw the same line using the a property list
argument, we would write:
(the stage).image.draw(0,0,100,100,[#shapeType: #line, #color: rgb(255,0,0)])
This looks a bit complex, but it is rather simple to understand. The #shapeType
property can be set to #line, #oval, #rectangle or #roundRect. So to draw a red
rectangle, we would write:
(the stage).image.draw(rect(0,0,100,100),[#shapeType: #rect, #color: rgb(255,0,0)])
or
(the stage).image.draw(0,0,100,100,[#shapeType: #rect, #color: rgb(255,0,0)])
Once again I preffer using the latter syntax. Just incase your not sure, the
rect data type works as follows:
rect(left,top,right,bottom)
or
rect(point(locH,locV),point(locH,locV))
The rect data type tends to confuse at first, so make sure you understand it
fully. You can experiment by setting the rect of a sprite:
sprite(1).rect = rect(0,0,100,100)
Playing with the values will help you understand. Try:
sprite(1).rect = rect(0,0,the mouseH,the mouseV)
There is one other property we can use in the property list argument for the
draw function. That property is #lineSize. This controls the thickness of the
line we are drawing with. So to draw a 3px thick red line from point(0,0) to
point(100,100). We would write:
(the stage).image.draw(0,0,100,100,[#shapeType: #line, #lineSize: 3, #color: rgb(255,0,0)])
These lines start to get a little long, so we can use \ to seperate them into
multiple lines:
(the stage).image.draw(0,0,100,100,
\
[#shapeType: #line, #lineSize: 3,
\
#color: rgb(255,0,0)])
Now, try out a couple variations of the draw function. Experiment with different
parameters until you understand it fully.
Example:
on beginSprite me
end
on prepareFrame me
(the stage).image.draw(rect(0,0,100,100), \
[#shapeType: #rect, #lineSize: 3, #color: rgb(255,0,0)])
(the stage).image.draw(0,0,100,100, \
[#shapeType: #rect, #color: rgb(255,0,0)])
(the stage).image.draw(100,100,200,200, \
[#shapeType: #oval, #color: rgb(255,0,255)])
(the stage).image.draw(70,80,230,220, \
[#shapeType: #oval, #lineSize: 3, #color: rgb(0,121,255)])
(the stage).image.draw(270,80,430,220, \
[#shapeType: #roundRect, #lineSize: 23, #color: rgb(0,0,0)])
-- draw ten lines
repeat with i = 1 to 10
-- increment offset by 5
_offset= _offset + 5
-- draw line
(the stage).image.draw(100,100+_offset,200,200+_offset, [#shapeType: #line,
#color: rgb(0,0,255)])
end repeat
end
FILL FUNCTION:
The fill function is almost exactly like the draw function. Either delete or
save your draw function experiment, then try this line out in your prepareFrame
handler:
(the stage).image.fill(0, 0, 120, 100,
\
[#shapeType: #oval, #lineSize: 5, #color: rgb(155, 255, 0),
\
#bgColor: rgb(255, 0, 0)])
Your code should look like this:
on beginSprite me
end
on prepareFrame me
-- its strange that the #bgColor property
controls the line color
(the stage).image.fill(10, 10, 120, 100,
\
[#shapeType: #oval, #lineSize: 5, #color: rgb(255, 255, 0), \
#bgColor: rgb(255, 0, 0)])
end
If you have basic lingo skills and understand these functions, you should be
able to go and create your own paint program.
COPYPIXELS AND DUPLICATE:
Now things start to get a little more complex. The copyPixels function can take
a little while to get used to because it is easy to mix up its parameters. Copy
pixels copies a rectangular portion from an image and then draws that portion
to another image.
If we want to copy an image named myImage to the stage we would write:
(the stage).image.copyPixels(myImage,myImage.rect,myImage.rect)
The first argument is the source image (the image we are copying from). The second
argument is the destination rectangle. This tells the copyPixels function where
to draw the portion of the image that we are copying. The last image is the source
or rectangle, this tells the copyPixels function what portion we are copying
from. The destination rectangle can be used to scale images and the source rectangle
can be used to crop images. Lets try it out:
Create a new bitmap member (CTRL+5) and draw a couple different colored shapes.
Name that member "myImageMember".

This code will copy that member to the stage using copyPixels:
-- create a variable to refference the image of "myImageMember"
property myImage
on beginSprite me
-- set myImage as a refference
to the image of "myImageMember"
myImage = member("myImageMember").image
end
on prepareFrame me
-- copy myImage to the stage
(the stage).image.copyPixels(myImage,myImage.rect,myImage.rect)
end
Run the code.
It is important to understand that by setting myImage to the image of member "myImageMember" we
are not making a duplicate of the image object in "myImageMember", we are creating
a direct refference to it. In other words, if you set a pixel on myImage, you'll
be setting a pixel on member("myImageMember").image. This is not what your going
to want to use. Most of the time, your going to want to make a duplicate of the
image. Doing this is much faster and keeps your original image intact. How do
you create a duplicate?
The duplicate function returns a copy of an image object that is then stored
in RAM. This is what we will use anytime we want to use an image object from
the cast.
Instead of:
-- set myImage as a refference to the image of "myImageMember"
myImage = member("myImageMember").image
We use:
-- make a duplicate copy of "myImageMember" and
store in memory
myImage = member("myImageMember").image.duplicate()
This is an extremely important concept to understand. If you don't fully understand
it, just remember to use the latter syntax and as we go on with the tutorial
it will become more clear to you. So the revised code looks like:
property myImage
on beginSprite me
-- make a duplicate copy of "myImageMember" and
store in memory / myImage variable
myImage = member("myImageMember").image.duplicate()
end
on prepareFrame me
-- copy myImage to the stage (source image,
destination rect, source rect)
(the stage).image.copyPixels(myImage,myImage.rect,myImage.rect)
end

Lets look at another copyPixels example. Lets say we want to copy the image of "myImageMember" to
the stage at twice the size. We would need to scale or multiply the destination
rectangle by 2. So we would write:
property myImage
on beginSprite me
-- make a duplicate copy of "myImageMember" to
store in memory
myImage = member("myImageMember").image.duplicate()
end
on prepareFrame me
-- copy myImage to the stage (source image,
destination rect, source rect)
(the stage).image.copyPixels(myImage,myImage.rect*2,myImage.rect)
end
Try it out.

If we wanted to crop the image in half we could do:
property myImage
property cropRect
on beginSprite me
myImage = member("myImageMember").image.duplicate()
cropRect = rect(0,0,myImage.width
,myImage.height/2)
end
on prepareFrame me
-- copy myImage to the stage (source image,
destination rect, source rect)
(the stage).image.copyPixels(myImage,cropRect,cropRect)
end

Now lets try animating. We do this by changing the values of the destination
rect in our prepareFrame handler:
property myImage
property counter
on beginSprite me
-- make a duplicate copy of "myImageMember" to
store in memory
myImage = member("myImageMember").image.duplicate()
end
on prepareFrame me
-- increment
counter = counter + 1
-- copy myImage to the stage (source image, destination rect, source rect)
(the stage).image.copyPixels(myImage,myImage.rect+counter,myImage.rect)
end

Notice the trails? This occurs because we are setting pixels on the stage to
the color of the image, but not setting them back. So, to avoid this we need
to continually draw a color to the background:
property myImage
property redImage
property counter
on beginSprite me
-- make a duplicate copy of "myImageMember" to
store in memory
myImage = member("myImageMember").image.duplicate()
-- create image the size of the stage
redImage= image(640,480,32)
-- fill it with red
redImage.fill(0,0,640,480,rgb(255,0,0))
end
on prepareFrame me
-- draw red background
(the stage).image.copyPixels(redImage,rect(0,0,640,480),rect(0,0,640,480))
-- increment counter
counter = counter + 1
-- copy myImage to the stage (source image,
destination rect, source rect)
(the stage).image.copyPixels(myImage,myImage.rect+counter,myImage.rect)
end

Lets move the image with the mouse, replace the last copyPixels line with:
-- create rect that will move with the mouse
mouseRect = rect(the mouseH -
myImage.width/2, \
the mouseV - myImage.height/2,
\
the mouseH + myImage.width/2,
\
the mouseV + myImage.height/2)
-- copy myImage to the stage (source image,
destination rect, source rect)
(the stage).image.copyPixels(myImage,mouseRect,myImage.rect)
Now take some time to play around with your own variations.
If you feel comfortable with copyPixels you've gotten past the hardest part.
Lets take a look at the optional parameter list argument. This argument of the
copyPixels function allows us to draw the pixels using ink effects and blend
(opacity). If we wanted to draw an image to the stage at 50% we would write:
-- draw red background
(the stage).image.copyPixels(redImage,rect(0,0,640,480),rect(0,0,640,480))
-- copy myImage to the stage (source
image, destination rect, source rect)
(the stage).image.copyPixels(myImage,myImage.rect,myImage.rect,[#blend:50])
The blend property can have a value from 0-100. I prefer to use the #blendlevel
parameter. This is exactly the same except it has a range of 0-255. So to do
the same thing we would write:
-- draw red background
(the stage).image.copyPixels(redImage,rect(0,0,640,480),rect(0,0,640,480))
-- copy myImage to the stage (source
image, destination rect, source rect)
(the stage).image.copyPixels(myImage,myImage.rect,myImage.rect,[#blendlevel:128])
Now try this:
-- draw red background
(the stage).image.copyPixels(redImage,rect(0,0,640,480),rect(0,0,640,480),[#blendlevel:20])
-- create rect that will move with the
mouse
mouseRect = rect(the mouseH - myImage.width/2, \
the mouseV - myImage.height/2, \
the mouseH + myImage.width/2, \
the mouseV + myImage.height/2)
-- copy myImage to the stage (source image,
destination rect, source rect)
(the stage).image.copyPixels(myImage,mouseRect,myImage.rect)

By changing the opacity of the background, we slowly erase the trails and create
a fake motion blur. This is an effect that imaging lingo is know for, despite
the fact that it can be done in the exact same way with sprite trails. That certainly
doesn't make it any less pleasing.
The ink effects open the doors to many possibilites. They allow us to alter images
before we display them on the stage and create realtime image filters. To invert
an image as we display it we would write:
(the stage).image.copyPixels(myImage,mouseRect,myImage.rect,[#ink:#NotCopy])
or:
(the stage).image.copyPixels(myImage,mouseRect,myImage.rect,[#ink:4])
Try it out in your prepareFrame handler.
property myImage
on beginSprite me
myImage = member("myImageMember").image.duplicate()
end
on prepareFrame me
(the stage).image.copyPixels(myImage,myImage.rect,myImage.rect,[#ink:#NotCopy])
end

Here is a list of the different ink effects. Note that you can use either a number
of a symbol to set the #ink property.
0--Copy
1--Transparent
2--Reverse
3--Ghost
4--Not copy
5--Not transparent
6--Not reverse
7--Not ghost
8--Matte
9--Mask
32--Blend
33--Add pin
34--Add
35--Subtract pin
36--Background transparent
37--Lightest
38--Subtract
39--Darkest
40--Lighten
41--Darken
Take some time and experiment with these. Its easy to create strange and ugly
effects, but an understanding of what each ink effect does will allow you to
write realtime filters like: brightness and contrast, hue and saturation, emboss,
grayscale and many others. The last aspect of the copyPixels function that we
are going to talk about is another facet to the destination rectangle argument.
Unlike the source destination rectangle, it has the ability to take a quad value
as input. This is useful for create 3d effects, rotating and distorting images.
Try this out:
property myImage
property redImage
on beginSprite me
myImage = member("myImageMember").image.duplicate()
-- create image the size of the stage
redImage= image(640,480,32)
-- fill it with red
redImage.fill(0,0,640,480,rgb(255,0,0))
end
on prepareFrame me
-- draw red background
(the stage).image.copyPixels(redImage,rect(0,0,640,480),rect(0,0,640,480))
-- [upper left,upper right, lower right,
lower left ]
myQuad = [point(0,0),point(100,20),point(300,300),point(0,100)]
(the stage).image.copyPixels(myImage,myQuad,myImage.rect)
end

That should be enough to get your started exploring the possibilites of imaging
lingo. If your comfortable with what I've covered here, move onto the next tutorial "Optimizing
Imaging Lingo." This is a short tutorial that will explain a few simple ways
to improve the performance of your imaging lingo projects.
|