- 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

- # layer.coffee

- ¶

  The entire layering system for Caman resides in this file. Layers get their own canvasLayer objectwhich is created when newLayer() is called. For extensive information regarding the specifics of howthe layering system works, there is an in-depth blog post on this very topic. Instead of copying the entirety of that post, I'll simply point you towards the blog link.

  However, the gist of the layering system is that, for each layer, it creates a new canvas element and then either copies the parent layer's data or applies a solid color to the new layer. After some (optional) effects are applied, the layer is blended back into the parent canvas layer using one of many different blending algorithms.

  You can also load an image (local or remote, with a proxy) into a canvas layer, which is useful if you want to add textures to an image.

      class Caman.Layer
        constructor: (@c) ->

- ¶

  Compatibility

          @filter = @c

          @options =
            blendingMode: 'normal'
            opacity: 1.0

- ¶

  Each layer gets its own unique ID

          @layerID = Util.uniqid.get()

- ¶

  Create the canvas for this layer

          @canvas = if exports? then new Canvas() else document.createElement('canvas')

          @canvas.width = @c.dimensions.width
          @canvas.height = @c.dimensions.height

          @context = @canvas.getContext('2d')
          @context.createImageData @canvas.width, @canvas.height
          @imageData = @context.getImageData 0, 0, @canvas.width, @canvas.height
          @pixelData = @imageData.data

- ¶

  If you want to create nested layers

        newLayer: (cb) -> @c.newLayer.call @c, cb

- ¶

  Sets the blending mode of this layer. The mode is the name of a blender function.

        setBlendingMode: (mode) ->
          @options.blendingMode = mode
          return @

- ¶

  Sets the opacity of this layer. This affects how much of this layer is applied to the parent layer at render time.

        opacity: (opacity) ->
          @options.opacity = opacity / 100
          return @

- ¶

  Copies the contents of the parent layer to this layer

        copyParent: ->
          parentData = @c.pixelData

          for i in [0...@c.pixelData.length] by 4
            @pixelData[i]   = parentData[i]
            @pixelData[i+1] = parentData[i+1]
            @pixelData[i+2] = parentData[i+2]
            @pixelData[i+3] = parentData[i+3]

          return @

- ¶

  Fills this layer with a single color

        fillColor: -> @c.fillColor.apply @c, arguments

- ¶

  Loads and overlays an image onto this layer

        overlayImage: (image) ->
          if typeof image is "object"
            image = image.src
          else if typeof image is "string" and image[0] is "#"
            image = $(image).src

          return @ if not image

          @c.renderer.renderQueue.push
            type: Filter.Type.LoadOverlay
            src: image
            layer: @

          return @

- ¶

  Takes the contents of this layer and applies them to the parent layer at render time. This should never be called explicitly by the user.

        applyToParent: ->
          parentData = @c.pixelStack[@c.pixelStack.length - 1]
          layerData = @c.pixelData

          for i in [0...layerData.length] by 4
            rgbaParent =
              r: parentData[i]
              g: parentData[i+1]
              b: parentData[i+2]
              a: parentData[i+3]

            rgbaLayer =
              r: layerData[i]
              g: layerData[i+1]
              b: layerData[i+2]
              a: layerData[i+3]

            result = Blender.execute @options.blendingMode, rgbaLayer, rgbaParent

            result.r = Util.clampRGB result.r
            result.g = Util.clampRGB result.g
            result.b = Util.clampRGB result.b
            result.a = rgbaLayer.a if not result.a?

            parentData[i]   = rgbaParent.r - (
              (rgbaParent.r - result.r) * (@options.opacity * (result.a / 255))
            )
            parentData[i+1] = rgbaParent.g - (
              (rgbaParent.g - result.g) * (@options.opacity * (result.a / 255))
            )
            parentData[i+2] = rgbaParent.b - (
              (rgbaParent.b - result.b) * (@options.opacity * (result.a / 255))
            )

      Layer = Caman.Layer