This commit is contained in:
2025-09-14 00:21:54 +08:00
commit d40b3bbd62
766 changed files with 36275 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
/* @import '../../../common/lib/weui.css'; */
camera {
height: 250px;
}
.preview-tips {
margin: 10px 0;
}
.photo,
.video {
margin-top: 25px;
width: 100%;
}
.btn-area {
margin-top: 0;
}
.first-btn {
margin-top: 15px;
}
form {
margin-top: 15px;
}
.weui-cell__bd {
display: flex;
justify-content: flex-start;
align-items: center;
padding: 10px 0;
min-height: 30px;
}
.info-container {
margin: 12px;
text-align: center;
}

View File

@@ -0,0 +1,224 @@
const vs = `
attribute vec3 aPos;
attribute vec2 aVertexTextureCoord;
varying highp vec2 vTextureCoord;
void main(void){
gl_Position = vec4(aPos, 1);
vTextureCoord = aVertexTextureCoord;
}
`;
const fs = `
varying highp vec2 vTextureCoord;
uniform sampler2D uSampler;
void main(void) {
gl_FragColor = texture2D(uSampler, vTextureCoord);
}
`;
const vertex = [
-1, -1, 0.0,
1, -1, 0.0,
1, 1, 0.0,
-1, 1, 0.0,
];
const vertexIndice = [
0, 1, 2,
0, 2, 3,
];
const texCoords = [
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
];
function createShader(gl, src, type) {
const shader = gl.createShader(type);
gl.shaderSource(shader, src);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error(`Error compiling shader: ${gl.getShaderInfoLog(shader)}`);
}
return shader;
}
const buffers = {};
function createRenderer(canvas, width, height) {
const gl = canvas.getContext('webgl');
if (!gl) {
console.error('Unable to get webgl context.');
return;
}
const info = xhs.getSystemInfoSync();
gl.canvas.width = info.pixelRatio * width;
gl.canvas.height = info.pixelRatio * height;
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
const vertexShader = createShader(gl, vs, gl.VERTEX_SHADER);
const fragmentShader = createShader(gl, fs, gl.FRAGMENT_SHADER);
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error('Unable to initialize the shader program.');
return;
}
gl.useProgram(program);
const texture = gl.createTexture();
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.bindTexture(gl.TEXTURE_2D, null);
buffers.vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertex), gl.STATIC_DRAW);
buffers.vertexIndiceBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.vertexIndiceBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(vertexIndice), gl.STATIC_DRAW);
const aVertexPosition = gl.getAttribLocation(program, 'aPos');
gl.vertexAttribPointer(aVertexPosition, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(aVertexPosition);
buffers.trianglesTexCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.trianglesTexCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texCoords), gl.STATIC_DRAW);
const vertexTexCoordAttribute = gl.getAttribLocation(program, 'aVertexTextureCoord');
gl.enableVertexAttribArray(vertexTexCoordAttribute);
gl.vertexAttribPointer(vertexTexCoordAttribute, 2, gl.FLOAT, false, 0, 0);
const samplerUniform = gl.getUniformLocation(program, 'uSampler');
gl.uniform1i(samplerUniform, 0);
return (arrayBuffer, width, height) => {
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBuffer);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
};
}
Page({
onShareAppMessage() {
return {
title: 'camera',
path: 'page/component/pages/camera/camera',
};
},
data: {
src: '',
videoSrc: '',
position: 'back',
mode: 'scanCode',
result: {},
frameWidth: 0,
frameHeight: 0,
width: 288,
height: 358,
showCanvas: false,
},
onReady() {
this.ctx = xhs.createCameraContext();
// const selector = xhs.createSelectorQuery();
// selector.select('#webgl')
// .node(this.init)
// .exec()
},
init(res) {
if (this.listener) {
this.listener.stop();
}
const canvas = res.node;
const render = createRenderer(canvas, this.data.width, this.data.height);
// if (!render || typeof render !== 'function') return
this.listener = this.ctx.onCameraFrame(frame => {
render(new Uint8Array(frame.data), frame.width, frame.height);
const {
frameWidth,
frameHeight,
} = this.data;
if (frameWidth === frame.width && frameHeight == frame.height) return;
this.setData({
frameWidth: frame.width,
frameHeight: frame.height,
});
});
this.listener.start();
},
takePhoto() {
this.ctx.takePhoto({
quality: 'high',
success: res => {
this.setData({
src: res.tempImagePath,
});
},
});
},
startRecord() {
this.ctx.startRecord({
success: () => {
console.log('startRecord');
},
});
},
stopRecord() {
this.ctx.stopRecord({
success: res => {
this.setData({
src: res.tempThumbPath,
videoSrc: res.tempVideoPath,
});
},
});
},
togglePosition() {
this.setData({
position: this.data.position === 'front'
? 'back' : 'front',
});
},
error(e) {
console.log(e.detail);
},
handleShowCanvas() {
const that = this;
this.setData({
showCanvas: !this.data.showCanvas,
}, () => {
if (this.data.showCanvas) {
const selector = xhs.createSelectorQuery();
selector.select('#webgl')
.node(this.init)
.exec();
}
});
},
});

View File

@@ -0,0 +1,3 @@
{
"navigationBarTitleText": "camera"
}

View File

@@ -0,0 +1,42 @@
<view class="container">
<view class="page-body">
<view class="page-body-wrapper">
<view style="margin-bottom: 10px"> camera 组件 </view>
<camera
flash="off"
device-position="{{position}}"
binderror="error"
>
</camera>
<view xhs:if="{{showCanvas}}" class="info-container">
<view style="margin: 10px 0">使用实时数据帧在 canvas 组件的展示</view>
<view>
帧高度:{{ frameHeight }} 帧宽度:{{ frameWidth }}
</view>
</view>
<view class="btn-area first-btn">
<button bindtap="handleShowCanvas" type="primary">{{showCanvas ? "关闭实时帧数据模式": "开启实时帧数据模式"}}</button>
</view>
<view class="btn-area">
<button type="primary" bindtap="togglePosition">切换摄像头</button>
</view>
<view class="btn-area">
<button type="primary" bindtap="takePhoto">拍照</button>
</view>
<view class="btn-area">
<button type="primary" bindtap="startRecord">开始录像</button>
</view>
<view class="btn-area">
<button type="primary" bindtap="stopRecord">结束录像</button>
</view>
<view class="btn-area">
<navigator url="/page/component/pages/camera-scan-code/camera-scan-code" hover-class="none">
<button type="primary">扫描一维码</button>
</navigator>
</view>
<view class="preview-tips">点击录像或拍照即可在下方预览效果</view>
<image xhs:if="{{src}}" mode="widthFix" class="photo" src="{{src}}"></image>
<video xhs:if="{{videoSrc}}" class="video" src="{{videoSrc}}"></video>
</view>
</view>
</view>