10. Playing with images
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
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.
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.
” show up as & quot ;
easily fixed in textastic but a pain in codea
Many thanks for the new addition. Your publishing at quite a rate now 🙂
Can you give another link for the code please? I can’t enter pastebin.com
ok, I’ll see what I can do, any preferences for location?
see my latest post
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?
Hey I realize that this might be slightly stupid, but why do you need the I=1 in there?
That’s how you do loops in Lua
http://www.dev-hq.net/lua/7–loops