# ImageData:mapPixel

Transform an image by applying a function to every pixel.

This function is a higher-order function. It takes another function as a parameter, and calls it once for each pixel in the ImageData.

The passed function is called with six parameters for each pixel in turn. The parameters are numbers that represent the x and y coordinates of the pixel and its red, green, blue and alpha values. The function should return the new red, green, blue, and alpha values for that pixel.

```function pixelFunction(x, y, r, g, b, a)
-- template for defining your own pixel mapping function
-- perform computations giving the new values for r, g, b and a
-- ...
return r, g, b, a
end
```

In versions prior to 11.0, color component values were within the range of 0 to 255 instead of 0 to 1.

## Function

### Synopsis

```ImageData:mapPixel( pixelFunction, x, y, width, height )
```

### Arguments

`function pixelFunction`
Function to apply to every pixel.
Available since LÖVE 0.9.0
`number x (0)`
The x-axis of the top-left corner of the area within the ImageData to apply the function to.
`number y (0)`
The y-axis of the top-left corner of the area within the ImageData to apply the function to.
`number width (ImageData:getWidth())`
The width of the area within the ImageData to apply the function to.
`number height (ImageData:getHeight())`
The height of the area within the ImageData to apply the function to.

Nothing.

## Examples

### Brighten an image

```local function brighten(x,y, r,g,b,a)
r = math.min(r*3, 1)
g = math.min(g*3, 1)
b = math.min(b*3, 1)
return r,g,b,a
end
imageData:mapPixel(brighten)
```

### Add colored stripes to an image

```local function stripey(x,y, r,g,b,a)
r = math.min(r * math.sin(x*100)*2, 1)
g = math.min(g * math.cos(x*150)*2, 1)
b = math.min(b * math.sin(x* 50)*2, 1)
return r,g,b,a
end
imageData:mapPixel(stripey)
```

### Tint grayscaled image

```local tintColor = {r=0.6, g=0.5, b=0.3} -- Sepia tone.

local function tint(x,y, r,g,b,a)
local gray = (r+g+b) / 3
if gray < 0.5 then
-- Between black and tintColor.
r = 2 * gray*tintColor.r
g = 2 * gray*tintColor.g
b = 2 * gray*tintColor.b
else
-- Between tintColor and white.
r = 2 * (gray + tintColor.r - gray*tintColor.r) - 1
g = 2 * (gray + tintColor.g - gray*tintColor.g) - 1
b = 2 * (gray + tintColor.b - gray*tintColor.b) - 1
end
return r,g,b,a
end

imageData:mapPixel(tint)
```

### A more efficient method using FFI

Here we invert the colors for two images - one using `mapPixel` and one using FFI functionality. What we should see is that the FFI method is a lot faster (albeit a bit less convenient).

Note: We're reading and writing directly from/to memory. Not being careful will likely lead to crashes, or worse!

```function love.load()
collectgarbage("stop")

-- Use mapPixel.
local imageData = love.image.newImageData("bigTexture.png")
local startTime = love.timer.getTime()

imageData:mapPixel(function(x,y, r,g,b,a)
return 1-r, 1-g, 1-b, a
end)

local time1 = love.timer.getTime() - startTime
_G.image1   = love.graphics.newImage(imageData)

-- Use FFI.
local imageData  = love.image.newImageData("bigTexture.png")
local pointer    = require("ffi").cast("uint8_t*", imageData:getFFIPointer()) -- imageData has one byte per channel per pixel.
local pixelCount = imageData:getWidth() * imageData:getHeight()
local startTime  = love.timer.getTime()

for i = 0, 4*pixelCount-1, 4 do -- Loop through the pixels, four values at a time (RGBA).
pointer[i  ] = 255 - pointer[i  ] -- r  (Remember that we're working with bytes and not normalized color values.)
pointer[i+1] = 255 - pointer[i+1] -- g
pointer[i+2] = 255 - pointer[i+2] -- b
end

local time2 = love.timer.getTime() - startTime
_G.image2   = love.graphics.newImage(imageData)

-- Results. (FFI can be more than ten times faster!)
print(string.format("Times: mapPixel=%.4f FFI=%.4f", time1, time2))
print(string.format("Difference: FFI is %.1f times faster", time1/time2))
end

function love.draw()
-- Show that the resulting images look the same.
local windowWidth = love.graphics.getWidth()
local x1          = 0
local x2          = windowWidth / 2
love.graphics.draw(image1, x1,0, 0, windowWidth/image1:getWidth())
love.graphics.draw(image2, x2,0, 0, windowWidth/image2:getWidth())
end
```