LiveScript ImageData双线性插值(Bilinear interpolation)图像缩放算法

浅析 HTML5 Canvas 的几种中文字体缩小方案》中用到的双线性插值算法的LiveScript实现.

require! 'prelude-ls': {map, round, floor, ceiling, sqrt, abs, sum}

bilinear-interpolation-put = (zoom, src-image) ->
  color = (image, offset, point) -->
    if point.x >= image.width or point.y >= image.height
      if offset is 3
        255
      else
        0
    else
      image.data[(image.width * point.y + point.x) * 4 + offset]
  [R, G, B, A] = map (color src-image), [0 to 3]
  canvas = document.create-element \canvas
  canvas.width = src-image.width * zoom
  canvas.height = src-image.height * zoom
  ctx = canvas.get-context \2d
  dst-image = ctx.create-image-data canvas.width, canvas.height
  for dst-x from 0 til canvas.width
    for dst-y from 0 til canvas.height
      src = x: dst-x / zoom, y: dst-y / zoom
      lt = x: floor(src.x), y: floor src.y
      rt = x: ceiling(src.x), y: floor src.y
      lb = x: floor(src.x), y: ceiling src.y
      rb = x: ceiling(src.x), y: ceiling src.y
      weight-mean = (src, points) ->
        weights = []
        sf = []
        for p, i in points when p.x < src-image.width and p.y < src-image.height
          w = sqrt(abs(p.x - src.x) * abs(p.y - src.y))
          w = 1 / w if w isnt 0
          weights.push w
          sf.push ((w, p)->
            (f) ->
              w * f p
          )(w, p)
        (f) ->
          s = sum map ((s) -> s(f)), sf
          if sum(weights) is 0 then 0 else s / sum weights
      get-weight-mean = weight-mean src, [lt, rt, lb, rb]
      dst-i = (dst-y * canvas.width + dst-x) * 4
      dst-image.data[dst-i + 0] = round get-weight-mean R
      dst-image.data[dst-i + 1] = round get-weight-mean G
      dst-image.data[dst-i + 2] = round get-weight-mean B
      dst-image.data[dst-i + 3] = round get-weight-mean A
  ctx.put-image-data dst-image, 0, 0
  canvas