Skip to content

Commit 0a4ef95

Browse files
committed
feat: canvas support image.
1 parent 148693c commit 0a4ef95

File tree

7 files changed

+116
-17
lines changed

7 files changed

+116
-17
lines changed

README-ja.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,24 @@ QRコードの背景色。
136136

137137
QRコードの前景色。
138138

139+
### `image-settings`
140+
141+
- タイプ: `ImageSettings`
142+
- デフォルト: `{}`
143+
144+
```ts
145+
export type ImageSettings = {
146+
src: string, // The URL of image.
147+
x?: number, // The horizontal offset. When not specified, will center the image.
148+
y?: number, // The vertical offset. When not specified, will center the image.
149+
height: number, // The height of image
150+
width: number, // The height of image
151+
excavate?: boolean, // Whether or not to "excavate" the modules around the image.
152+
}
153+
```
154+
155+
The settings to support qrcode image logo.
156+
139157
### `class`
140158
141159
- タイプ:`string`

README-zh_cn.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,27 @@ createApp({
135135

136136
二维码前景颜色。
137137

138+
### `image-settings`
139+
140+
- 类型: `ImageSettings`
141+
- 默认值: `{}`
142+
143+
```ts
144+
export type ImageSettings = {
145+
src: string, // 图片的地址。
146+
x?: number, // 水平横向偏移。没有设定值时,图片剧中
147+
y?: number, // 垂直竖向偏移。没有设定值时,图片剧中
148+
height: number, // 图片的高度
149+
width: number, // 图片的宽度
150+
// 是否“挖掘”图像周围的模块。
151+
// 这意味着嵌入图像重叠的任何模块都将使用背景颜色。
152+
// 使用此选项可确保图像周围的边缘清晰。嵌入透明图像时也很有用。
153+
excavate?: boolean,
154+
}
155+
```
156+
157+
二维码图片 logo 配置。
158+
138159
### `class`
139160
140161
- 类型:`string`

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,24 @@ The background color of qrcode.
136136

137137
The foreground color of qrcode.
138138

139+
### `image-settings`
140+
141+
- Type: `ImageSettings`
142+
- Default: `{}`
143+
144+
```ts
145+
export type ImageSettings = {
146+
src: string, // The URL of image.
147+
x?: number, // The horizontal offset. When not specified, will center the image.
148+
y?: number, // The vertical offset. When not specified, will center the image.
149+
height: number, // The height of image
150+
width: number, // The height of image
151+
excavate?: boolean, // Whether or not to "excavate" the modules around the image.
152+
}
153+
```
154+
155+
The settings to support qrcode image logo.
156+
139157
### `class`
140158
141159
- Type: `string`

example/webpack.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ <h1>qrcode.vue:</h1>
230230
</div>
231231
</div>
232232
</div>
233-
<form>
233+
<form v-cloak>
234234
<div class="row mb-3">
235235
<label class="col-sm-2 col-form-label">Value:</label>
236236
<div class="col-sm-10">

rollup.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ function createEntry(options) {
2424
name: 'QrcodeVue',
2525
file: options.file,
2626
format: options.format,
27-
exports: 'default',
27+
exports: 'named',
2828
globals: {
2929
vue: 'Vue'
3030
},

src/index.ts

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { defineComponent, h, onMounted, onUpdated, PropType, ref } from 'vue'
1+
import { defineComponent, Fragment, h, onMounted, onUpdated, PropType, ref } from 'vue'
22
import QR from './qrcodegen'
33

44
type Modules = ReturnType<QR.QrCode['getModules']>
@@ -98,7 +98,7 @@ function getImageSettings(
9898
w: number
9999
excavation: Excavation | null
100100
} {
101-
const { width, height, x: imageX, y: imageY} = imageSettings
101+
const { width, height, x: imageX, y: imageY } = imageSettings
102102
const numCells = cells.length + margin * 2
103103
const defaultSize = Math.floor(size * 0.1)
104104
const scale = numCells / size
@@ -178,7 +178,7 @@ const QRCodeVueProps = {
178178
},
179179
}
180180

181-
const QRCodeSvg = defineComponent({
181+
export const QRCodeSvg = defineComponent({
182182
name: 'QRCodeSvg',
183183
props: QRCodeProps,
184184
setup(props) {
@@ -195,8 +195,8 @@ const QRCodeSvg = defineComponent({
195195
if(props.imageSettings.src) {
196196
const imageSettings = getImageSettings(cells, props.size, margin, props.imageSettings)
197197
imageProps = {
198-
x: imageSettings.x,
199-
y: imageSettings.y,
198+
x: imageSettings.x + margin,
199+
y: imageSettings.y + margin,
200200
width: imageSettings.w,
201201
height: imageSettings.h,
202202
}
@@ -245,11 +245,12 @@ const QRCodeSvg = defineComponent({
245245
},
246246
})
247247

248-
const QRCodeCanvas = defineComponent({
248+
export const QRCodeCanvas = defineComponent({
249249
name: 'QRCodeCanvas',
250250
props: QRCodeProps,
251-
setup(props) {
251+
setup(props, ctx) {
252252
const canvasEl = ref<HTMLCanvasElement | null>(null)
253+
const imageRef = ref<HTMLImageElement | null>(null)
253254

254255
const generate = () => {
255256
const { value, level, size, margin, background, foreground } = props
@@ -266,9 +267,27 @@ const QRCodeCanvas = defineComponent({
266267
return
267268
}
268269

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

273+
const image = imageRef.value
274+
let imageProps = { x: 0, y: 0, width: 0, height: 0 }
275+
const showImage = props.imageSettings.src && image != null && image.naturalWidth !== 0 && image.naturalHeight !== 0
276+
277+
if(showImage) {
278+
const imageSettings = getImageSettings(cells, props.size, margin, props.imageSettings)
279+
imageProps = {
280+
x: imageSettings.x + margin,
281+
y: imageSettings.y + margin,
282+
width: imageSettings.w,
283+
height: imageSettings.h,
284+
}
285+
286+
if (imageSettings.excavation) {
287+
cells = excavateModules(cells, imageSettings.excavation)
288+
}
289+
}
290+
272291
const devicePixelRatio = window.devicePixelRatio || 1
273292

274293
const scale = (size / numCells) * devicePixelRatio
@@ -291,17 +310,41 @@ const QRCodeCanvas = defineComponent({
291310
})
292311
})
293312
}
313+
314+
if (showImage) {
315+
ctx.drawImage(
316+
image,
317+
imageProps.x,
318+
imageProps.y,
319+
imageProps.width,
320+
imageProps.height
321+
);
322+
}
294323
}
295324

296325
onMounted(generate)
297326
onUpdated(generate)
298327

328+
const { style } = ctx.attrs
329+
299330
return () => h(
300-
'canvas',
301-
{
302-
ref: canvasEl,
303-
style: { width: `${props.size}px`, height: `${props.size}px`},
304-
},
331+
Fragment,
332+
[
333+
h(
334+
'canvas',
335+
{
336+
...ctx.attrs,
337+
ref: canvasEl,
338+
style: { ...(style as Object), width: `${props.size}px`, height: `${props.size}px`},
339+
},
340+
),
341+
props.imageSettings.src && h('img', {
342+
ref: imageRef,
343+
src: props.imageSettings.src,
344+
style: {display: 'none'},
345+
onLoad: generate,
346+
})
347+
],
305348
)
306349
},
307350
})

src/qrcodegen.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -543,8 +543,7 @@ namespace qrcodegen {
543543
return [];
544544
else {
545545
const numAlign: int = Math.floor(this.version / 7) + 2;
546-
const step: int = (this.version == 32) ? 26 :
547-
Math.ceil((this.version * 4 + 4) / (numAlign * 2 - 2)) * 2;
546+
const step: int = Math.floor((this.version * 8 + numAlign * 3 + 5) / (numAlign * 4 - 4)) * 2;
548547
let result: Array<int> = [6];
549548
for (let pos = this.size - 7; result.length < numAlign; pos -= step)
550549
result.splice(1, 0, pos);

0 commit comments

Comments
 (0)