uniapp app端解析图片的经纬度、方位角

一般情况下gpsImgDirection即为图片的方向角,但是大疆图片的方位角不是,大疆图片的方位角是通过**exif.getAttribute("Xmp")**获取到图片的xml,然后再xml里获取到的方位角

具体代码如下:

复制代码
let that = this
//图片的路径
let imgPath = 'XXXX'
// 仅支持 Android 端
if (plus.os.name !== 'Android') {
        console.log("仅支持 Android 端读取 EXIF 信息");
        return;
}
try {
        // 1. 导入 Android 原生类
        const ExifInterface = plus.android.importClass('android.media.ExifInterface');
        // 2. 实例化 ExifInterface(传入图片路径)
        const exif = new ExifInterface(imgPath);
        // 3. 定义需要读取的 EXIF 字段(可扩展)
        const exifFields = {
          // 基础信息
          orientation: ExifInterface.TAG_ORIENTATION, // 图片旋转角度
          width: ExifInterface.TAG_IMAGE_WIDTH, // 图片宽度
          height: ExifInterface.TAG_IMAGE_LENGTH, // 图片高度
          mimeType: ExifInterface.TAG_MIME_TYPE, // 图片格式
          dateTime: ExifInterface.TAG_DATETIME, // 拍摄时间
          // 相机信息
          make: ExifInterface.TAG_MAKE, // 设备制造商
          model: ExifInterface.TAG_MODEL, // 设备型号
          exposureTime: ExifInterface.TAG_EXPOSURE_TIME, // 曝光时间
          fNumber: ExifInterface.TAG_F_NUMBER, // 光圈
          iso: ExifInterface.TAG_ISO_SPEED_RATINGS, // ISO
          focalLength: ExifInterface.TAG_FOCAL_LENGTH, // 焦距
          // GPS 信息
          gpsLatitude: ExifInterface.TAG_GPS_LATITUDE, // 纬度
          gpsLatitudeRef: ExifInterface.TAG_GPS_LATITUDE_REF, // 纬度方向(N/S)
          gpsLongitude: ExifInterface.TAG_GPS_LONGITUDE, // 经度
          gpsLongitudeRef: ExifInterface.TAG_GPS_LONGITUDE_REF, // 经度方向(E/W)
          gpsAltitude: ExifInterface.TAG_GPS_ALTITUDE, // 海拔
          gpsAltitudeRef: ExifInterface.TAG_GPS_ALTITUDE_REF, // 海拔参考
          gpsImgDirection: ExifInterface.TAG_GPS_IMG_DIRECTION, // 拍摄方位角(真北 / 磁北)浮点数(0~360),如 90.0 表示正东
          gpsImgDirectionRef: ExifInterface.TAG_GPS_IMG_DIRECTION_REF, // 方位角参考基准 T= 真北,M= 磁北
        };
        // 4. 解析 EXIF 字段
        const exifInfo = {};
        for (const [key, tag] of Object.entries(exifFields)) {
          try {
            // 读取字段值(部分字段返回 null 表示无该信息)
            const value = exif.getAttribute(tag);
            // console.log("解析出的键值对信息", `${tag}: ${value}`)
            if (value !== null) {
              exifInfo[key] = value;
            }
          } catch (e) {
            exifInfo[key] = '解析失败';
          }
        }
        // 5. 解析 GPS 坐标为标准格式(度分秒转十进制)
        if (exifInfo.gpsLatitude && exifInfo.gpsLatitudeRef) {
          exifInfo.gpsLatitudeDecimal = that
            .convertDmsToDecimal(
              exifInfo.gpsLatitude,
              exifInfo.gpsLatitudeRef
            );
        }
        if (exifInfo.gpsLongitude && exifInfo
          .gpsLongitudeRef) {
          exifInfo.gpsLongitudeDecimal = that
            .convertDmsToDecimal(
              exifInfo.gpsLongitude,
              exifInfo.gpsLongitudeRef
            );
        }
        // 解析大疆图片的方位角
        const xmpRawData = exif.getAttribute("Xmp");
        const gimbalYaw = that.getDJIGimbalYaw(xmpRawData);
        console.log('经纬度', exifInfo.gpsLatitudeDecimal, exifInfo.gpsLongitudeDecimal)
        console.log('方位角', gimbalYaw)
} catch (err) {
        console.log(`解析 EXIF 失败:${err.message}`)
 }

convertDmsToDecimal方法

解析 GPS 坐标为标准格式(度分秒转十进制)

复制代码
convertDmsToDecimal(dmsStr, ref) {
    try {
					// 拆分度、分、秒(如 "30/1,12/1,3456/100" → [30, 12, 34.56])
					const parts = dmsStr.split(',').map(part => {
						const [num, den] = part.split('/').map(Number);
						return den === 0 ? 0 : num / den;
					});
					const [degrees, minutes, seconds] = parts;
					// 计算十进制
					let decimal = degrees + minutes / 60 + seconds / 3600;
					// 南纬/西经取负数
					if (ref === 'S' || ref === 'W') {
						decimal = -decimal;
					}
					return Number(decimal.toFixed(6)); // 保留 6 位小数
    } catch (e) {
        return null;
    }
},

getDJIGimbalYaw方法

获取到大疆图片的xml文件后,解析xml里的方位角

复制代码
getDJIGimbalYaw(xmpRawData) {
    try {
					const pureXml = xmpRawData
						.replace(/<\?xpacket begin[^>]*\?>/g, "")
						.replace(/<\?xpacket end[^>]*\?>/g, "")
						.trim();

					// 1. 导入 Android 原生 XML 解析类
					const XmlPullParser = plus.android.importClass('org.xmlpull.v1.XmlPullParser');
					const XmlPullParserFactory = plus.android.importClass('org.xmlpull.v1.XmlPullParserFactory');
					const StringReader = plus.android.importClass('java.io.StringReader');

					// 2. 创建 XML 解析工厂和解析器
					const factory = XmlPullParserFactory.newInstance();
					// 注意:setNamespaceAware 也需要用 invoke 调用(避免潜在报错)
					plus.android.invoke(factory, "setNamespaceAware", true);
					const parser = plus.android.invoke(factory, "newPullParser"); // 通过 invoke 创建 parser
					const reader = new StringReader(pureXml);
					// 通过 plus.android.invoke 调用 setInput 方法
					plus.android.invoke(parser, "setInput", reader);

					// 3. 定义需要获取的方位角字段(大疆 XMP 中常见的方位角字段)
					let gimbalYaw = null;
					const droneDjiNs = "http://www.dji.com/drone-dji/1.0/"; // 大疆命名空间
					const rdfNs = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; // rdf命名空间

					// 4. 开始解析 XML
					let eventType = plus.android.invoke(parser, "getEventType");
					const END_DOCUMENT = plus.android.getAttribute(XmlPullParserFactory, "END_DOCUMENT"); // 获取常量
					const START_TAG = plus.android.getAttribute(XmlPullParserFactory, "START_TAG"); // 获取常量
					while (eventType !== XmlPullParser.END_DOCUMENT) {
						if (eventType === XmlPullParser.START_TAG) {
							const tagName = plus.android.invoke(parser, "getName");
							const currentNs = plus.android.invoke(parser, "getNamespace");
							// 匹配rdf:Description标签(这是包含大疆属性的目标标签)
							if (currentNs === rdfNs && tagName === "Description") {
								// 提取drone-dji命名空间下的GimbalYawDegree属性
								gimbalYaw = plus.android.invoke(parser, "getAttributeValue", droneDjiNs,
								"GimbalYawDegree");
								// 提取到后直接break,无需继续遍历
								break;
							}
						}
						eventType = plus.android.invoke(parser, "next"); // 遍历下一个节点
					}

					// 5. 处理解析结果(转为数字类型,方便后续使用)
					gimbalYaw = gimbalYaw ? parseFloat(gimbalYaw) : null;
					return gimbalYaw
    } catch (error) {
        console.error('Android 原生解析 XMP 方位角失败:', error.message);
    }
},
相关推荐
h_65432102 小时前
uniapp app端获取指定路径下的所有图片
uni-app
雪芽蓝域zzs2 小时前
uniapp真机运行鸿蒙定位报getLocation:fail maybe not obtain GPS Permission
华为·uni-app·harmonyos
初遇你时动了情2 小时前
不用每个请求都写获取请求 类似无感刷新逻辑 uniapp vue3 react实现方案
javascript·react.js·uni-app
apollo_qwe19 小时前
解决移动端键盘遮挡痛点
uni-app
脾气有点小暴2 天前
scroll-view分页加载
前端·javascript·uni-app
脾气有点小暴2 天前
uniapp自定义头部导航
前端·uni-app
前端 贾公子2 天前
[uniapp][swtich开关]阻止切换状态(类似阻止事件冒泡)
uni-app
雪芽蓝域zzs2 天前
uniapp基于picker选择器实现年月日时分秒
uni-app
niucloud-admin2 天前
本地开发部署——uniapp端站点部署
uni-app