UNPKG

mcanvas

Version:

the image-composer or image-croper that can draw image/text/watermark or crop the image.

171 lines (158 loc) 6.12 kB
import * as StackBlur from 'stackblur-canvas' export function blur(cvs: HTMLCanvasElement, value: number = 20) { const { width, height } = cvs const ctx = cvs.getContext('2d') as CanvasRenderingContext2D StackBlur.canvasRGBA(cvs, 0, 0, width, height, value) return [cvs, ctx] } // 翻转 export function flip(cvs: HTMLCanvasElement, dire: 'hor' | 'ver' = 'hor') { const { width, height } = cvs const ctx = cvs.getContext('2d') as CanvasRenderingContext2D const { data: oPixels } = ctx.getImageData(0, 0, width, height) const imageData = ctx.createImageData(width, height) const dstPixels = imageData.data let y, x, off, dstOff for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { off = (y * width + x) * 4 dstOff = dire === 'hor' ? (y * width + (width - x - 1)) * 4 : ((height - y - 1) * width + x) * 4 dstPixels[dstOff] = oPixels[off] dstPixels[dstOff + 1] = oPixels[off + 1] dstPixels[dstOff + 2] = oPixels[off + 2] dstPixels[dstOff + 3] = oPixels[off + 3] } } ctx.putImageData(imageData, 0, 0) return [cvs, ctx] } // 黑白 export function gray(cvs: HTMLCanvasElement) { const { width, height } = cvs const ctx = cvs.getContext('2d') as CanvasRenderingContext2D const { data: oPixels } = ctx.getImageData(0, 0, width, height) const imageData = ctx.createImageData(width, height) const dstPixels = imageData.data let i, r, g, b, v for (i = 0; i < oPixels.length; i += 4) { r = oPixels[i] g = oPixels[i + 1] b = oPixels[i + 2] v = 0.3 * r + 0.59 * g + 0.11 * b dstPixels[i] = dstPixels[i + 1] = dstPixels[i + 2] = v dstPixels[i + 3] = oPixels[i + 3] } ctx.putImageData(imageData, 0, 0) return [cvs, ctx] } // 马赛克 export function mosaic(cvs: HTMLCanvasElement, block: number = 10) { const { width, height } = cvs const ctx = cvs.getContext('2d') as CanvasRenderingContext2D const { data: oPixels } = ctx.getImageData(0, 0, width, height) const imageData = ctx.createImageData(width, height) const dstPixels = imageData.data let cols = Math.ceil(width / block), rows = Math.ceil(height / block), row, col, x_start, x_end, y_start, y_end, x, y, yIndex, index, size, r, g, b, a for (row = 0; row < rows; row++) { y_start = row * block y_end = y_start + block if (y_end > height) y_end = height for (col = 0; col < cols; col++) { x_start = col * block x_end = x_start + block if (x_end > width) x_end = width r = g = b = a = 0 size = (x_end - x_start) * (y_end - y_start) for (y = y_start; y < y_end; y += 1) { yIndex = y * width for (x = x_start; x < x_end; x += 1) { index = (yIndex + x) << 2 r += oPixels[index] g += oPixels[index + 1] b += oPixels[index + 2] a += oPixels[index + 3] } } r = (r / size) + 0.5 | 0 g = (g / size) + 0.5 | 0 b = (b / size) + 0.5 | 0 a = (a / size) + 0.5 | 0 for (y = y_start; y < y_end; y++) { yIndex = y * width for (x = x_start; x < x_end; x++) { index = (yIndex + x) << 2 dstPixels[index] = r dstPixels[index + 1] = g dstPixels[index + 2] = b dstPixels[index + 3] = a } } } } ctx.putImageData(imageData, 0, 0) return [cvs, ctx] } // range: 1 - 5 // levels: 1 - 256 export function oil(cvs: HTMLCanvasElement, range: number = 2, levels: number = 32) { const { width, height } = cvs const ctx = cvs.getContext('2d') as CanvasRenderingContext2D const { data: oPixels } = ctx.getImageData(0, 0, width, height) const imageData = ctx.createImageData(width, height) const dstPixels = imageData.data const rh: number[] = [], gh: number[] = [], bh: number[] = [], rt: number[] = [], gt: number[] = [], bt: number[] = [] let index = 0, rowIndex, colIndex, offset, srcIndex, x, y, z, row, col, sr, sg, sb, ri, gi, bi, r, g, b for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { for (z = 0; z < levels; z++) { rh[z] = gh[z] = bh[z] = rt[z] = gt[z] = bt[z] = 0 } for (row = -range; row <= range; row++) { rowIndex = y + row if (rowIndex < 0 || rowIndex >= height) continue offset = rowIndex * width for (col = -range; col <= range; col++) { colIndex = x + col if (colIndex < 0 || colIndex >= width) continue srcIndex = (offset + colIndex) << 2 sr = oPixels[srcIndex] sg = oPixels[srcIndex + 1] sb = oPixels[srcIndex + 2] ri = (sr * levels) >> 8 gi = (sg * levels) >> 8 bi = (sb * levels) >> 8 rt[ri] += sr gt[gi] += sg bt[bi] += sb rh[ri] += 1 gh[gi] += 1 bh[bi] += 1 } } r = g = b = 0 for (z = 1; z < levels; z++) { if (rh[z] > rh[r]) r = z if (gh[z] > gh[g]) g = z if (bh[z] > bh[b]) b = z } dstPixels[index] = rt[r] / rh[r] | 0 dstPixels[index + 1] = gt[g] / gh[g] | 0 dstPixels[index + 2] = bt[b] / bh[b] | 0 dstPixels[index + 3] = oPixels[index + 3] index += 4 } } ctx.putImageData(imageData, 0, 0) return [cvs, ctx] }