- Jump To … +
  analyze.coffee autoload.coffee blender.coffee calculate.coffee caman.coffee convert.coffee event.coffee filter.coffee io.coffee layer.coffee logger.coffee module.coffee pixel.coffee plugin.coffee renderer.coffee store.coffee util.coffee blenders.coffee filters.coffee size.coffee blur.coffee camera.coffee compoundBlur.coffee edges.coffee posterize.coffee presets.coffee rotate.coffee stackBlur.coffee threshold.coffee

- # camera.coffee

- ¶

      vignetteFilters =
        brightness: (rgba, amt, opts) ->
          rgba.r = rgba.r - (rgba.r * amt * opts.strength)
          rgba.g = rgba.g - (rgba.g * amt * opts.strength)
          rgba.b = rgba.b - (rgba.b * amt * opts.strength)
          rgba

        gamma: (rgba, amt, opts) ->
          rgba.r = Math.pow(rgba.r / 255, Math.max(10 * amt * opts.strength, 1)) * 255
          rgba.g = Math.pow(rgba.g / 255, Math.max(10 * amt * opts.strength, 1)) * 255
          rgba.b = Math.pow(rgba.b / 255, Math.max(10 * amt * opts.strength, 1)) * 255
          rgba

        colorize: (rgba, amt, opts) ->
          rgba.r -= (rgba.r - opts.color.r) * amt;
          rgba.g -= (rgba.g - opts.color.g) * amt;
          rgba.b -= (rgba.b - opts.color.b) * amt;
          rgba

      Filter.register "vignette", (size, strength = 60) ->
        if typeof size is "string" and size.substr(-1) is "%"
          if @dimensions.height > @dimensions.width
            size = @dimensions.width * (parseInt(size.substr(0, size.length - 1), 10) / 100)
          else
            size = @dimensions.height * (parseInt(size.substr(0, size.length - 1), 10) / 100)

        strength /= 100
        center = [@dimensions.width / 2, @dimensions.height / 2]
        start = Math.sqrt Math.pow(center[0], 2) + Math.pow(center[1], 2)
        end = start - size
        bezier = Calculate.bezier [0, 1], [30, 30], [70, 60], [100, 80]

        @process "vignette", (rgba) ->
          loc = rgba.locationXY()
          dist = Calculate.distance loc.x, loc.y, center[0], center[1]

          if dist > end
            div = Math.max 1, ((bezier[Math.round(((dist - end) / size) * 100)]/10) * strength)

            rgba.r = Math.pow(rgba.r / 255, div) * 255
            rgba.g = Math.pow(rgba.g / 255, div) * 255
            rgba.b = Math.pow(rgba.b / 255, div) * 255

          rgba

      Filter.register "rectangularVignette", (opts) ->
        defaults =
          strength: 50
          cornerRadius: 0
          method: 'brightness'
          color:
            r: 0
            g: 0
            b: 0

        opts = Util.extend defaults, opts

        if not opts.size
          return @
        else if typeof opts.size is "string"
          percent = parseInt(opts.size, 10) / 100
          opts.size =
            width: @dimensions.width * percent
            height: @dimensions.height * percent
        else if typeof opts.size is "object"
          for dim in ["width", "height"]
            if typeof opts.size[dim] is "string"
              opts.size[dim] = @dimensions[dim] * (parseInt(opts.size[dim], 10) / 100)
        else if opts.size is "number"
          size = opts.size
          opts.size =
            width: size
            height: size

        if typeof opts.cornerRadius is "string"
          opts.cornerRadius = (opts.size.width / 2) * (parseInt(opts.cornerRadius, 10) / 100)

        opts.strength /= 100

- ¶

  Since pixels are discreet, force size to be an int

        opts.size.width = Math.floor opts.size.width
        opts.size.height = Math.floor opts.size.height
        opts.image =
          width: @dimensions.width
          height: @dimensions.height

        if opts.method is "colorize" and typeof opts.color is "string"
          opts.color = Convert.hexToRGB opts.color

        opts.coords =
          left: (@dimensions.width - opts.size.width) / 2
          right: @dimensions.width - opts.coords.left
          bottom: (@dimensions.height - opts.size.height) / 2
          top: @dimensions.height - opts.coords.bottom

        opts.corners = [
          {x: opts.coords.left + opts.cornerRadius, y: opts.coords.top - opts.cornerRadius},
          {x: opts.coords.right - opts.cornerRadius, y: opts.coords.top - opts.cornerRadius},
          {x: opts.coords.right - opts.cornerRadius, y: opts.coords.bottom + opts.cornerRadius},
          {x: opts.coords.left + opts.cornerRadius, y: opts.coords.bottom + opts.cornerRadius}
        ]

        opts.maxDist = Calculate.distance(0, 0, opts.corners[3].x, opts.corners[3].y) - opts.cornerRadius

        @process "rectangularVignette", (rgba) ->
          loc = rgba.locationXY()

- ¶

  Trivial rejects

          if (loc.x > opts.corners[0].x and loc.x < opts.corners[1].x) and (loc.y > opts.coords.bottom and loc.y < opts.coords.top)
            return rgba
          if (loc.x > opts.coords.left && loc.x < opts.coords.right) && (loc.y > opts.corners[3].y && loc.y < opts.corners[2].y)
            return rgba

- ¶

  Need to figure out which section we're in. First, the easy ones, then the harder ones.

          if loc.x > opts.corners[0].x && loc.x < opts.corners[1].x && loc.y > opts.coords.top

- ¶

  top-middle section

            amt = (loc.y - opts.coords.top) / opts.maxDist
          else if loc.y > opts.corners[2].y && loc.y < opts.corners[1].y && loc.x > opts.coords.right

- ¶

  right-middle section

            amt = (loc.x - opts.coords.right) / opts.maxDist
          else if loc.x > opts.corners[0].x && loc.x < opts.corners[1].x && loc.y < opts.coords.bottom

- ¶

  bottom-middle section

            amt = (opts.coords.bottom - loc.y) / opts.maxDist
          else if loc.y > opts.corners[2].y && loc.y < opts.corners[1].y && loc.x < opts.coords.left

- ¶

  left-middle section

            amt = (opts.coords.left - loc.x) / opts.maxDist
          else if loc.x <= opts.corners[0].x && loc.y >= opts.corners[0].y

- ¶

  top-left corner

            radialDist = Caman.distance(loc.x, loc.y, opts.corners[0].x, opts.corners[0].y)
            amt = (radialDist - opts.cornerRadius) / opts.maxDist
          else if loc.x >= opts.corners[1].x && loc.y >= opts.corners[1].y

- ¶

  top-right corner

            radialDist = Caman.distance(loc.x, loc.y, opts.corners[1].x, opts.corners[1].y)
            amt = (radialDist - opts.cornerRadius) / opts.maxDist
          else if loc.x >= opts.corners[2].x && loc.y <= opts.corners[2].y

- ¶

  bottom-right corner

            radialDist = Caman.distance(loc.x, loc.y, opts.corners[2].x, opts.corners[2].y)
            amt = (radialDist - opts.cornerRadius) / opts.maxDist
          else if loc.x <= opts.corners[3].x && loc.y <= opts.corners[3].y

- ¶

  bottom-left corner

            radialDist = Caman.distance(loc.x, loc.y, opts.corners[3].x, opts.corners[3].y)
            amt = (radialDist - opts.cornerRadius) / opts.maxDist

          return rgba if amt < 0
          return vignetteFilters[opts.method](rgba, amt, opts)