// GeoTiff 地图文件处理 // todo load: leaflet import JSZip from 'jszip' import { fileUtils } from '@/utils/util.js' import mapCanvas from '@/utils/mapCanvas.js' import * as wasmMap from '@/pkg/common_wasm.js' import { fromUrl, fromArrayBuffer, fromFile } from 'geotiff' // #ifdef APP-PLUS // import io from '@/utils/io.js' // #endif let that = null let dbHelper = null let imgMap = null export default { async handleMapInfo(context, mapInfo) { that = context dbHelper = that.$dbHelper imgMap = that.$refs.imgMap console.log("[handleMapInfo]", context, mapInfo) console.log("[handleMapInfo] imgMap", imgMap) try { await dbHelper.openDB() const res = await this.dbGetMapInfo(mapInfo.shopid) let download = false let action = null let mapData = null if (res == null || res.length == 0) { console.warn('[handleMapInfo] 本地无匹配记录,需要下载地图') download = true action = 'insert' } else { const localMd5 = (res.zipImage != undefined) ? res.zipImage.md5 : res.zipImageMd5 if (localMd5 != mapInfo.zipimage.md5) { console.warn('[handleMapInfo] MD5不同,需再次下载地图') download = true action = 'update' } else { console.log('[handleMapInfo] MD5相同,无需再次下载地图') download = false mapData = this.getMapDataFromDBres(res) // download = true // debug, will del // action = 'update' // debug, will del } } if (download) { const zipData = await this.getZipFiles(mapInfo.zipimage.url) // const unzipFiles = await this.unzipMap(zipData) // console.log("[handleMapInfo] download", mapInfo, unzipFiles) const unzipFiles = '' await this.dbSaveMapInfo(mapInfo, zipData, unzipFiles, action) // mapData = unzipFiles[0].fileData mapData = zipData } await dbHelper.closeDB() // await this.parseMap(mapData) // await this.parseMap2(mapData) await this.loadMap(mapData) // return mapData } catch (err) { console.error('[handleMapInfo]', err) } }, // 从指定的URL下载地图压缩包 async getZipFiles(zipUrl) { console.log("[getZipFiles] zipUrl:", zipUrl) if (!(zipUrl.length > 0)) { console.log("[getZipFiles] err: zipUrl 为空") return } let [err, res] = await uni.request({ url: zipUrl, timeout: 60000, // 超时时间,单位 ms responseType: 'arraybuffer', // 设置响应的数据类型。合法值:text、arraybuffer }); console.log("[getZipFiles]", res) return res.data }, // 解包并获取包内的各文件内容数据 (arraybuffer格式) async unzipMap(zipData) { // console.log("[unzipMap] zipData: ", zipData) if (zipData == undefined || (!(zipData.byteLength > 0))) { console.log("[unzipMap] err: zipData 为空") return } console.log("[unzipMap] 压缩包大小(字节) zipData.byteLength:", zipData.byteLength) try { let jsZip = new JSZip() let zip = await jsZip.loadAsync(zipData) // console.log('zip.files', zip.files) let unzipFiles = [] let i = 0 for (let fileName in zip.files) { // filename为压缩包中的文件名 console.log('[unzipMap] fileName', fileName) let isImage = fileUtils.isTypeImage(fileName) let fileData = '' let dataType = '' // 获取文件内容,可以使用string、arraybuffer等格式 if (isImage) { fileData = await zip.file(fileName).async('arraybuffer') dataType = 'arraybuffer' } else { fileData = await zip.file(fileName).async('string') dataType = 'string' } // console.log('[unzipMap] content', content) unzipFiles[i] = { fileName: fileName, fileData: fileData, dataType: dataType } i++ } return unzipFiles } catch(err) { console.error('[unzipMap]', err) } }, // 将地图信息保存到本地数据库中 async dbSaveMapInfo(mapInfo, zipData, unzipFiles='', action='insert') { // #ifdef H5 await this.dbSaveMapInfo_H5(mapInfo, zipData, unzipFiles, action) // #endif // #ifdef APP-PLUS await this.dbSaveMapInfo_APP(mapInfo, zipData, unzipFiles, action) // #endif }, // [H5端] 将地图信息保存到本地浏览器 dbHelper 数据库中 async dbSaveMapInfo_H5(mapInfo, zipData, unzipFiles, action) { // console.log("[dbSaveMapInfo_H5]", mapInfo, unzipFiles) let storeName = 'mapInfo' let data = { shopId: mapInfo.shopid, mapName: mapInfo.mapname, zipImage: { url: mapInfo.zipimage.url, md5: mapInfo.zipimage.md5, }, zipData: zipData, unzipFiles: unzipFiles } try { if (action == 'insert') { await dbHelper.insertData(storeName, data) } else if (action == 'update') { await dbHelper.updateData(storeName, data) } else { console.warn('[dbSaveMapInfo_H5] 参数 action 非法: ' + action) } } catch(err) { console.error('[dbSaveMapInfo_H5]', err) } }, // [APP端] 将地图信息保存到手机中的 SQLITE 数据库中 async dbSaveMapInfo_APP(mapInfo, zipData, unzipFiles, action) { // console.log("[dbSaveMapInfo_APP]", mapInfo, unzipFiles) let tableName = 'mapInfo' let zipFileKey = 'map_' + mapInfo.shopid let zipFileName = '' if (unzipFiles.length > 0) { zipFileName = unzipFiles[0].fileName // let zipFilePath = mapInfo.shopid + '_' + unzipFiles[0].fileName let zipFileData = uni.arrayBufferToBase64(unzipFiles[0].fileData) // await io.write(zipFilePath, zipFileData) uni.setStorageSync(zipFileKey, zipFileData); console.log("[dbSaveMapInfo_APP] setStorageSync Key:", zipFileKey) console.log("[dbSaveMapInfo_APP] setStorageSync data.fileData length:", unzipFiles[0].fileData.byteLength) // let zipFile = uni.base64ToArrayBuffer(uni.getStorageSync(zipFileKey)); // console.log("-----> getStorageSync Key", zipFileKey) // console.log("-----> getStorageSync data.fileData length", zipFile.byteLength) } let data = { shopId: mapInfo.shopid, mapName: mapInfo.mapname, zipImageUrl: mapInfo.zipimage.url, zipImageMd5: mapInfo.zipimage.md5, zipFileName: zipFileName, zipFileKey: zipFileKey, // zipFilePath: zipFilePath, } try { if (action == 'insert') { await dbHelper.insertData(tableName, data) } else if (action == 'update') { let wsql = 'shopId = ' + data.shopId await dbHelper.updateData(tableName, data, wsql) } else { console.warn('[dbSaveMapInfo_APP] 参数 action 非法: ' + action) } } catch(err) { console.error('[dbSaveMapInfo_APP]', err) } }, async dbGetMapInfo(shopid) { let res = null // #ifdef H5 res = await this.dbGetMapInfo_H5(shopid) // #endif // #ifdef APP-PLUS res = await this.dbGetMapInfo_APP(shopid) // #endif return res }, // [H5端] async dbGetMapInfo_H5(shopid) { console.log("[dbGetMapInfo_H5]", shopid) let storeName = 'mapInfo' let key = shopid try { let data = await dbHelper.getDataByKey(storeName, key) return data } catch(err) { console.error('[dbGetMapInfo_H5]', err) } }, // [APP端] async dbGetMapInfo_APP(shopid) { console.log("[dbGetMapInfo_APP] shopid", shopid) let tableName = 'mapInfo' let key = shopid try { let data = await dbHelper.getDataByKey(tableName, key) if (data != '' && data.zipFileKey.length > 0) { // let zipFileData = uni.base64ToArrayBuffer(await io.read(data.zipFilePath)) let zipFileData = uni.base64ToArrayBuffer(uni.getStorageSync(data.zipFileKey)) console.log("[dbGetMapInfo_APP] getStorageSync Key", data.zipFileKey) console.log("[dbGetMapInfo_APP] getStorageSync data length", zipFileData.byteLength) data.zipFileData = zipFileData } // console.log("[dbGetMapInfo_APP] data", data) return data } catch(err) { console.error('[dbGetMapInfo_APP]', err) } }, getMapDataFromDBres(dbres) { let arrayBuffer = null // #ifdef H5 // arrayBuffer = dbres.unzipFiles[0].fileData arrayBuffer = dbres.zipData // console.log('getMapDataFromDBres', dbres.unzipFiles[0].fileName, dbres.unzipFiles[0].fileData) // #endif // #ifdef APP-PLUS arrayBuffer = dbres.zipFileData // console.log('getMapDataFromDBres', dbres.zipFileName, dbres.zipFileData) // #endif return arrayBuffer }, async parseMap(arrayBuffer) { // console.log("[parseMap]", arrayBuffer) // for(let i=0; i<30; i++) { // console.log(`[parseMap] arrayBuffer[${i}] ${arrayBuffer[i]}`) // } if (arrayBuffer == undefined || (!(arrayBuffer.byteLength > 0))) { console.log("[parseMap] err: arrayBuffer 为空") return } console.log("[parseMap] MAP文件大小(字节) arrayBuffer.byteLength: " + arrayBuffer.byteLength) try { // 加载 GeoTIFF 文件 const tiff = await fromArrayBuffer(arrayBuffer) console.log("[parseMap] tiff", tiff) const image = await tiff.getImage() console.log("[parseMap] image", image) const width = image.getWidth(); const height = image.getHeight(); const tileWidth = image.getTileWidth(); const tileHeight = image.getTileHeight(); console.log( `[parseMap] width: ${width} height: ${height} tileWidth: ${tileWidth} tileHeight: ${tileHeight}` ) // const samplesPerPixel = image.getSamplesPerPixel(); // let canvas = this.$refs.canvasMap // canvas.width = width // canvas.height = height // let ctx = canvas.getContext('2d') // let ctx = uni.createCanvasContext('canvasMap', this) // 渲染图片 // ctx.drawImage(image, 0, 0) // ctx.draw() // console.log('图片渲染完成') // return let imageData = new Uint8ClampedArray(width * height * 4) // console.log("imageData:", imageData) // let src = that image.readRasters().then(function(rasters) { // console.log("rasters:", rasters) // console.log("rasters:", JSON.stringify(rasters)) for (let i = 0; i < width * height; i++) { let offset = i * 4 // console.log("rasters[0]:", rasters[0][i]) imageData[offset + 0] = rasters[0][i] imageData[offset + 1] = rasters[1][i] imageData[offset + 2] = rasters[2][i] imageData[offset + 3] = 255 } uni.canvasPutImageData({ canvasId: 'canvasMap', data: imageData, x: 0, y: 0, width: width, // height: 100, success(res) { console.log("[parseMap] canvasPutImageData res", res) }, fail(err) { console.log("[parseMap] canvasPutImageData err", err) } }) // ctx.draw() }) // // when we are actually dealing with geo-data the following methods return // // meaningful results: // const origin = image.getOrigin(); // const resolution = image.getResolution(); // const bbox = image.getBoundingBox(); } catch (err) { console.error("[parseMap] catch err:", err) } }, async parseMap2(mapData) { let binaryData = []; binaryData.push(mapData); that.mapUrl = URL.createObjectURL(new Blob(binaryData)); console.log("[parseMap2] imgMap", imgMap) // imgMap.src = URL.createObjectURL(new Blob(binaryData)); }, async loadMap(mapData) { try { let mapPackage = wasmMap.parse_map_package(new Uint8Array(mapData)) console.log("[loadMap] mapPackage", mapPackage) let binaryData = []; binaryData.push(mapPackage.map_image_data); that.mapUrl = URL.createObjectURL(new Blob(binaryData)); return await mapCanvas.initCanvas('canvasMap', that) mapCanvas.handleDrawMap(that.mapUrl) // let offset = new wasmMap.Offset() // offset.x = 100 // offset.y = 200 // let position = mapPackage.pic_to_position(offset) // console.log("[loadMap] pic_to_position", offset, position) // let position2 = new wasmMap.Position() // position2.latitude = 36.67352331171326 // position2.longitude = 117.1257123815962 // let offset2 = mapPackage.position_to_pic(position2) // console.log("[loadMap] position_to_pic", position2, offset2) // 使用完毕后一定要调用free方法释放内存 // position.free() // offset2.free() // mapPackage.free() // console.log("[loadMap] imgMap", imgMap) } catch (err) { console.error('[loadMap]', err) } } }