fix: 网络摄像头

This commit is contained in:
wangzhongjie 2025-08-21 15:02:16 +08:00
parent ee4d54e8d7
commit e6a75028c5
5 changed files with 120 additions and 25 deletions

View File

@ -145,4 +145,5 @@ export async function initCarParameter(params: object) {
method: http.RequestMethod.POST, method: http.RequestMethod.POST,
xml: false, xml: false,
}) })
} }

View File

@ -0,0 +1,94 @@
import http from '@ohos.net.http';
import buffer from '@ohos.buffer';
import image from '@ohos.multimedia.image';
const TAG = 'CameraService';
export async function ObtainNetworkCameraImages(): Promise<string | null> {
const url = "http://192.168.1.125/snapshot.cgi?stream=1&username=admin&password=123456";
let httpRequest = http.createHttp();
try {
console.info(TAG, 'Starting image request...');
const response = await httpRequest.request(url, {
method: http.RequestMethod.GET,
connectTimeout: 10000,
readTimeout: 10000,
expectDataType: http.HttpDataType.ARRAY_BUFFER,
});
if (response.responseCode === 200) {
let arrayBuffer = response.result as ArrayBuffer;
// 裁剪左半部分
const croppedBase64 = await cropLeftHalf(arrayBuffer);
return croppedBase64;
} else {
console.error(TAG, `HTTP Error: ${response.responseCode}`);
return null;
}
} catch (error) {
console.error(TAG, 'An error occurred while fetching the image.', JSON.stringify(error));
return null;
} finally {
httpRequest.destroy();
}
}
async function cropLeftHalf(arrayBuffer: ArrayBuffer): Promise<string> {
let imageSource: image.ImageSource | null = null;
let pixelMap: image.PixelMap | null = null;
try {
// 1. 创建ImageSource
imageSource = image.createImageSource(arrayBuffer);
// 2. 获取图片信息
const imageInfo = await imageSource.getImageInfo();
console.info(TAG, `Original image size: ${imageInfo.size.width}x${imageInfo.size.height}`);
// 3. 计算并定义左半部分的裁剪区域
const leftHalfWidth = Math.floor(imageInfo.size.width / 2);
const cropRegion: image.Region = {
size: {
width: leftHalfWidth,
height: imageInfo.size.height
},
x: 0,
y: 0
};
// 创建解码选项,并将裁剪区域放入其中
const decodingOptions: image.DecodingOptions = {
desiredRegion: cropRegion
};
// 4. 创建像素映射并进行裁剪
pixelMap = await imageSource.createPixelMap(decodingOptions);
// 5. 将裁剪后的PixelMap转换为ArrayBuffer
const imagePacker = image.createImagePacker();
const packedData = await imagePacker.packing(pixelMap, {
format: "image/jpeg",
quality: 90
});
// 6. 转换为Base64
const buf = buffer.from(packedData);
const base64 = buf.toString('base64');
const result = `data:image/jpeg;base64,${base64}`;
console.info(TAG, `Left half cropped successfully. Size: ${leftHalfWidth}x${imageInfo.size.height}`);
return result;
} catch (error) {
console.error(TAG, 'Image cropping failed:', JSON.stringify(error));
return "";
} finally {
// 7. 在 finally 块中安全地释放资源
imageSource?.release();
pixelMap?.release();
}
}

View File

@ -19,6 +19,7 @@ import Prompt from '@system.prompt';
import { DifferentialAndSignal } from '../utils/business/DifferentialAndSignalWorker'; import { DifferentialAndSignal } from '../utils/business/DifferentialAndSignalWorker';
import { dConsole } from '../utils/LogWorker'; import { dConsole } from '../utils/LogWorker';
import CarLoadingComponent from './Index/Loading'; import CarLoadingComponent from './Index/Loading';
import { ObtainNetworkCameraImages } from '../api/networkCamera';
@Entry @Entry
@Component @Component
@ -40,6 +41,7 @@ struct Index {
@State isPlay: boolean = false; @State isPlay: boolean = false;
@State initWork: boolean = false @State initWork: boolean = false
@State status: string = "开始" @State status: string = "开始"
@State base64Img: string = ""
// 请求网络表等待弹窗 // 请求网络表等待弹窗
customDialogController: CustomDialogController = new CustomDialogController({ customDialogController: CustomDialogController = new CustomDialogController({
builder: CarLoadingComponent(), builder: CarLoadingComponent(),
@ -62,6 +64,7 @@ struct Index {
async aboutToAppear() { async aboutToAppear() {
dConsole.log("权限首页 aboutToAppear") dConsole.log("权限首页 aboutToAppear")
this.base64Img = await ObtainNetworkCameraImages() || ""
this.ratio = AppStorage.get<BaseInfoType>('baseInfo')?.ratio || 1.4 this.ratio = AppStorage.get<BaseInfoType>('baseInfo')?.ratio || 1.4
this.angle = 0 this.angle = 0
AppStorage.set('lsh', '1111111111111') AppStorage.set('lsh', '1111111111111')
@ -217,7 +220,7 @@ struct Index {
HeaderComponent({ HeaderComponent({
shortLogo: false shortLogo: false
}) })
CardComponent({ CardComponent({
isSingle: this.singlePlay, isSingle: this.singlePlay,
singleClick: () => { singleClick: () => {

View File

@ -6,11 +6,9 @@ import {
DefaultJudgeConfigObj, DefaultJudgeConfigObj,
ExtendType, ExtendType,
Gps, Gps,
JudgeSound,
LANE, LANE,
MarkRule, MarkRule,
PLCType, PLCType,
ProcessDataEnumType,
ProjectInfo, ProjectInfo,
ProjectInfos, ProjectInfos,
ProjectRoads, ProjectRoads,
@ -21,7 +19,6 @@ import { ArrayToByteArray, NumberToByteArray } from '../../utils/Common';
import dayTs from '../../utils/Date'; import dayTs from '../../utils/Date';
import { dConsole } from '../../utils/LogWorker'; import { dConsole } from '../../utils/LogWorker';
import VoiceAnnounce from '../judgeSDK/utils/voiceAnnouncements'; import VoiceAnnounce from '../judgeSDK/utils/voiceAnnouncements';
import { examJudgeSoundEnd } from './JudgeSDKUtils';
// 中心信号转换 // 中心信号转换
@ -863,23 +860,23 @@ export const CurrentProjectConversion = (code: number, projectsObj: object): str
* @param sound - 评判音频对象 * @param sound - 评判音频对象
* @param avPlayer - 语音播放器实例 * @param avPlayer - 语音播放器实例
*/ */
export function PlayJudgeVoice(sound: JudgeSound, avPlayer: VoiceAnnounce) { // export function PlayJudgeVoice(sound: JudgeSound, avPlayer: VoiceAnnounce) {
if (sound.type == 1) { // if (sound.type == 1) {
avPlayer?.playAudio([`voice/${sound.code[0]}.mp3`], false, () => { // avPlayer?.playAudio([`voice/${sound.code[0]}.mp3`], false, () => {
examJudgeSoundEnd({ // examJudgeSoundEnd({
xmdm: sound.xmdm, code: sound.code[0], type: sound.type // xmdm: sound.xmdm, code: sound.code[0], type: sound.type
}); // });
dConsole.writeProcessData(ProcessDataEnumType.JudgeExamData, JSON.stringify({ // dConsole.writeProcessData(ProcessDataEnumType.JudgeExamData, JSON.stringify({
method: 'examJudgeSoundEnd', // method: 'examJudgeSoundEnd',
itemno: sound.xmdm, // itemno: sound.xmdm,
code: sound.code[0], // code: sound.code[0],
type: sound.type, // type: sound.type,
})); // }));
}); // });
} else { // } else {
avPlayer?.playAudio([`voice/${sound.code[0]}.mp3`]); // avPlayer?.playAudio([`voice/${sound.code[0]}.mp3`]);
} // }
} // }
/** /**
* 检查差分 * 检查差分

View File

@ -1,6 +1,6 @@
// 处理worker线程的消息tcp拿差分改正数,udp给后置机 // 处理worker线程的消息tcp拿差分改正数,udp给后置机
import worker, { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope } from '@ohos.worker'; import worker, { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope } from '@ohos.worker';
import { WorkerTag } from '../config'; import { SerialPortTag, WorkerTag } from '../config';
import { import {
CenterCallBackMsgType, CenterCallBackMsgType,
EnvironmentConfigurationType, EnvironmentConfigurationType,
@ -68,7 +68,7 @@ function getDataFn(config: EnvironmentConfigurationType) {
if (data !== "" && config.carType !== "2") { if (data !== "" && config.carType !== "2") {
// TODO // TODO
// 需要观察 // 需要观察
// console.log(WorkerTag, "后置机消息", data) console.log(WorkerTag, "后置机消息", data)
const res = await SerialPortService.getData() const res = await SerialPortService.getData()
if (res.length > 0) { if (res.length > 0) {
const dataArray = data.split(","); const dataArray = data.split(",");
@ -76,7 +76,7 @@ function getDataFn(config: EnvironmentConfigurationType) {
dataArray[28] = res[9].toString(); dataArray[28] = res[9].toString();
data = dataArray.join(","); data = dataArray.join(",");
} }
// console.log(SerialPortTag, "处理完的档位信号", data) console.log(SerialPortTag, "处理完的档位信号", data)
workerPort.postMessage( workerPort.postMessage(
JSON.stringify({ JSON.stringify({
type: WorkerBackMessageType.ObtainUdpData, type: WorkerBackMessageType.ObtainUdpData,