Skip to content

Commit

Permalink
release(mask-editor): v0.4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
surunzi committed Feb 25, 2024
1 parent 93e2534 commit a4d597e
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 25 deletions.
2 changes: 1 addition & 1 deletion index.json
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@
"dependencies": ["painter"],
"style": false,
"react": true,
"version": "0.3.0",
"version": "0.4.0",
"icon": false,
"test": true,
"install": false
Expand Down
78 changes: 59 additions & 19 deletions src/mask-editor/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import Component, { IComponentOptions } from '../share/Component'
import LunaPainter, { Layer, Zoom } from 'luna-painter'
import LunaPainter, { Layer, Zoom, Hand } from 'luna-painter'
import debounce from 'licia/debounce'
import Color from 'licia/Color'
import { loadImage } from '../share/util'

/** IOptions */
export interface IOptions extends IComponentOptions {
/** Image src. */
image: string
/** Mask src. */
mask?: string
}

/**
Expand Down Expand Up @@ -59,32 +62,64 @@ export default class MaskEditor extends Component<IOptions> {

this.bindEvent()

this.loadImage()
this.loadImage().then(() => this.loadMask())
}
/** Get a canvas with mask drawn. */
getCanvas() {
return this.canvas
}
private loadImage() {
private async loadImage() {
const { painter } = this
if (!this.options.image) {
return
}

const image = new Image()
image.onload = () => {
const { width, height } = image
painter.setOption({
width,
height,
})
const image = await loadImage(this.options.image)

const ctx = this.baseLayer.getContext()
ctx.drawImage(image, 0, 0, width, height)
painter.renderCanvas()
const zoom = painter.getTool('zoom') as Zoom
zoom.fitScreen()
const { width, height } = image
painter.setOption({
width,
height,
})

const ctx = this.baseLayer.getContext()
ctx.drawImage(image, 0, 0, width, height)
painter.renderCanvas()

this.renderMask()

this.renderMask()
const zoom = painter.getTool('zoom') as Zoom
zoom.fitScreen()
const hand = painter.getTool('hand') as Hand
hand.centerCanvas()
}
private async loadMask() {
const { painter } = this
if (!this.options.mask) {
return
}

const image = await loadImage(this.options.mask)

const width = painter.getOption('width')
const height = painter.getOption('height')
const ctx = this.drawingLayer.getContext()
ctx.drawImage(image, 0, 0, width, height)
const c = new Color(painter.getForegroundColor())
const rgb = Color.parse(c.toRgb()).val
const canvas = ctx.canvas
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
const { data } = imageData
for (let i = 0, len = data.length; i < len; i += 4) {
data[i + 3] = (data[i] + data[i + 1] + data[i + 2]) / 3
data[i] = rgb[0]
data[i + 1] = rgb[1]
data[i + 2] = rgb[2]
}
image.src = this.options.image
ctx.putImageData(imageData, 0, 0)
painter.renderCanvas()

this.renderMask()
}
private renderMask() {
const { canvas, ctx, blackCanvas, blackCtx, painter } = this
Expand Down Expand Up @@ -142,8 +177,13 @@ export default class MaskEditor extends Component<IOptions> {
})

this.on('optionChange', (name) => {
if (name === 'image') {
this.loadImage()
switch (name) {
case 'image':
this.loadImage()
break
case 'mask':
this.loadMask()
break
}
})
}
Expand Down
2 changes: 1 addition & 1 deletion src/mask-editor/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mask-editor",
"version": "0.3.0",
"version": "0.4.0",
"description": "Image mask editing",
"luna": {
"dependencies": [
Expand Down
9 changes: 8 additions & 1 deletion src/mask-editor/react.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ const LunaMaskEditor: FC<IMaskEditorProps> = (props) => {
const maskEditor = useRef<MaskEditor>()

useEffect(() => {
const { image } = props
const { image, mask } = props
maskEditor.current = new MaskEditor(maskEditorRef.current!, {
image,
mask,
})
props.onCreate && props.onCreate(maskEditor.current)

Expand All @@ -32,6 +33,12 @@ const LunaMaskEditor: FC<IMaskEditorProps> = (props) => {
}
}, [props.image])

useNonInitialEffect(() => {
if (maskEditor.current) {
maskEditor.current.setOption('mask', props.mask)
}
}, [props.mask])

return <div ref={maskEditorRef} style={props.style}></div>
}

Expand Down
11 changes: 8 additions & 3 deletions src/mask-editor/story.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import $ from 'licia/$'
import h from 'licia/h'
import readme from './README.md'
import LunaMaskEditor from './react'
import { text } from '@storybook/addon-knobs'
import { text, files } from '@storybook/addon-knobs'
import { useRef } from 'react'
import isEmpty from 'licia/isEmpty'

const def = story(
'mask-editor',
Expand Down Expand Up @@ -33,9 +34,10 @@ const def = story(
})
wrapper.appendChild(maskContainer)

const { image } = createKnobs()
const { image, mask } = createKnobs()
const maskEditor = new MaskEditor(container, {
image,
mask,
})

onCreate(maskEditor, maskContainer)
Expand All @@ -51,13 +53,14 @@ const def = story(
source: __STORY__,
ReactComponent({ theme }) {
const maskContainer = useRef(null)
const { image } = createKnobs()
const { image, mask } = createKnobs()

return (
<>
<LunaMaskEditor
theme={theme}
image={image}
mask={mask}
onCreate={(maskEditor) => {
if (maskContainer.current) {
onCreate(maskEditor, maskContainer.current)
Expand Down Expand Up @@ -86,9 +89,11 @@ const def = story(

function createKnobs() {
const image = text('Image', 'https://res.liriliri.io/luna/pic1.jpg')
const masks = files('Mask')

return {
image,
mask: !isEmpty(masks) ? masks[0] : '',
}
}

Expand Down
13 changes: 13 additions & 0 deletions src/share/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import isNum from 'licia/isNum'
import contain from 'licia/contain'
import toNum from 'licia/toNum'
import detectOs from 'licia/detectOs'
import loadImg from 'licia/loadImg'
import isHidden from 'licia/isHidden'

export function exportCjs(module: any, clazz: any) {
Expand Down Expand Up @@ -171,3 +172,15 @@ export function resetCanvasSize(canvas: HTMLCanvasElement) {
canvas.width = Math.round(canvas.offsetWidth * window.devicePixelRatio)
canvas.height = Math.round(canvas.offsetHeight * window.devicePixelRatio)
}

export function loadImage(url: string): Promise<HTMLImageElement> {
return new Promise((resolve, reject) => {
loadImg(url, function (err, img) {
if (err) {
return reject(err)
}

resolve(img)
})
})
}

0 comments on commit a4d597e

Please sign in to comment.