uniapp藍牙打印圖片

前言
這是個藍牙打印圖片的功能,業務是打印界面固定的demo范圍,這里通過html2canvas插件生成的圖片base64,然后圖片base64繪制到canvas中去后,獲取canvas中的像素信息,然后對像素信息進行一個灰度值處理,灰度值處理后再進行黑白值的處理,然后再根據藍牙機需要通過圖片的寬高比例進行一個二維數組的生成等等,一番數據處理后,將數據轉換為buffer格式 ,因為藍牙一次只能發20字節所以采用遞歸方式發送。

采用貼紙打印的話,需要使用黑標指令發送固定數據給藍牙一次,打印機會蜂鳴,目的是打印內容完后,自動切換下一個紙準備,不會仍舊在當前紙打印。

這里用的是南方鴻志科技的58mm熱敏打印機

總結:打印的view視圖范圍中有文字有圖片,其中圖片是base64格式是正常運行的,如果是本地圖片會發現html2canvas在app端無法處理。

  • 搜索連接藍牙界面
  • 藍牙打印界面
  • 引用組件界面

搜索連接藍牙界面

<template><view class="content"><button type="default" @click="bluetoothInit">搜尋藍牙設備</button><button @click="goPrint">跳轉打印界面</button><uni-search-bar  :focus="true" v-model="searchValue"  @input="input"@cancel="cancel" @clear="clear"></uni-search-bar><view class="list"><view class="item" v-for="(item,index) in bluetoothList" :key="index"><text class="name">{{item.name}}----{{item.deviceId}}</text><view class="btns" @click="connect(item)">點擊連接</view></view></view></view>
</template><script>export default {data() {return {bluetoothList: [], //藍牙列表searchValue:""}},onshow() {},created() {},methods: {input(e){console.log(e);let bluetoothList=uni.getStorageSync('bluetoothList');this.bluetoothList=bluetoothList.filter(element=>{return element.name.includes(e)})console.log(this.bluetoothList);},cancel(){this.bluetoothList=uni.getStorageSync('bluetoothList');},clear(){this.bluetoothList=uni.getStorageSync('bluetoothList');},goPrint(){uni.navigateTo({url:'/pages/Print/Print'})},//點擊連接設備connect(device) {uni.showModal({title: device.name,content: '確定連接此設備?',success: (res => {if (res.confirm) {uni.setStorageSync("DeviceID", device.deviceId) //把已經連接的藍牙設備信息放入緩存this.DeviceID = device.deviceIdlet DeviceID = device.deviceId //這里是拿到的uuidthis.StopBluetoothDevicesDiscovery() //當找到匹配的藍牙后就關掉藍牙搜尋,因為藍牙搜尋很耗性能console.log("匹配到的藍牙this.DeviceID:", this.DeviceID)this.CreateBLEConnection(DeviceID) //創建藍牙連接,連接低功耗藍牙設備	uni.showLoading({title: '正在嘗試連接藍牙...'}); 	console.log('用戶點擊確定');} else if (res.cancel) {console.log('用戶點擊取消');}})});},//藍牙初始化bluetoothInit() {this.searchValue='';this.bluetoothList = [];uni.openBluetoothAdapter({success: (res) => {console.log('第一步初始化藍牙成功:' + res.errMsg);// 初始化完畢開始搜索this.StartBluetoothDeviceDiscovery()},fail: (res) => {console.log('初始化藍牙失敗: ' + JSON.stringify(res));if (res.errCode == 10001) {uni.showToast({title: '藍牙未打開',duration: 2000,})} else {uni.showToast({title: res.errMsg,duration: 2000,})}}});},/*** 第二步 在頁面顯示的時候判斷是都已經初始化完成藍牙適配器若成功,則開始查找設備*/StartBluetoothDeviceDiscovery() {uni.startBluetoothDevicesDiscovery({// services: ['0000FFE0'],success: res => {console.log('第二步 開始搜尋附近的藍牙外圍設備:startBluetoothDevicesDiscovery success', res)this.OnBluetoothDeviceFound();},fail: res => {uni.showToast({icon: "none",title: "查找設備失敗!",duration: 3000})}});},/*** 第三步  發現外圍設備*/OnBluetoothDeviceFound() {console.log("監聽尋找新設備");uni.showLoading({title: '搜尋設備中...'});uni.onBluetoothDeviceFound(res => {console.log("第三步 監聽尋找到新設備的事件:", JSON.stringify(res))console.log("第三步 監聽尋找到新設備列表:", res.devices)let bluetoothList = [...res.devices, ...this.bluetoothList];this.bluetoothList=bluetoothList;uni.setStorageSync('bluetoothList', bluetoothList);console.log(bluetoothList);// 		res.devices.forEach(device => { //這一步就是去篩選找到的藍牙中,有沒有你匹配的名稱// 			console.log("這一步就是去篩選找到的藍牙中,有沒有你匹配的名稱:", JSON.stringify(device))// 			if (device.name == 'Qsprinter') { //匹配藍牙名稱// 				uni.setStorageSync("DeviceID", device.deviceId) //把已經連接的藍牙設備信息放入緩存// 				this.DeviceID = device.deviceId// 				let DeviceID = device.deviceId //這里是拿到的uuid// 				this.StopBluetoothDevicesDiscovery() //當找到匹配的藍牙后就關掉藍牙搜尋,因為藍牙搜尋很耗性能// 				console.log("匹配到的藍牙this.DeviceID:", this.DeviceID)// 				this.CreateBLEConnection(DeviceID) //創建藍牙連接,連接低功耗藍牙設備// 			}// 		})setTimeout(() => {this.StopBluetoothDevicesDiscovery()}, 10000)});},/*** 第四步 停止搜索藍牙設備*/StopBluetoothDevicesDiscovery() {uni.stopBluetoothDevicesDiscovery({success: res => {console.log("第四步 找到匹配的藍牙后就關掉藍牙搜尋:", JSON.stringify(res))},fail: res => {console.log('第四步 停止搜索藍牙設備失敗,錯誤碼:' + res.errCode);},complete() {uni.hideLoading();}});},// 第五步 創建藍牙連接,連接低功耗藍牙設備CreateBLEConnection(DeviceID, index) {let doc = thisuni.createBLEConnection({ //創建藍牙連接,連接低功耗藍牙設備deviceId: DeviceID, //傳入剛剛獲取的uuidsuccess(res) {console.log("第五步 創建藍牙連接成功:", JSON.stringify(res))doc.GetBLEDeviceServices(DeviceID) //獲取藍牙設備所有服務(service)。},fail(res) {console.log(res)}})},//第六步 獲取藍牙設備所有服務(service)。GetBLEDeviceServices(DeviceID, index) {let doc = thissetTimeout(function() { //這里為什么要用setTimeout呢,等等下面會解釋uni.getBLEDeviceServices({ //獲取藍牙設備所有服務deviceId: DeviceID,success(res) { //為什么要用延時,因為不用延時就拿不到所有的服務,在上一步,連接低功耗藍牙//設備的時候,需要一個600-1000毫秒的時間后,再去獲取設備所有服務,不給延時就會一直返回錯誤碼10004console.log("第六步 獲取藍牙設備所有服務:", JSON.stringify(res))uni.setStorageSync("ServiceUUID", res.services[2].uuid) //把已經連接的藍牙設備信息放入緩存uni.setStorageSync("ServiceUUIDNew", res.services[2].uuid) //把已經連接的藍牙設備信息放入緩存let ServiceUUIDNew = res.services[2].uuidthis.ServiceUUID = res.services[2].uuidconsole.log("this.ServiceUUID:", this.ServiceUUID);doc.GetBLEDeviceCharacteristics(DeviceID) //獲取藍牙設備某個服務中所有特征值},fail(res) {console.log(JSON.stringify(res))}})}, 1000)},// 第七步 獲取藍牙特征值GetBLEDeviceCharacteristics(DeviceID) {console.log("第七步 獲取藍牙特征值DeviceID:", DeviceID, "serviceId:", uni.getStorageSync('ServiceUUIDNew'));setTimeout(() => {let that = this;uni.getBLEDeviceCharacteristics({ //獲取藍牙設備某個服務中所有特征值deviceId: DeviceID,serviceId: uni.getStorageSync('ServiceUUIDNew'), //這個serviceId可以在上一步獲取中拿到,也可以在//藍牙文檔中(硬件的藍牙文檔)拿到,我這里是通過文檔直接賦值上去的,一般有兩個,一個是收的uuid,一個是發的uuid,我們這邊是發success(res) {console.log("第七步 獲取藍牙設備某個服務中所有特征值成功:", JSON.stringify(res))uni.showToast({title: '設備藍牙已連接',duration: 2000});// uni.hideLoading();// #ifdef APP-IOSuni.setStorageSync("CharacteristicId", res.characteristics[0].uuid) //把某個服務中所有特征值信息放入緩存that.characteristicId = res.characteristics[0].uuidconsole.log(res);// #endif// #ifdef APP-ANDROIDuni.setStorageSync("CharacteristicId", res.characteristics[1].uuid) //把某個服務中所有特征值信息放入緩存that.characteristicId = res.characteristics[1].uuid// #endif// that.WriteBLECharacteristicValue()},fail(res) {console.log("獲取藍牙設備某個服務中所有特征值失敗:", JSON.stringify(res))}})}, 2000)},}}
</script><style>.container {display: flex;flex-direction: column;align-items: center;}.row {display: flex;}.cell {width: 10px;height: 10px;margin-top: 2rpx;color: #000;/* 這里可以根據灰度值設置背景色 */}.list {margin-top: 10rpx;}.list .item {width: 97%;height: 100rpx;margin-top: 10rpx;display: flex;justify-content: space-between;align-items: center;border-bottom: 1rpx solid #ccc;}.btns {white-space: nowrap;}
</style>

藍牙打印界面

<template><view><PrintCode ref='PrintCode' :imgUrl="imgUrl" codeType="code" :info="info"></PrintCode><button type="default" @click="btn">選中圖片打印</button><button type="default" @click="btn2">黑標打印</button></view>
</template><script>export default {data() {return {imgUrl:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkAQAAAABYmaj5AAAAtElEQVR4nJWTwYkDQRADa43/tRk4/7CcgSYC3cOfgwMfml/DCKmlFoA2FODB7/dtwlYCtR1wD64bXxGue8A9Ad7e5950PgFenHhPOGyNcdzvAgTgbHxtW2vbZtEZkJC68aVRsbLwJZiIyeILDSmCdcshmBA3Xz5Ak7jhwLSUZNTZFsm4H0IsMOXQtqaxzPtRVMYcqqTWue/AOde/P/9Mx5v6vta+9wC59r5/znvC8el7Rl9+AN59eFd5eY5PAAAAAElFTkSuQmCC",resultArray:[],info:{name:"xxxxxxxxxxxxxxxxxx",model:"1111111111112123123132312",amount:"12312312313212312123",start_use_date:'2024-2-3'}}},methods: {btn(){this.$refs.PrintCode.open()},btn2(){let value=[31, 27, 31, 128, 4, 5, 6, 68];uni.writeBLECharacteristicValue({deviceId: uni.getStorageSync('DeviceID'),// 這里的 serviceId 需要在 getBLEDeviceServices 接口中獲取serviceId: uni.getStorageSync('ServiceUUIDNew'),// 這里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中獲取characteristicId: uni.getStorageSync('CharacteristicId'),// 這里的value是ArrayBuffer類型value: value,success: function(res) {console.log(res);//寫入成功后繼續遞歸調用發送剩下的數據// that.sendMsg(newData)},fail: function(err) {console.log(err)},complete: function() {}})},},onShow() {uni.onBLEConnectionStateChange(function (res) {// 該方法回調中可以用于處理連接意外斷開等異常情況console.log(`device ${res.deviceId} state has changed, connected: ${res.connected}`)})}}
</script>

引用組件界面

<template><view><uni-popup ref="popup" type="center"><view class="BigBox" v-if="codeType=='bar'"><image :src="imgUrl" mode="" class="barImg"></image></view><view class="BigBox2" v-else id="pagePoster"><view class="lf"><view class="">名稱:{{setLength(info.name)}}</view><view class="">型號:{{setLength(info.model)}}</view><view class="">數量:{{setLength(info.amount)}}</view><view class="">投用時間:{{setLength(info.start_use_date)}}</view></view><view class="rg"><image :src="imgUrl" mode=""></image></view></view><view class="btnBox"><view class="print" v-if="codeType=='bar'" @click="printBtn">打印</view><view class="print" v-else @click="canvasImage.generateImage">打印</view><view class="close" @click="close">取消</view></view><canvas canvas-id="myCanvas" id="myCanvas" :style="{width:imgWidth,height:imgHeight}"></canvas></uni-popup></view>
</template><script>export default {name: "PrintCode",props: {imgUrl: {default: ""},codeType: {default: 'bar'},info: {type: Object}},data() {return {imgWidth: "",imgHeight: ""};},mounted() {uni.openBluetoothAdapter({success: (res) => {console.log('第一步初始化藍牙成功:' + res.errMsg);uni.showToast({title: '藍牙已初始化',duration: 1000});},fail: (res) => {console.log('初始化藍牙失敗: ' + JSON.stringify(res));if (res.errCode == 10001) {uni.showToast({title: '藍牙未打開',duration: 2000,})} else {uni.showToast({title: res.errMsg,duration: 2000,})}}});},methods: {//canvas無法顯示省略號,給文字添加省略號,setLength(e) {console.log(e);let text = e;if (e?.length > 8) {text = e.substring(0, 8) + '...';}return text},open() {this.$refs.popup.open('center')},close() {this.$refs.popup.close()},//二維碼打印receiveSendData(val) {const ctx = uni.createCanvasContext('myCanvas', this);// 獲取圖片信息成功后繪制到 Canvas 上ctx.drawImage(val, 0, 0, 350, 176);// 獲取繪制完成的圖片數據ctx.draw(false, () => {this.imgWidth = 350 + 'px';this.imgHeight = 176 + 'px';// 將 Canvas 中的圖片數據轉換為灰度圖像uni.canvasGetImageData({canvasId: 'myCanvas',x: 0,y: 0,width: 350,height: 176,success: (res) => {console.log(res);const imageData = res.data;console.log(imageData);this.chuli(imageData)},fail: (error) => {console.error('獲取圖片數據失敗', error);}});});},//條碼打印printBtn() {// const dcRichAlert = uni.requireNativePlugin('Yunjinginc-Print')//  dcRichAlert.printBitmap1(0,this.imgUrl,true)},//處理像素為打印機發送數據chuli(imageData) {let imgWidth = 350;let imgHeight = 176;// 將彩色圖片轉換為灰度圖片for (let i = 0; i < imageData.length; i += 4) {const r = imageData[i];const g = imageData[i + 1];const b = imageData[i + 2];// 根據灰度公式將 RGB 值轉換為灰度值const grayscale = 0.299 * r + 0.587 * g + 0.114 *b;// 將灰度值賦給 RGBimageData[i] = grayscale; // RedimageData[i + 1] = grayscale; // GreenimageData[i + 2] = grayscale; // Blue}console.log(imageData);let blackWhiteData = this.convertToBlackWhite(imageData); // 轉換成黑白像素點數據console.log(blackWhiteData);this.grayscaleArray = [];// 將一維數組轉換為二維數組for (let i = 0; i < imgWidth; i++) {// 每一行的起始索引let startIndex = i * imgWidth;// 每一行的灰度值數據let row = blackWhiteData.slice(startIndex,startIndex + imgWidth);// 將當前行添加到二維數組中this.grayscaleArray.push(row);}let originalArray = this.grayscaleArray;console.log(this.grayscaleArray);let resultArray = this.complementArr(this.grayscaleArray, imgWidth, imgHeight);//求二維數組進行24行處理時除數與余數const quotient = resultArray.length / 24; // 求次數let list = []// 對前24*n行進行處理for (let i = 0; i < quotient; i++) {const startIndex = i * 24;const endIndex = (i + 1) * 24;const rowsToProcess = originalArray.slice(startIndex, endIndex);console.log(rowsToProcess);console.log(startIndex, endIndex);list.push(this.processRows(rowsToProcess))}console.log(list);// 二維轉一維let list2 = list.flat()console.log(list2);this.resultArray = list2;// 創建一個 Uint8Array 視圖對象,將數組數據復制到該視圖中const typedArray = new Uint8Array(this.resultArray);// 獲取 typedArray 的 buffer 屬性,即得到對應的 ArrayBufferconst buffer = typedArray.buffer;this.sendMsg(buffer)},//發送數據給藍牙sendMsg(buffer) {var newData = buffer.slice(20)var writeBuffer = buffer.slice(0, 20)console.log(writeBuffer.length);if (writeBuffer.byteLength < 20) {console.log("Invalid data length. Data will not be sent.");//紙打印完了之后進行切刀,(標簽紙)uni.writeBLECharacteristicValue({deviceId: uni.getStorageSync('DeviceID'),// 這里的 serviceId 需要在 getBLEDeviceServices 接口中獲取serviceId: uni.getStorageSync('ServiceUUIDNew'),// 這里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中獲取characteristicId: uni.getStorageSync('CharacteristicId'),// 這里的value是ArrayBuffer類型value: [27, 35, 35, 67, 84, 71, 72, 48],success: function(res) {console.log(res);},})return; // 數據無效,不發送}let that = this;console.log(uni.getStorageSync('DeviceID'));uni.writeBLECharacteristicValue({deviceId: uni.getStorageSync('DeviceID'),// 這里的 serviceId 需要在 getBLEDeviceServices 接口中獲取serviceId: uni.getStorageSync('ServiceUUIDNew'),// 這里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中獲取characteristicId: uni.getStorageSync('CharacteristicId'),// 這里的value是ArrayBuffer類型value: writeBuffer,writeType: 'write',success: function(res) {//寫入成功后繼續遞歸調用發送剩下的數據that.sendMsg(newData)},fail: function(err) {console.log(err)},complete: function() {}})},//補充數組complementArr(originalArray, width, height) {let originalArrayData = originalArraylet replenish = 24 - height % 24for (let i = 0; i < replenish; i++) {let arr = []for (let j = 0; j < width; j++) {arr.push(0)}originalArrayData.push(arr)}return originalArrayData},//處理數據processRows(rows) {const columnValues = [];for (let col = 0; col < rows[0].length; col++) {const values = [];for (let row = 0; row < rows.length; row++) {values.push(rows[row][col]);}// 將每列的值拆分為三份const partitionSize = Math.ceil(values.length / 3);const partitions = [];for (let i = 0; i < values.length; i += partitionSize) {partitions.push(values.slice(i, i + partitionSize));}// 將每份的值拼接成一個字符串,并轉換為10進制數for (let i = 0; i < partitions.length; i++) {const binaryString = partitions[i].join('');const decimalValue = parseInt(binaryString, 2);columnValues.push(decimalValue);}}//計算 n1,n2const n2 = Math.floor((this.grayscaleArray[0]).length / 256) < 1 ? 0 : Math.floor((this.grayscaleArray[0]).length / 256); // 求除數const n1 = this.grayscaleArray[0].length % 256; // 求余數console.log(n2, n1);columnValues.unshift(27, 42, 33, n1, n2)columnValues.push(10)console.log(columnValues);return columnValues},// 根據閾值將灰度值轉換為黑白像素值convertToBlackWhite(grayscaleData) {let blackWhiteData = [];for (let i = 0; i < grayscaleData.length; i += 4) {let pixel = grayscaleData[i];let bwPixel = pixel > 128 ? 0 : 1;blackWhiteData.push(bwPixel);}return blackWhiteData;},}}
</script>
<script lang="renderjs" module="canvasImage">import html2canvas from 'html2canvas'export default {data() {return {}},methods: {// 生成圖片需要調用的方法generateImage(e, ownerVm) {setTimeout(() => {const dom = document.getElementById('pagePoster') // 需要生成圖片內容的 dom 節點console.log(dom.clientWidth, dom.clientHeight);html2canvas(dom, {width: dom.clientWidth, //dom 原始寬度height: dom.clientHeight,scrollY: 0, // html2canvas默認繪制視圖內的頁面,需要把scrollY,scrollX設置為0scrollX: 0,useCORS: true //支持跨域// , // 設置生成圖片的像素比例,默認是1,如果生成的圖片模糊的話可以開啟該配置項}).then((canvas) => {// 創建新的 Canvasvar newCanvas = document.createElement("canvas");var newContext = newCanvas.getContext("2d");// 設置新 Canvas 的寬度和高度var width = 350; // 設置新 Canvas 的寬度var height = 176; // 設置新 Canvas 的高度newCanvas.width = width;newCanvas.height = height;console.log(newCanvas.height);// 將 HTML2Canvas 生成的內容繪制到新 Canvas 中newContext.drawImage(canvas, 0, 0, width, height);// 將新 Canvas 轉換為 base64 圖像var base64 = newCanvas.toDataURL("image/png");console.log(base64);// 發送數據到 邏輯層ownerVm.callMethod('receiveSendData', base64)}).catch(err => {})}, 300)},}}
</script><style scoped lang="scss">.BigBox {width: 630rpx;height: auto;background: #FFFFFF;border-radius: 20rpx 20rpx 20rpx 20rpx;display: flex;justify-content: center;align-items: center;}.barImg {width: 566rpx;height: 300rpx;}.BigBox2 {width: 630rpx;height: auto;background: #FFFFFF;border-radius: 20rpx 20rpx 20rpx 20rpx;display: flex;justify-content: space-between;padding: 32rpx 25rpx;box-sizing: border-box;margin: 0 auto;.lf {width: 362rpx;view {width: 100%;white-space: nowrap;/* 禁止換行 */overflow: hidden;/* 溢出內容隱藏 */text-overflow: ellipsis;/* 顯示省略號 */font-family: PingFang SC, PingFang SC;font-weight: 500;font-size: 40rpx;color: #000000;margin-top: 15rpx;font-weight: 700;}view:first-child {margin-top: 0;}}.rg {display: flex;justify-content: center;align-items: center;image {width: 204rpx;height: 204rpx;}}}.qrImg {}.print,.close {width: 48%;height: 88rpx;line-height: 88rpx;text-align: center;border-radius: 10rpx 10rpx 10rpx 10rpx;border: 2rpx solid #FFFFFF;font-family: PingFang SC, PingFang SC;font-weight: 500;font-size: 30rpx;color: #FFFFFF;margin-top: 160rpx;}.btnBox {width: 630rpx;display: flex;justify-content: space-between;margin: 0 auto;}#myCanvas {width: 350px;height: 176px;opacity: 0;}
</style>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/13883.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/13883.shtml
英文地址,請注明出處:http://en.pswp.cn/web/13883.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在Linux系統中解決Java生成海報文字亂碼和缺少字體文件的問題

在Linux系統中,如果缺少特定的字體文件,可以通過以下幾種方法來解決: 1. 安裝系統字體包 大多數Linux發行版提供了各種字體包,可以通過包管理器安裝這些字體包。例如,在Debian/Ubuntu系統上,可以使用以下命令安裝常見的字體包: # 安裝基本的字體包 sudo apt-get updat…

Java集合的組內平均值怎么計算

要計算Java集合&#xff08;例如List或Set中的Integer、Double或其他數值類型的對象&#xff09;的組內平均值&#xff0c;我們需要遍歷這個集合&#xff0c;累加所有的元素值&#xff0c;然后除以集合的大小&#xff08;即元素的數量&#xff09;。以下是一個詳細的步驟說明和…

opencl色域變換,處理傳遞顯存數據

在使用ffmpeg解碼后的多路解碼數據非常慢&#xff0c;還要給AI做行的加速方式是在顯存處理數據&#xff0c;在視頻拼接融合產品的產品與架構設計中&#xff0c;提出了比較可靠的方式是使用cuda&#xff0c;那么沒有cuda的顯卡如何處理呢 &#xff0c;比較好的方式是使用opencl來…

go語言的一些常見踩坑問題

開始之前&#xff0c;介紹一下?最近很火的開源技術&#xff0c;低代碼。 作為一種軟件開發技術逐漸進入了人們的視角里&#xff0c;它利用自身獨特的優勢占領市場一角——讓使用者可以通過可視化的方式&#xff0c;以更少的編碼&#xff0c;更快速地構建和交付應用軟件&#…

安卓手機APP開發__網絡連接性支持VPN

安卓手機APP開發__網絡連接性支持VPN 安卓提供了API給開發者,來創建一個虛擬的私有網絡(VPN)的解決方案. 根據這里的介紹,你能知道如何開發和測試你的針對安卓設備的VPN的客戶端. 概述 VPN允許設備為了安全地連接網絡,而沒有物理性的連接在一個網絡上. 安卓包括了一個內嵌的…

【無重復字符的最長子串】python,滑動窗口+哈希表

滑動窗口哈希表 哈希表 seen 統計&#xff1a; 指針 j遍歷字符 s&#xff0c;哈希表統計字符 s[j]最后一次出現的索引 。 更新左指針 i &#xff1a; 根據上輪左指針 i 和 seen[s[j]]&#xff0c;每輪更新左邊界 i &#xff0c;保證區間 [i1,j] 內無重復字符且最大。 更新結…

使用JSDOM安全截斷文章HTML內容

在Web開發中&#xff0c;經常需要處理大量的HTML內容&#xff0c;尤其是在展示文章預覽、動態加載內容或限制顯示長度等場景中。直接截斷HTML字符串可能會導致頁面布局混亂、樣式錯誤或標簽不完整等問題。為了安全地截斷HTML內容&#xff0c;我們可以利用jsdom庫來解析HTML&…

JVM學習-垃圾回收器(一)

垃圾回收器 按線程數分類 串行垃圾回收器 串行回收是在同一時間段內只允許有一個CPU用于執行垃圾回收操作&#xff0c;此時工作線程被暫停&#xff0c;直至垃圾收集工作結束 在諸如單CPU處理器或者較小的應用內存等硬件平臺不是特別優越的場合&#xff0c;串行回收器的性能表…

http和https的區別,怎么免費實現https(內涵教學)

超文本傳輸協議HTTP協議被用于在Web瀏覽器和網站服務器之間傳遞信息&#xff0c;HTTP協議以明文方式發送內容&#xff0c;不提供任何方式的數據加密&#xff0c;如果攻擊者截取了Web瀏覽器和網站服務器之間的傳輸報文&#xff0c;就可以直接讀懂其中的信息&#xff0c;因此&…

etcd 和 MongoDB 的混沌(故障注入)測試方法

最近在對一些自建的數據庫 driver/client 基礎庫的健壯性做混沌&#xff08;故障&#xff09;測試, 去驗證了解業務的故障處理機制和恢復時長. 主要涉及到了 MongoDB 和 etcd 這兩個基礎組件. 本文會介紹下相關的測試方法. MongoDB 中的故障測試 MongoDB 是比較世界上熱門的文…

AI網絡爬蟲:批量爬取電視貓上面的《慶余年》分集劇情

電視貓上面有《慶余年》分集劇情&#xff0c;如何批量爬取下來呢&#xff1f; 先找到每集的鏈接地址&#xff0c;都在這個class"epipage clear"的div標簽里面的li標簽下面的a標簽里面&#xff1a; <a href"/drama/Yy0wHDA/episode">1</a> 這個…

速盾:負載均衡能防ddos攻擊嗎?

負載均衡是一種分布式系統的設計思想&#xff0c;通過將流量分散到多個服務器上&#xff0c;以提高系統的穩定性和可擴展性。然而&#xff0c;負載均衡本身并不能完全防止DDoS攻擊&#xff0c;但可以在一定程度上減輕其影響。 DDoS&#xff08;分布式拒絕服務&#xff09;攻擊…

【C語言】8.C語言操作符詳解(1)

文章目錄 1.操作符的分類2.?進制和進制轉換3.原碼、反碼、補碼4.移位操作符4.1 左移操作符4.2 右移操作符 5.位操作符&#xff1a;&、|、^、~5.1 &&#xff1a;按位與5.2 |&#xff1a;按位或5.3 ^&#xff1a;按位異或5.4 ~&#xff1a;按位取反5.5 例題例題1例題2例…

短視頻矩陣系統4年獨立開發正規代發布接口源碼搭建部署開發

1. 短視頻矩陣源碼技術開發要求及實現流程&#xff1a; 短視頻矩陣源碼開發要求具備視頻錄制、編輯、剪輯、分享等基本功能&#xff0c;支持實時濾鏡、特效、音樂等個性化編輯&#xff0c;能夠實現高效的視頻渲染和處理。開發流程主要包括需求分析、技術選型、設計架構、編碼實…

Web前端開發技術、詳細文章、(例子)html 列表、有序列表、無序列表、列表嵌套

目錄 列表概述 列表類型與標記符號 無序列表 語法&#xff1a; 語法說明&#xff1a; 無序列表標記的 type 屬性及其說明 代碼解釋 有序列表 基本語法 屬性說明 1、列表 o1標記的屬性 2、列表項li標記的屬性 有序列表 o1標記的屬性、值 代碼解釋 列表嵌套 基本…

如何將Qt pro工程文件 改成CMakeLists.txt

Qt pro工程管理文件&#xff0c;本人認為是很好用的&#xff0c;語法簡潔易懂&#xff0c;但是只能在QtCreator中使用&#xff0c;想用使用其它IDE比如Clion或者vs&#xff0c;CMakeLists是種通用的選擇&#xff0c;另外QtCreator的調試功能跟粑粑一樣。 一&#xff0c;思路 …

FreeBSD/Linux下的系統資源監視器排隊隊

bpytop bpytop 是一個基于 Python 的資源監視器&#xff0c;可以在 FreeBSD 上使用。它提供了對文件寫入磁盤、網絡、CPU 和內存占用的監視功能。 pkg install bpytop 或者用ports安裝 cd /usr/ports/sysutils/bpytop/ make install clean bashtop bashtop 也是一個基于 P…

化簡資源分配圖判斷是否發生死鎖

目錄 1.資源分配圖的概念 2.判斷是否發生死鎖 1.資源分配圖的概念 資源分配圖表示進程和資源之間的請求關系&#xff0c;例如下圖&#xff1a; P代表進程&#xff0c;R代表資源&#xff0c;R方框中 有幾個圓球就表示有幾個這種資源&#xff0c;在圖中&#xff0c;R1指向P1&a…

C++ RPC ORM 高速解析

支持所有常用編程語 https://capnproto.org/GitHub - capnproto/capnproto: Capn Proto serialization/RPC system - core tools and C library https://capnproto.org/capnproto-c-win32-1.0.2.zip 常用命令&#xff1a; capnp help capnp compile -oc myschema.capn…

java文件上傳時給pdf、word、excel、ppt、圖片添加水印

前言 在開發的過程中&#xff0c;因為文件的特殊性&#xff0c;需要給pdf、word、excel、ppt、圖片添加水印。添加水印可以在文件上傳時添加&#xff0c;也可以在文件下載時添加。因為業務的某些原因&#xff0c;文件需要在瀏覽器預覽&#xff0c;如果用戶將文件另存為則無法添…