| | |
| | | <uv-button type="primary" :plain="true" text="颜色" @click="changeColor()"></uv-button> |
| | | <uv-button type="primary" :plain="true" text="单帧移动" @click="enterMoveMode()"></uv-button> |
| | | <uv-button type="primary" :plain="true" text="多帧移动" @click="enterMultiMoveMode()"></uv-button> |
| | | <uv-button type="primary" :plain="true" text="图片上传" @click="chooseImage()"></uv-button> |
| | | <uv-button type="primary" :plain="true" text="文字" @click="addText()"></uv-button> |
| | | <uv-button type="primary" :plain="true" text="清除" @click="clear()"></uv-button> |
| | | <uv-button type="primary" :plain="true" text="保存" @click="clickSaveData"></uv-button> |
| | |
| | | }); |
| | | }, |
| | | |
| | | // 选择图片(相册或拍照) |
| | | chooseImage() { |
| | | uni.chooseImage({ |
| | | count: 1, |
| | | sizeType: ['compressed'], |
| | | sourceType: ['album', 'camera'], |
| | | success: (res) => { |
| | | console.log('chooseImage', JSON.stringify(res)) |
| | | const tempFilePath = res.tempFilePaths[0] |
| | | uni.showLoading({ title: '转换中', mask: true }) |
| | | this.imageToDotMatrix(tempFilePath).then(pixelArray => { |
| | | this.pixelData = pixelArray |
| | | uni.hideLoading() |
| | | }).catch(err => { |
| | | uni.hideLoading() |
| | | console.error('图片转点阵失败:', err) |
| | | uni.showToast({ title: '图片转点阵失败', icon: 'none' }) |
| | | }) |
| | | } |
| | | }) |
| | | }, |
| | | // 将图片转成点数据,参考generateDotMatrix的采样逻辑 |
| | | imageToDotMatrix(imagePath) { |
| | | return new Promise((resolve, reject) => { |
| | | // 先获取图片信息,得到原始宽高用于按比例缩放 |
| | | uni.getImageInfo({ |
| | | src: imagePath, |
| | | success: (imgInfo) => { |
| | | console.log('getImageInfo', JSON.stringify(imgInfo)) |
| | | const imgW = imgInfo.width |
| | | const imgH = imgInfo.height |
| | | if (!imgW || !imgH) { |
| | | reject(new Error('图片尺寸异常')) |
| | | return |
| | | } |
| | | // 等比缩放,使图片完整包含在画布内并居中 |
| | | const scale = Math.min(this.canvasWidth / imgW, this.canvasHeight / imgH) |
| | | const drawW = imgW * scale |
| | | const drawH = imgH * scale |
| | | const drawX = (this.canvasWidth - drawW) / 2 |
| | | const drawY = (this.canvasHeight - drawH) / 2 |
| | | |
| | | ctx = uni.createCanvasContext('myCanvas', this) |
| | | ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight) |
| | | // 将缩放后的图片绘制到画布 |
| | | ctx.drawImage(imagePath, drawX, drawY, drawW, drawH) |
| | | ctx.draw(false, () => { |
| | | setTimeout(() => { |
| | | uni.canvasGetImageData({ |
| | | canvasId: 'myCanvas', |
| | | x: 0, |
| | | y: 0, |
| | | width: this.canvasWidth, |
| | | height: this.canvasHeight, |
| | | success: (res) => { |
| | | console.log('canvasGetImageData', JSON.stringify(res)) |
| | | const imageData = res.data |
| | | const colCount = this.width * (this.modeVal == 2 ? 10 : 1) |
| | | const pixelArray = new Array(this.height * colCount).fill('') |
| | | const cellWidth = this.canvasWidth / colCount |
| | | const cellHeight = this.canvasHeight / this.height |
| | | if (!imageData) { |
| | | reject(new Error('读取图片像素数据异常')) |
| | | return |
| | | } |
| | | // 按格子采样,判断每个格子是否为前景(暗)像素 |
| | | for (let y = 0; y < this.height; y++) { |
| | | for (let x = 0; x < colCount; x++) { |
| | | let darkPixels = 0 |
| | | let totalPixels = 0 |
| | | for (let py = 0; py < cellHeight; py++) { |
| | | for (let px = 0; px < cellWidth; px++) { |
| | | const pixelY = Math.floor(y * cellHeight + py) |
| | | const pixelX = Math.floor(x * cellWidth + px) |
| | | const idx = (pixelY * this.canvasWidth + pixelX) * 4 |
| | | const r = imageData[idx] |
| | | const g = imageData[idx + 1] |
| | | const b = imageData[idx + 2] |
| | | const a = imageData[idx + 3] |
| | | const brightness = 0.3 * r + 0.59 * g + 0.11 * b |
| | | if (brightness < 128 && a > 128) { |
| | | darkPixels++ |
| | | } |
| | | totalPixels++ |
| | | } |
| | | } |
| | | const isDark = darkPixels / totalPixels > 0.3 |
| | | const arrayIndex = y * colCount + x |
| | | pixelArray[arrayIndex] = isDark ? this.color : '' |
| | | } |
| | | } |
| | | resolve(pixelArray) |
| | | }, |
| | | fail: (err) => { |
| | | reject(err) |
| | | } |
| | | }) |
| | | }, 1000) |
| | | }) |
| | | }, |
| | | fail: (err) => { |
| | | reject(err) |
| | | } |
| | | }) |
| | | }) |
| | | }, |
| | | openPreview() { |
| | | if (this.fpsList.length === 0 || this.fpsList.every(f => f === null || f === undefined)) { |
| | | uni.showToast({ |