• 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