-------------------------------------------------------------------------------------------------------------- -- DESCRIPTION -- Basic ImageFX -- There are three types: -- (1) Ink Effects (which are quick) -- (2) Pixel Effects (which are bog slow) -- (3) Pixel Convolver Effects (even slower than the pixel effects) -- Note: These effects assume that the image passed in is passed by reference so they don't return anything. -- This means that if you apply the effect to a cast member, then the member itself will change -- keep a backup -- of you castmembers if you are not sure what you're doing. --### example usage -- script("ImageFX3").mMakeMoody( member("SomePicture").image ) -- Created by Luke Wigley -- Last updated 4/6/2002 -- added a couple more pixel effects -- changed the progress bar to only update through every x interation -- Updated 22/3/2002 -- added the convolver scripts -- updated the progress dialog script -- Updated 22/3/2002 -- Created by: -- luke@meccamedialight.com.au -------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------- --- INK EFFECTS (QUICK) -------------------------------------------------------------------------------------------------------------- on mInvert (me, anImage) -- apply image onto itself with not copy ink anImage.copyPixels(anImage, anImage.rect, anImage.rect, [#Ink: 4]) end on mDarkInvert (me, anImage) src = anImage.duplicate() anImage.copyPixels(anImage, anImage.rect, anImage.rect, [#Ink: 4]) anImage.copyPixels(src, anImage.rect, anImage.rect, [#Ink: 35]) end on mOverexpose (me, anImage) -- apply image onto itself with add pin ink anImage.copyPixels(anImage, anImage.rect, anImage.rect, [#Ink: 33]) end on mDesaturate (me, anImage) a = image(anImage.width, anImage.height, 8, #grayscale) a.copypixels(anImage, anImage.rect, anImage.rect) anImage.copyPixels(a, anImage.rect, anImage.rect) end on mSoften (me, anImage) a = image(anImage.width, anImage.height, 8, #grayscale) a.copypixels(anImage, anImage.rect, anImage.rect) anImage.copyPixels(a, anImage.rect, anImage.rect, [#Ink:37]) end on mDullen (me, anImage) a = image(anImage.width, anImage.height, 8, #grayscale) a.copypixels(anImage, anImage.rect, anImage.rect) anImage.copyPixels(a, anImage.rect, anImage.rect, [#Ink:39]) end on mExperiment (me, anImage) src = anImage.duplicate() anImage.copyPixels(anImage, anImage.rect, anImage.rect, [#Ink: 4]) anImage.copyPixels(src, anImage.rect, anImage.rect, [#Ink: 37]) end -------------------------------------------------------------------------------------------------------------- --- OTHER QUICK EFFECTS -------------------------------------------------------------------------------------------------------------- on mPixelate (me, anImage, aScale) if voidP(aScale) then aScale = 8 W = anImage.width / aScale H = anImage.height / aScale buffer = image(W,H, 24) buffer.copyPixels(anImage, buffer.rect, anImage.rect) anImage.copyPixels(buffer, anImage.rect, buffer.rect) end -------------------------------------------------------------------------------------------------------------- ---- PIXEL EFFECTS (SLOW) -------------------------------------------------------------------------------------------------------------- -- Since these effects are slow, they will attempt to display a progress bar -- unless the noFeedback parameter is set to true (note that the progress bar -- will slow them down even further) on mInvertPixels (me, anImage, noFeedback) buffer = anImage.duplicate() mx = buffer.width - 1 my = buffer.height -1 if noFeedback or member("ProgressDialog").type <> #script then repeat with x = 0 to mx repeat with y = 0 to my colour = buffer.getPixel(x,y, #integer) buffer.setPixel(x,y, (16777215 - colour)) end repeat end repeat else prog = script("ProgressDialog").new("Inverting pixels...", "ButtonFactory_Default") maxStep = float(mx) step = 0 -- repeat with x = 0 to mx step = step + 1 cancelled = prog.mShowProgress(step/maxStep) if cancelled then prog.mDestroy() repeat with y = 0 to my colour = buffer.getPixel(x,y, #integer) buffer.setPixel(x,y, (16777215 - colour)) end repeat end repeat prog.mDestroy() end if anImage.copyPixels(buffer,buffer.rect, buffer.rect) end on mDesaturatePixels (me, anImage, noFeedback) buffer = anImage.duplicate() mx = buffer.width - 1 my = buffer.height -1 if noFeedback or member("ProgressDialog").type <> #script then repeat with x = 0 to mx repeat with y = 0 to my colour = buffer.getPixel(x,y) if colour = 0 then next repeat colour.colorType = #RGB newColourVal = (76*colour.red + 150*colour.green + 29*colour.blue)/256 newColour = RGB(newColourVal, newColourVal, newColourVal) buffer.setPixel(x,y, newColour) end repeat end repeat else prog = script("ProgressDialog").new("Desaturating pixels...", "ButtonFactory_Default") maxStep = float(mx) step = 0 -- repeat with x = 0 to mx step = step + 1 cancelled = prog.mShowProgress(step/maxStep) if cancelled then return prog.mDestroy() repeat with y = 0 to my colour = buffer.getPixel(x,y) if colour = 0 then next repeat colour.colorType = #RGB newColourVal = (76*colour.red + 150*colour.green + 29*colour.blue)/256 newColour = RGB(newColourVal, newColourVal, newColourVal) buffer.setPixel(x,y, newColour) end repeat end repeat prog.mDestroy() end if anImage.copyPixels(buffer,buffer.rect, buffer.rect) end on mTweakSaturation (me, anImage, aPercentage, noFeedback) -- tweaks the saturation by specified percentage (0-100) if voidP(aPercentage) then aPercentage = random(90) + 5 buffer = anImage.duplicate() mx = buffer.width - 1 my = buffer.height -1 if noFeedback or member("ProgressDialog").type <> #script then repeat with x = 0 to mx repeat with y = 0 to my colour = buffer.getPixel(x,y) colour.colorType = #RGB maxColour = Max(colour.red,colour.blue,colour.green) if maxColour > 0 then minColour = Min(colour.red,colour.blue,colour.green) sat= (maxColour - minColour)/float(maxColour) tweak = sat * (aPercentage/100.0) * 256 newColourVal = (tweak*colour.red + tweak*colour.green + tweak*colour.blue)/256 newColour = RGB(newColourVal, newColourVal, newColourVal) buffer.setPixel(x,y, newColour) end if end repeat end repeat else prog = script("ProgressDialog").new("Tweaking saturation by " & aPercentage & "% ...", "ButtonFactory_Default") maxStep = float(mx) step = 0 -- repeat with x = 0 to mx step = step + 1 cancelled = prog.mShowProgress(step/maxStep) if cancelled then return prog.mDestroy() repeat with y = 0 to my colour = buffer.getPixel(x,y) colour.colorType = #RGB maxColour = Max(colour.red,colour.blue,colour.green) if maxColour > 0 then minColour = Min(colour.red,colour.blue,colour.green) sat= (maxColour - minColour)/float(maxColour) tweak = sat * (aPercentage/100.0) * 256 newColourVal = (tweak*colour.red + tweak*colour.green + tweak*colour.blue)/256 newColour = RGB(newColourVal, newColourVal, newColourVal) buffer.setPixel(x,y, newColour) end if end repeat end repeat prog.mDestroy() end if anImage.copyPixels(buffer,buffer.rect, buffer.rect) end on mSwitchColours (me, anImage, noFeedback) -- switches the red, blue and green components of each pixel -- (red->blue, green->red, blue->green) buffer = anImage.duplicate() mx = buffer.width - 1 my = buffer.height -1 if noFeedback or member("ProgressDialog").type <> #script then repeat with x = 0 to mx repeat with y = 0 to my colour = buffer.getPixel(x,y) if colour = 0 then next repeat colour.colorType = #RGB newColour = RGB(colour.blue, colour.red, colour.green) buffer.setPixel(x,y, newColour) end repeat end repeat else prog = script("ProgressDialog").new("Switching colours ...", "ButtonFactory_Default") maxStep = float(mx) step = 0 repeat with x = 0 to mx step = step + 1 cancelled = prog.mShowProgress(step/maxStep) if cancelled then return prog.mDestroy() repeat with y = 0 to my colour = buffer.getPixel(x,y) if colour = 0 then next repeat colour.colorType = #RGB newColour = RGB(colour.blue, colour.red, colour.green) buffer.setPixel(x,y, newColour) end repeat end repeat prog.mDestroy() end if anImage.copyPixels(buffer,buffer.rect, buffer.rect) end on mMakeMoody (me, anImage, noFeedback) -- adjusts the colour of a pixel based on its distance from the -- middle of the image buffer = anImage.duplicate() mx = buffer.width -1 my = buffer.height -1 if noFeedback or member("ProgressDialog").type <> #script then midPoint = [mx/2, my/2] maxdistance = sqrt((midPoint[1]*midPoint[1]) + (midPoint[2]*midPoint[2])) repeat with x = 0 to mx repeat with y = 0 to my colour = buffer.getPixel(x,y) distanceFromMiddle = sqrt((x-midPoint[1])*(x-midPoint[1]) + (y-midPoint[2])*(y-midPoint[2])) thisAdjust = distanceFromMiddle / float(maxdistance) colour.red = colour.red - (colour.red*thisAdjust) colour.green = colour.green - (colour.green*thisAdjust) colour.blue = colour.blue - (colour.blue*thisAdjust) newColour = RGB(colour.blue, colour.red, colour.green) buffer.setPixel(x,y,newColour) end repeat end repeat else -- prog = script("ProgressDialog").new("Getting moody...", "ButtonFactory_Default") maxStep = float(mx) step = 0 -- midPoint = [mx/2, my/2] maxdistance = sqrt((midPoint[1]*midPoint[1]) + (midPoint[2]*midPoint[2])) repeat with x = 0 to mx step = step + 1 cancelled = prog.mShowProgress(step/maxStep) if cancelled then return prog.mDestroy() repeat with y = 0 to my colour = buffer.getPixel(x,y) distanceFromMiddle = sqrt((x-midPoint[1])*(x-midPoint[1]) + (y-midPoint[2])*(y-midPoint[2])) thisAdjust = distanceFromMiddle / float(maxdistance) colour.red = colour.red - (colour.red*thisAdjust) colour.green = colour.green - (colour.green*thisAdjust) colour.blue = colour.blue - (colour.blue*thisAdjust) newColour = RGB(colour.blue, colour.red, colour.green) buffer.setPixel(x,y,newColour) end repeat end repeat prog.mDestroy() end if anImage.copyPixels(buffer,buffer.rect, buffer.rect) end on mShuffleNeighbors (me, anImage, percent) -- shuffle pixels around their immediate neighbors if voidP(percent) then percent = 50 buffer = anImage.duplicate() mx = buffer.width my = buffer.height pixelList = [] prog = script("ProgressDialog").new("Diffusing " & percent & "% of the Image...", "ButtonFactory_Default") maxStep = float(mx) step = 0 nList = [[-1,0], [-1,-1], [0,-1], [1,-1], [1,0], [1,1], [0,1], [-1,1]] mx2 = mx -1 my2 = my -1 repeat with x = 2 to mx2 step = step + 1 cancelled = prog.mShowProgress(step/maxStep) if cancelled then return prog.mDestroy() repeat with y = 2 to my2 if random(100) <= percent then a = [x-1, y-1] b = a + nList[random(8)] pa = anImage.getPixel(a[1],a[2], #integer) pb = anImage.getPixel(b[1],b[2], #integer) buffer.setPixel(b[1], b[2], pa) buffer.setPixel(a[1], a[2], pb) end if end repeat end repeat prog.mDestroy() anImage.copyPixels(buffer, buffer.rect, buffer.rect) end on mShufflePixels (me, anImage, percent) -- shuffle pixels around if voidP(percent) then percent = 50 buffer = anImage.duplicate() mx = buffer.width my = buffer.height pixelList = [] prog = script("ProgressDialog").new("Shuffling " & percent & "% of the Image...", "ButtonFactory_Default") maxStep = float(mx) step = 0 i = 0 repeat with x = 1 to mx step = step + 1 cancelled = prog.mShowProgress(step/maxStep) if cancelled then return prog.mDestroy() repeat with y = 1 to my if random(100) <= percent then pLoc = [x-1,y-1] i = i + 1 pixelList.addAt(random(i), pLoc) end if end repeat end repeat prog = script("ProgressDialog").new("Rendering the result...", "ButtonFactory_Default") maxStep = float(pixelList.count) step = 0.0 repeat with i = 1 to pixelList.count step = step + 1 cancelled = prog.mShowProgress(step/maxStep) if cancelled then return prog.mDestroy() a = pixelList[i] if i = pixelList.count then b = pixelList[1] else b = pixelList[i+1] p = anImage.getPixel(a[1],a[2], #integer) buffer.setPixel(b[1], b[2], p) end repeat prog.mDestroy() anImage.copyPixels(buffer, buffer.rect, buffer.rect) end on mExplode (me, anImage, percent) if voidP(percent) then percent = 20 buffer = anImage.duplicate() mx = buffer.width - 1 my = buffer.height -1 prog = script("ProgressDialog").new("Exploding Image...", "ButtonFactory_Default") maxStep = float(mx) step = 0.0 -- midX = mx/2 midY = my/2 scaleX = 4.0/midX scaleY = 4.0/midY repeat with x = 0 to mx step = step + 1 cancelled = prog.mShowProgress(step/maxStep) if cancelled then return prog.mDestroy() repeat with y = 0 to my if random(100) <= percent then r = 0 dX= (x - (midX)) * scaleX * random(3) dY= (y - (midY)) * scaleY * random(3) colour = anImage.getPixel(x,y, #integer) buffer.setPixel(x+dX,y+dY, colour) end if end repeat end repeat prog.mDestroy() anImage.copyPixels(buffer,buffer.rect, buffer.rect) end -------------------------------------------------------------------------------------------------------------- --- PIXEL CONVOLVER EFFECTS (BOG SLOW) -------------------------------------------------------------------------------------------------------------- -- The following use the pixel convolver which is very, very slow. The mPixelConvolve requires the -- "ProgessDialog" utility script - see www.lingoworkshop.com -- Note that similar effects can be achieved using inks (which is much quicker). on mBlur (me, anImage) buffer = anImage.duplicate() aMatrix = [0,1,0,1,4,1,0,1,0] aDivisor = 8 me.mPixelConvolve(buffer, aMatrix, aDivisor) anImage.copyPixels(buffer, buffer.rect, buffer.rect) end on mBlurMore (me, anImage) buffer = anImage.duplicate() aMatrix = [1,2,1,2,4,2,1,2,1] aDivisor = 16 me.mPixelConvolve(buffer, aMatrix, aDivisor) anImage.copyPixels(buffer, buffer.rect, buffer.rect) end on mSharpen (me, anImage) buffer = anImage.duplicate() aMatrix = [0,-1,0,-1,5,-1,0,-1,0] aDivisor = 1 me.mPixelConvolve(buffer, aMatrix, aDivisor) anImage.copyPixels(buffer, buffer.rect, buffer.rect) end on mNeonGlow (me, anImage) buffer = anImage.duplicate() aMatrix = [1,1,1,0,1,0,-1,-1,-1] aDivisor = 1 me.mPixelConvolve(buffer, aMatrix, aDivisor) anImage.copyPixels(buffer, buffer.rect, buffer.rect) end on mEmboss (me, anImage) buffer = anImage.duplicate() aMatrix = [-1,-1,0,-1,1,1,0,1,1] aDivisor = 1 me.mPixelConvolve(buffer, aMatrix, aDivisor) anImage.copyPixels(buffer, buffer.rect, buffer.rect) end on mRandomConlvusion (me, anImage) buffer = anImage.duplicate() aDivisor = 0 aMatrix= [] repeat with i = 1 to 9 v = 4 - random(7) aMatrix[i] = v aDivisor = aDivisor + v end repeat if aDivisor < 1 then aDivisor = 1 me.mPixelConvolve(buffer, aMatrix, aDivisor) anImage.copyPixels(buffer, buffer.rect, buffer.rect) end on mPixelConvolve (me, anImage, aMatrix, aDivisor) -- Pixel convolve a 3 x 3 matrix if voidP(aDivisor) or aDivisor = 0 then alert "No divisor specified" return anImage end if mx = anImage.width my = anImage.height newImage = anImage.duplicate() feedbackObj = script("ProgressDialog").new("Convolving", "ButtonFactory_Default") if feedbackObj.ilk = #instance then numSteps = float(mx) step = 0 else alert "Problem finding feedback object" return anImage end if colourMap = [] repeat with x = 1 to mx step = step + 1 cancelled = feedbackObj.mShowProgress(step/numSteps) if cancelled then return feedbackObj.mDestroy() colourMap.append([]) repeat with y = 1 to my colourMap[x][y] = anImage.getPixel(x-1,y-1) end repeat end repeat mxx = mx -1 myy = my - 1 feedbackObj = script("ProgressDialog").new("Rendering the result...", "ButtonFactory_Default") numSteps = float( mxx ) step = 0 repeat with x = 2 to mxx step = step + 1 cancelled = feedbackObj.mShowProgress(step/numSteps) if cancelled then return feedbackObj.mDestroy() repeat with y = 2 to myy L = x -1 R = x + 1 T = y -1 B = y + 1 ------ build pixel map colours = [] colours[1] = colourMap[L][T] colours[2] = colourMap[x][T] colours[3] = colourMap[R][T] colours[4] = colourMap[L][y] colours[5] = colourMap[x][y] colours[6] = colourMap[R][y] colours[7] = colourMap[L][B] colours[8] = colourMap[x][B] colours[9] = colourMap[R][B] newCol = [0,0,0] repeat with i = 1 to 9 colours[i].colorType = #rgb newCol[1] = newCol[1] + ( colours[i].red * aMatrix[i] ) newCol[2] = newCol[2] + ( colours[i].green * aMatrix[i] ) newCol[3] = newCol[3] + ( colours[i].blue * aMatrix[i] ) end repeat newCol = newCol/ aDivisor newImage.setPixel(x-1,y-1, rgb(newCol[1], newCol[2], newCol[3])) end repeat end repeat feedbackObj.mDestroy() anImage.copyPixels(newImage, anImage.rect, anImage.rect) end