Skip to content
Tags

10. Playing with images

March 26, 2013

Images are pretty important in Codea, and you can do some cool stuff with them.

I’ve put together a little project to illustrate. I may extend it later as I think of more…It downloads an internet image for my backdrop, and another image which I will mess with and draw onto my backdrop image. It shows how to copy parts of images and draw onto an image rather than the screen. And more. This post is packed.

Loading images into Codea

First, you should already be familiar with loading images from your library, as in

Img=readImage('Documents:myImage')

You can also load images from your iPad’s photo library. It’s one of the options in the Documents folder of your Codea library, press it when selecting a picture, and you’ll be asked to choose a picture from your photo library, give it a name, and it will be imported into your Documents folder.

Internet
Finally, you can download pictures directly from the internet, like so

http.request(url, function(img,h,c) A=img end)

(NB if you’re thinking what is this function in the middle of the line, go to the very bottom, where I explain further).

This command tries to download the url you provide, and it returns an image, and other items of information which we will ignore. We simply assign the image to our own image name (A above).

There is one problem with this, which is that downloads don’t happen immediately, so you can’t go straight on and draw your image. Your draw function has to wait, somehow, until all the downloads are finished.

The next problem is that when the image is downloaded, you may want to do some setting up before drawing anything. You could put something in the function above, like this, where I call the function setupImage() when the image is downloaded:

http.request(url, function(img,h,c) A=img setupImage() end)

..but if, say, you’re downloading more than one image, you’ll have several of these internet requests, and they could arrive in any order, and you’ll probably want to wait for all of them to arrive before setting up.

State variable
What I’ve done in my example, is to get the draw function to manage things. It uses a “state” variable, which is important in animation programs, so it’s a useful thing to know about. This is just a variable which tells draw what is currently happening. In my case, I only have two states, “LOADING” while my images are downloading, and “RUNNING”, when the downloads are done.

So in setup, I start my downloads going, as above, then set state=”LOADING”. Here is my code. Note that for testing purposes, I print a message when each download completes.

function setup()
    print('Please wait while I load the images from the internet')
    http.request('https://img1.minebook.me/gallery/48755_mordor.png',
        function(i,a,b) mordor=i print('loaded') end)
    http.request('http://www.portent.com/images/2012/04/nazgul-cyclery-logo-long.png',
        function(i,a,b) nazgul=i print('loaded') end)
    state='LOADING'
end

The draw function checks the state value. If it is “RUNNING”, then it can go ahead and draw, but if it is “LOADING”, then it has work to do. I have two images downloading, so I can get draw to see if they are complete by just asking if they equal nil. If either of them is nil, it returns without doing anything, ie it waits. If both are complete, then it calls a setup function and sets state=”RUNNING”.

So here is draw()

function draw()
    background(40, 40, 50)
    if state=='LOADING' then
        if mordor==nil or nazgul==nil then return --wait for internet image before drawing
        else
            setupImages() -- setup
            scroll={img=mordor,x=0,y=0}
            state='RUNNING'
        end
    end
    sprite(mordor,0,0)
end

Note I’ve also created a variable called scroll containing the mordor image and an x and y value. You’ll see why, later.

Scrolling the image
Now I want do some nice things with my images. My mordor image is too wide for my screen, but it would be cool to be able to scroll left and right with my finger, rather than the alternative of shrinking it to fit the screen. This means changing the x value in the sprite command, when we draw mordor. I always find these things tricky, but we can start with figuring out the scrolling limits.

First, if x=0, then we will be at the extreme left of the picture and cannot scroll left.

Second, if we are at the extreme right, then the right of the picture lines up with the right of the screen, and the picture is wider than the screen, so the left hand side of the picture must be at
x=WIDTH – mordor.width. (ie a negative value).

So we have to restrict x in our sprite command so it is between WIDTH-mordor, and 0.

But how do we detect sideways scrolling? We use the touch function provided by Codea. If you just add this code

function touched(touch)
end

then Codea automatically provides a whole lot of information in the touch parameter. The item that interests us is deltaX, which tells us how much the user’s finger moved since the last draw, in the x direction. So we can use that to slide the picture left and right, within the limits we set above. We’ll need a variable that will tell draw what the x position is, and that is scroll.x, which I created in draw when the pictures finished downloading.

function touched(touch)
    if scroll then
        scroll.x=scroll.x+touch.deltaX
        if scroll>0 then 
            scroll.x=0 
        elseif scroll.x+scroll.img.width

Then in draw, I draw my mordor sprite at position scroll.x, scroll.y instead of 0,0.

Modding an image
I want to superimpose the nazgul image on the background, but it has a logo that I don’t want, and I’d like to change the colors.

I can get rid of the logo by clipping the image, by copying just part of the image to a new image, like this code, which copies the left 1/3 of nazgul to a new image

local img=nazgul:copy(0,0,nazgul.width/3,nazgul.height)

Now I’m going to mess with nazgul’s colors. The bicycle is black, but I’ll make it dark red. Note that black pixels have r,g,b of 0,0,0, and so do blank (transparent) pixels, but the difference is that blank pixels have a=0, while a is non zero for black pixels. Hence the if test below.

for i=1,img.width do
        for j=1,img.height do
            local r,g,b,a=img:get(i,j)
            if a>0 and r+g+b==0 then img:set(i,j,110,38,38,255) end
            end
        end
    end

Now for something really, really cool. Instead of having to draw nazgul on top of mordor all the time, I can draw it right onto the mordor image so it becomes part of it. Codea has this neat feature where you can draw onto an image instead of the screen, so you can create and modify your own images. Anyway, I put nazgul over to the right of mordor like this.

setContext(mordor) --draw to the mordor image, not the screen
    sprite(img,mordor.width-img.width,300,100)
    setContext() --back to normal

So now mordor includes the nazgul image.

I should add one other thing. If you want to superimpose one image on another, you have to get rid of the background on it first, ie you want a transparent background. I this case, I chose an image that had this, by searching for png images, which support transparency. You can make image backgrounds transparent using Photoshop etc, but it’s a messy business.

All done

And that’s pretty much it. Here is the final code. Underneath, I’ll explain two things

  • how I found out what colors there were in nazgul, before trying to change them
  • the function thing embedded in the internet request at the top

.
Code here or here.

Out of interest, I’ll share how I found out what colors there were in the nazgul image. I was hoping it only had 2 or 3 so I could make more changes, but it had quite a number. If you look at the code in the setupImages function, you’ll see three lines marked with a comment “A”. If you uncomment these lines, they will create a table of all unique colors, printing them out as they are found. It is very simple indeed. All I do is create a number from the r,g,b values, and use this as an index in my table. So if my first number is 34673, I look up t[34673]. If it is nil, then I haven’t had it before, so I set t[34673]=1, and print out r,g,b. The next time I look up 34673, I will get a value of 1, meaning I’ve already seen it, so I don’t print it out. So I only print colors the first time I see them.

Anonymous functions

Lastly, the callback function embedded in the Internet image request

http.request(url, function(img,h,c) A=img end)

 

is what is called an anonymous function, because it doesn’t have a name.

You could instead specify a function called (say) someFunction to run when the download completes, like this

http.request(url, someFunction)

 

but in our case, all we want to do is assign an image to the result, and so what you are allowed to do is basically write a temporary function instead of calling some other function. Your temporary function doesn’t need a name because it will disappear as soon as it completes. Think of it as just saving you the trouble of having to write a separate function for something pretty trivial.

Advertisement

From → animation

9 Comments
  1. briarfox permalink

    Great tutorials but could you put the code up on pastebin or gist it? Its hard to copy code off the site and all the ” characters are " etc I like running the code first then reading the tutorials.

    • briarfox permalink

      ” show up as & quot ;
      easily fixed in textastic but a pain in codea

  2. Ken Duerden permalink

    Many thanks for the new addition. Your publishing at quite a rate now 🙂

  3. Inanc permalink

    Can you give another link for the code please? I can’t enter pastebin.com

  4. Circussmith permalink

    Just as a side question, I notice that a lot of tutorials use the readImage function instead of just putting sprite(). I saw this on your, and others, excellent physics post. Is there a reason this is preferable?

  5. Echeb permalink

    Hey I realize that this might be slightly stupid, but why do you need the I=1 in there?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: