Skip to content

Commit

Permalink
feat: canvas support image.
Browse files Browse the repository at this point in the history
  • Loading branch information
scopewu committed Sep 25, 2024
1 parent 148693c commit 0a4ef95
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 17 deletions.
18 changes: 18 additions & 0 deletions README-ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,24 @@ QRコードの背景色。

QRコードの前景色。

### `image-settings`

- タイプ: `ImageSettings`
- デフォルト: `{}`

```ts
export type ImageSettings = {
src: string, // The URL of image.
x?: number, // The horizontal offset. When not specified, will center the image.
y?: number, // The vertical offset. When not specified, will center the image.
height: number, // The height of image
width: number, // The height of image
excavate?: boolean, // Whether or not to "excavate" the modules around the image.
}
```
The settings to support qrcode image logo.
### `class`
- タイプ:`string`
Expand Down
21 changes: 21 additions & 0 deletions README-zh_cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,27 @@ createApp({

二维码前景颜色。

### `image-settings`

- 类型: `ImageSettings`
- 默认值: `{}`

```ts
export type ImageSettings = {
src: string, // 图片的地址。
x?: number, // 水平横向偏移。没有设定值时,图片剧中
y?: number, // 垂直竖向偏移。没有设定值时,图片剧中
height: number, // 图片的高度
width: number, // 图片的宽度
// 是否“挖掘”图像周围的模块。
// 这意味着嵌入图像重叠的任何模块都将使用背景颜色。
// 使用此选项可确保图像周围的边缘清晰。嵌入透明图像时也很有用。
excavate?: boolean,
}
```
二维码图片 logo 配置。
### `class`
- 类型:`string`
Expand Down
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,24 @@ The background color of qrcode.

The foreground color of qrcode.

### `image-settings`

- Type: `ImageSettings`
- Default: `{}`

```ts
export type ImageSettings = {
src: string, // The URL of image.
x?: number, // The horizontal offset. When not specified, will center the image.
y?: number, // The vertical offset. When not specified, will center the image.
height: number, // The height of image
width: number, // The height of image
excavate?: boolean, // Whether or not to "excavate" the modules around the image.
}
```
The settings to support qrcode image logo.
### `class`
- Type: `string`
Expand Down
2 changes: 1 addition & 1 deletion example/webpack.html
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ <h1>qrcode.vue:</h1>
</div>
</div>
</div>
<form>
<form v-cloak>
<div class="row mb-3">
<label class="col-sm-2 col-form-label">Value:</label>
<div class="col-sm-10">
Expand Down
2 changes: 1 addition & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function createEntry(options) {
name: 'QrcodeVue',
file: options.file,
format: options.format,
exports: 'default',
exports: 'named',
globals: {
vue: 'Vue'
},
Expand Down
69 changes: 56 additions & 13 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineComponent, h, onMounted, onUpdated, PropType, ref } from 'vue'
import { defineComponent, Fragment, h, onMounted, onUpdated, PropType, ref } from 'vue'
import QR from './qrcodegen'

type Modules = ReturnType<QR.QrCode['getModules']>
Expand Down Expand Up @@ -98,7 +98,7 @@ function getImageSettings(
w: number
excavation: Excavation | null
} {
const { width, height, x: imageX, y: imageY} = imageSettings
const { width, height, x: imageX, y: imageY } = imageSettings
const numCells = cells.length + margin * 2
const defaultSize = Math.floor(size * 0.1)
const scale = numCells / size
Expand Down Expand Up @@ -178,7 +178,7 @@ const QRCodeVueProps = {
},
}

const QRCodeSvg = defineComponent({
export const QRCodeSvg = defineComponent({
name: 'QRCodeSvg',
props: QRCodeProps,
setup(props) {
Expand All @@ -195,8 +195,8 @@ const QRCodeSvg = defineComponent({
if(props.imageSettings.src) {
const imageSettings = getImageSettings(cells, props.size, margin, props.imageSettings)
imageProps = {
x: imageSettings.x,
y: imageSettings.y,
x: imageSettings.x + margin,
y: imageSettings.y + margin,
width: imageSettings.w,
height: imageSettings.h,
}
Expand Down Expand Up @@ -245,11 +245,12 @@ const QRCodeSvg = defineComponent({
},
})

const QRCodeCanvas = defineComponent({
export const QRCodeCanvas = defineComponent({
name: 'QRCodeCanvas',
props: QRCodeProps,
setup(props) {
setup(props, ctx) {
const canvasEl = ref<HTMLCanvasElement | null>(null)
const imageRef = ref<HTMLImageElement | null>(null)

const generate = () => {
const { value, level, size, margin, background, foreground } = props
Expand All @@ -266,9 +267,27 @@ const QRCodeCanvas = defineComponent({
return
}

const cells = QR.QrCode.encodeText(value, ErrorCorrectLevelMap[level]).getModules()
let cells = QR.QrCode.encodeText(value, ErrorCorrectLevelMap[level]).getModules()
const numCells = cells.length + margin * 2

const image = imageRef.value
let imageProps = { x: 0, y: 0, width: 0, height: 0 }
const showImage = props.imageSettings.src && image != null && image.naturalWidth !== 0 && image.naturalHeight !== 0

if(showImage) {
const imageSettings = getImageSettings(cells, props.size, margin, props.imageSettings)
imageProps = {
x: imageSettings.x + margin,
y: imageSettings.y + margin,
width: imageSettings.w,
height: imageSettings.h,
}

if (imageSettings.excavation) {
cells = excavateModules(cells, imageSettings.excavation)
}
}

const devicePixelRatio = window.devicePixelRatio || 1

const scale = (size / numCells) * devicePixelRatio
Expand All @@ -291,17 +310,41 @@ const QRCodeCanvas = defineComponent({
})
})
}

if (showImage) {
ctx.drawImage(
image,
imageProps.x,
imageProps.y,
imageProps.width,
imageProps.height
);
}
}

onMounted(generate)
onUpdated(generate)

const { style } = ctx.attrs

return () => h(
'canvas',
{
ref: canvasEl,
style: { width: `${props.size}px`, height: `${props.size}px`},
},
Fragment,
[
h(
'canvas',
{
...ctx.attrs,
ref: canvasEl,
style: { ...(style as Object), width: `${props.size}px`, height: `${props.size}px`},
},
),
props.imageSettings.src && h('img', {
ref: imageRef,
src: props.imageSettings.src,
style: {display: 'none'},
onLoad: generate,
})
],
)
},
})
Expand Down
3 changes: 1 addition & 2 deletions src/qrcodegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -543,8 +543,7 @@ namespace qrcodegen {
return [];
else {
const numAlign: int = Math.floor(this.version / 7) + 2;
const step: int = (this.version == 32) ? 26 :
Math.ceil((this.version * 4 + 4) / (numAlign * 2 - 2)) * 2;
const step: int = Math.floor((this.version * 8 + numAlign * 3 + 5) / (numAlign * 4 - 4)) * 2;
let result: Array<int> = [6];
for (let pos = this.size - 7; result.length < numAlign; pos -= step)
result.splice(1, 0, pos);
Expand Down

0 comments on commit 0a4ef95

Please sign in to comment.