If you have your own tutorials or open source and would like to share your Director knowledge please send them to info@shocksites.com. We will review them, post it and give full credit to the developer.
Current Open Source and Tutorials

MENU

  1. Intro To Imageing Lingo
  2. SETPIXEL FUNCTION:
  3. COLOR DATA TYPE:
  4. GETPIXEL FUNCTION:
  5. DRAW FUNCTION:
  6. FILL FUNCTION:
  7. 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.