Imaging Functions

Something you want to see in a LiveCode product? Want a new forum set up for a specific topic? Talk about it here.

Moderator: Klaus

Luisa Klose
Posts: 48
Joined: Tue Aug 30, 2011 2:24 pm

Imaging Functions

Post by Luisa Klose » Wed Aug 31, 2011 11:41 pm

Does LiveCode have a way to get and set pixel values? About 10 years ago I wrote a drawing program in Director called PixelToolbox (still available free and downloaded thousands of times a month just from my site) that I would like to translate to LiveCode & develop further. It seems to me that LiveCode has some basic imaging functionality but not enough for something like PixelToolbox.

Dixie
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 1336
Joined: Sun Jul 12, 2009 10:53 am

Re: Imaging Functions

Post by Dixie » Thu Sep 01, 2011 2:37 am

Hi

Look at the 'imageData' property in the dictionary...

Dixie

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4163
Joined: Sun Jan 07, 2007 9:12 pm

Re: Imaging Functions

Post by bn » Thu Sep 01, 2011 8:41 am

Hi Luisa,

have a look at what Wilhlem Sanke does with Livecode/Revolution

http://www.sanke.org/ImageDataArt/index.htm
especially the imageToolKit
and
http://www.sanke.org/PatternArt/index.htm
patternToolKit

or on RevOnline (which is also accessible from within Livecode (user samples)

http://revonline2.runrev.com/stack/470/ ... ker-Plugin

there is a lot you can do with imageData and alphaData in Livecode. As long as the images are small you get reasonable response times.

kind regards

Bernd

Klaus
Posts: 14177
Joined: Sat Apr 08, 2006 8:41 am
Contact:

Re: Imaging Functions

Post by Klaus » Thu Sep 01, 2011 12:34 pm

Hi Luisa,
Luisa Klose wrote:... It seems to me that LiveCode has some basic imaging functionality but not enough for something like PixelToolbox.
I'm afraid this is the case!
RunRev is in fact currently rewriting the complete media/graphics engine, but we do not have a date for this now.


Best

Klaus

Luisa Klose
Posts: 48
Joined: Tue Aug 30, 2011 2:24 pm

Re: Imaging Functions

Post by Luisa Klose » Thu Sep 01, 2011 3:45 pm

Klaus, you will spoil the heck out of me if you make the new set of functions more thorough, easier to use, and faster than Director's functions. If you're not familiar with them, here are most of them:

Code: Select all

copyPixels() - imageObject.copyPixels(sourceImageObject, destinationRect, sourceRect {, parameterList})

fill() - imageObject.fill(left, top, right, bottom, colorObjectOrParameterList)

crop() - imageObject.crop(rectToCropTo)

draw() - imageObject.draw(x1, y1, x2, y2, colorObjectOrParameterList)

image() - image(width, height, bitDepth {, alphaDepth} {, paletteSymbolOrMember})

duplicate() - imageObject.duplicate()

getPixel() - imageObject.getPixel(point(x, y) {, #integer}) 

setPixel() - imageObject.setPixel(x, y, integerValue)

color() - color(#rgb, redValue, greenValue, blueValue)

And several functions for dealing with alpha channels.
By the way, I had to use an "Xtra" to save to several of the formats, and I was never able to find a way to load .ico and .cur files for editing. Could write them but couldn't read them.

If you need anyone to help you evaluate & test...

Thanks, Dixie and Bernd for your responses. Impressed by Wilhelm Sanke's work...

jacque
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 7389
Joined: Sat Apr 08, 2006 8:31 pm
Contact:

Re: Imaging Functions

Post by jacque » Thu Sep 01, 2011 4:30 pm

Most of those are built into the engine already.

copyPixels() - imageObject.copyPixels(sourceImageObject, destinationRect, sourceRect {, parameterList})
Not sure quite what this does, but it is trivial to copy an image. You can either script the copy and paste commands, or easier, use the "clone" command.

fill() - imageObject.fill(left, top, right, bottom, colorObjectOrParameterList)
Script the paint tools. Set the fillColor, choose the bucket tool, and "click at <coord>".

crop() - imageObject.crop(rectToCropTo)
Built into the language, see "crop" in the dictionary.

draw() - imageObject.draw(x1, y1, x2, y2, colorObjectOrParameterList)
Create a new graphic object. Set its points to a list of coordinates.

image() - image(width, height, bitDepth {, alphaDepth} {, paletteSymbolOrMember})
"create image", then set its width, height, and alphamask

duplicate() - imageObject.duplicate()
"clone image 1"

getPixel() - imageObject.getPixel(point(x, y) {, #integer})
You have to cheat for this, it's ugly, but: set the loc of the cursor and then get the mousecolor

setPixel() - imageObject.setPixel(x, y, integerValue)
You can do this with imagedata, but not so easy.

color() - color(#rgb, redValue, greenValue, blueValue)
I'm not sure what this does, but there are a variety of color properties you can set for objects.

And several functions for dealing with alpha channels
You can set an alpha mask on any image by setting its alphaData property.
Jacqueline Landman Gay | jacque at hyperactivesw dot com
HyperActive Software | http://www.hyperactivesw.com

Luisa Klose
Posts: 48
Joined: Tue Aug 30, 2011 2:24 pm

Re: Imaging Functions

Post by Luisa Klose » Thu Sep 01, 2011 5:26 pm

Jacqueline, PixelToolbox's warp function works with copyPixels, as do many of the other functions. It's for copying a part of an image, (or the whole thing), into part of another image, with several parameters including transparency, ink, blend, etc. It's also a quick way to do gaussian blur, unsharp mask and other filters. Here is the Lingo code for the warp function:

Code: Select all

on toolWarp
  -- set state 1 for undo/redo
  member("state1 - " & gSize, gCast).image = member(gSize & "x" & gSize, gCast).image
  -- draw & update preview
  startPoint = point((((the mouseH  - sprite(1).left ) * 2) / gVariable) / 2, (((the mouseV - sprite(1).top) * 2) / gVariable) / 2)
  myCurrentImage = duplicate(member(gSize & "x" & gSize, gCast).image)
  myStartImage = duplicate(myCurrentImage)
  myCurrentPreview = duplicate(member("preview", gCast).image)
  
  tLImage = image(startPoint.locH, startPoint.locV, member(gSize & "x" & gSize, gCast).depth, member(gSize & "x" & gSize, gCast).paletteRef)
  tLImage.copyPixels(myCurrentImage, tLImage.rect, rect(0, 0, startPoint.locH, startPoint.locV))
  tRImage = image(myCurrentImage.width - startPoint.locH, startPoint.locV, member(gSize & "x" & gSize, gCast).depth, member(gSize & "x" & gSize, gCast).paletteRef)
  tRImage.copyPixels(myCurrentImage, tRImage.rect, rect(startPoint.locH, 0, myCurrentImage.width, startPoint.locV))
  bLImage = image(startPoint.locH, myCurrentImage.height - startPoint.locV, member(gSize & "x" & gSize, gCast).depth, member(gSize & "x" & gSize, gCast).paletteRef)
  bLImage.copyPixels(myCurrentImage, bLImage.rect, rect(0, startPoint.locV, startPoint.locH, myCurrentImage.height))
  bRImage = image(myCurrentImage.width - startPoint.locH, myCurrentImage.height - startPoint.locV, member(gSize & "x" & gSize, gCast).depth, member(gSize & "x" & gSize, gCast).paletteRef)
  bRImage.copyPixels(myCurrentImage, bRImage.rect, rect(startPoint.locH, startPoint.locV, myCurrentImage.width, myCurrentImage.height))
  
  repeat while the mouseDown
    myCurrentImage.copyPixels(myStartImage, myStartImage.rect, myStartImage.rect)
    myCurrentImage.copyPixels(tLImage, [point(0, 0), point(startPoint.locH, 0), point((((the mouseH  - sprite(1).left ) * 2) / gVariable) / 2, (((the mouseV - sprite(1).top) * 2) / gVariable) / 2), point(0, startPoint.locV)], tLImage.rect)
    myCurrentImage.copyPixels(tRImage, [point(startPoint.locH, 0), point(myCurrentImage.width, 0), point(myCurrentImage.width, startPoint.locV), point((((the mouseH  - sprite(1).left ) * 2) / gVariable) / 2, (((the mouseV - sprite(1).top) * 2) / gVariable) / 2)], tRImage.rect)
    myCurrentImage.copyPixels(bLImage, [point(0, startPoint.locV), point((((the mouseH  - sprite(1).left ) * 2) / gVariable) / 2, (((the mouseV - sprite(1).top) * 2) / gVariable) / 2), point(startPoint.locH, myCurrentImage.height), point(0, myCurrentImage.height)], bLImage.rect)
    myCurrentImage.copyPixels(bRImage, [point((((the mouseH  - sprite(1).left ) * 2) / gVariable) / 2, (((the mouseV - sprite(1).top) * 2) / gVariable) / 2), point(myCurrentImage.width, startPoint.locV), point(myCurrentImage.width, myCurrentImage.height), point(startPoint.locH, myCurrentImage.height)], bRImage.rect)
    member(gSize & "x" & gSize, gCast).image.copyPixels(myCurrentImage, myCurrentImage.rect, myCurrentImage.rect)
    updateStage
    put (((the mouseH  - sprite(1).left ) * 2) / gVariable) / 2 into field "location status X"
    put (((the mouseV - sprite(1).top) * 2) / gVariable) / 2 into field "location status Y"
    fnUpdatePreview
  end repeat
end
Can you show me an application created with LiveCode that allows the user to pick an rgb color and paint in elegant (and responsive) airbrushed strokes (not the splatters of LiveCode's airbrush) ?

I'll be straightforward with you. If Adobe Director offered me a way to publish apps to the new mobile devices, I wouldn't be here. I like LiveCode a lot, and I can see that it's very powerful. But I can also see that it would be less than satisfying or succesful to tanslate PixeToolbox into LiveCode in its present state.

If RunRev wants to attract more developers, improving the graphics engine is a step in the right direction. I wouldn't make the same mistake that Adobe is making with Director though. It's focus on 3d game development is misguided, and its execution foolish.

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4163
Joined: Sun Jan 07, 2007 9:12 pm

Re: Imaging Functions

Post by bn » Thu Sep 01, 2011 8:50 pm

Hi Luisa,

Colin Holgate and I wrote a proof of principle stack that lets you 'stamp' an image into an image, it was part of his presentation on Livecode, a streaming video presentation

the two parts of the presentation:

http://blog.livecode.tv/2011/04/172/

the sample stack "SimplePaint":

http://blog.livecode.tv/wp-content/uplo ... ePaint.zip


Colin wanted to use this as an iPad app.

Again this is probably not as elaborate an example as you would expect and frankly Livecode has a lot to be desired regarding image manipulation.

The SimplePaint stack just puts the imageData of an image into the imageData of the target image. If you drag the 'stamp' you paint the image repeatedly into the target image. No provisions for blending, transparency. Though one could script that it is a lot of scripting, could be done though. But the limiting step is: Livecode is slow in updating an image if it also has to update the alphaData, for live painting with transparencies I don't think Livecode is really up to that.

Actually it all depends on what size of image your want to work on, and what exactly it is you are doing. I can not test your PixelToolbox since I am on a Mac.

(once you load the image Colin provides in the folder the Reload Image button becomes active and you can erase what you painted, restoring the original image, if you press the shift-key then you erase also with the current paint image. You could load your own png images to paint with)

Kind regards

Bernd

Luisa Klose
Posts: 48
Joined: Tue Aug 30, 2011 2:24 pm

Re: Imaging Functions

Post by Luisa Klose » Fri Sep 02, 2011 12:39 am

Hi, Bernd, very interesting. That is similar to how the soft brushes work in PixelToolbox, with a mask with an alpha channel.

After some tweaking, I was able to get a Shockwave version of PixelToolbox to work. Things that don't work:

Import
Revert
Save As
Save
Copy
Paste
Apply Wallpaper
Export Image
Open Windows Control Panels
Fonts
The Pattern Screen function doesn't work, but if you click on it's little icon, you can choose "Fast Weave" which does.

Since I wrote the program I developed a better airbrush (with some help) that hasn't been integrated.

The URL is: www axiomx com/temp/PixelToolbox htm

Edit to add link for PixelToolbox's pdf manual:

www axiomx com/PixelToolbox/PixelToolbox_guide pdf

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4163
Joined: Sun Jan 07, 2007 9:12 pm

Re: Imaging Functions

Post by bn » Fri Sep 02, 2011 1:11 am

Hi Luisa,

that looks very good.

I am not shure you could replicate everything in Livecode, but I would try it with just small pieces of the PixelToolbox and see how it goes. Since you work on small images it could work. Not shure about the speed of the alpha channel.

Kind regards

Bernd

Luisa Klose
Posts: 48
Joined: Tue Aug 30, 2011 2:24 pm

Re: Imaging Functions

Post by Luisa Klose » Fri Sep 02, 2011 2:46 pm

Thanks, Bernd, I will take your advice. Perhaps I'll do the "fast weave" as a stack to share with the community.

And thanks for inspiring me to do a Shockwave version of PixelToolbox :)

I like your idea of using an image to paint with in the place of a color. PixelToolbox doesn't have that, and I hope you don't mind if I add it as a new brush. I especially like the idea of painting with a sphere.

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4163
Joined: Sun Jan 07, 2007 9:12 pm

Re: Imaging Functions

Post by bn » Fri Sep 02, 2011 4:17 pm

HI Luisa,

I thought you might like this:

I made a stack that makes a color gradient by code. You can also click on a colorwheel and move the mouse to do the gradient dynamically. It is a bit of code to show how imageData in Livecode can be used to "paint".

Kind regards

Bernd


Edit: I deleted the attachement, it is replaced by a stack below.
Last edited by bn on Fri Sep 02, 2011 9:25 pm, edited 1 time in total.

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10043
Joined: Sat Apr 08, 2006 7:05 am
Contact:

Re: Imaging Functions

Post by FourthWorld » Fri Sep 02, 2011 7:40 pm

bn wrote:I made a stack that makes a color gradient by code. You can also click on a colorwheel and move the mouse to do the gradient dynamically. It is a bit of code to show how imageData in Livecode can be used to "paint".
Nicely done, Bernd. Very smooth performance.
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4163
Joined: Sun Jan 07, 2007 9:12 pm

Re: Imaging Functions

Post by bn » Fri Sep 02, 2011 9:23 pm

@ Richard, thank you.

@ Luisa and all:

unfortunately there were bugs in the color libraries that convert RGB values to HSV values and the inverse. They concerned greyscale and white. I corrected the libraries. Now it seems to work nicely, even with greyscale / white /black values.

I upload the corected version, some more comments added to the code too.

Kind regards

Bernd
makeGradient_4.livecode.zip
improved colorLib version
(102.02 KiB) Downloaded 414 times
I will delete the previous version "makeGradient_3"

Luisa Klose
Posts: 48
Joined: Tue Aug 30, 2011 2:24 pm

Re: Imaging Functions

Post by Luisa Klose » Sat Sep 03, 2011 7:04 pm

Wow, friends, the more I see, the more impressed I am with LiveCode, and with the community.

Bernd, I'm going to download the new version of your gradient demonstration and check it out in a little while.

I was able to do a little something to share. My introduction to imaging in LiveCode. After I post it here, I'm going to find out what "Share This Stack..." entails.

Warm regards,

Luisa
Attachments
PixelToolbox_PatternWeaver.zip
(5.15 KiB) Downloaded 400 times

Post Reply