Windows CE 中向JPG文件写入经纬度 时间等信息

本文介绍如何使用ExifLib在WinCE环境下向JPG文件中添加GPS位置及时间信息,并提供示例代码。通过转换经纬度值并设置GPS标签,实现了在资源受限的平台上对图片进行地理标记。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在一个项目中  需要向JPG文件中写入时间  GPS位置等信息 如果是在PC上很好实现,但是在WinCE上由于.NET CF好多库都没有 所以实现起来还是挺困难,于是就在网上google看有什么开源的东西可以用,于是就找到了 ExifLib,在CodeProject的网址为http://www.codeproject.com/Articles/43665/ExifLibrary-for-NET,不过该源码为PC版的,要改改改才能在WinCE上运行,下面是示例代码

 

  /// <summary>
        /// 
        /// </summary>
        /// <param name="filename">JPG文件路径</param>
        /// <param name="latituderef">GPSLatitudeRef枚举值</param>
        /// <param name="latitude">纬度  弧度值</param>
        /// <param name="longituderef">GPSLongitudeRef 枚举值</param>
        /// <param name="longitude">经度  弧度值</param>
        /// <param name="time">DateTime 类型值  获取的GPS时间</param>
        private void SetLatituLongitudeAndGPSTime(string filename, GPSLatitudeRef latituderef, double latitude, GPSLongitudeRef longituderef, double longitude, DateTime time)
        {
            ImageFile file=null;
            try
            {
                file = ImageFile.FromFile(filename);
                CDms latitudedms = new CDms();
                latitudedms.Radian = Math.Abs(latitude);
                CDms longitudedms = new CDms();
                longitudedms.Radian = Math.Abs(longitude);
                uint latituded = (uint)Math.Round(latitudedms.d, 2) * 100;
                uint latitudem = (uint)Math.Round(latitudedms.m, 2) * 100;
                uint latitudes = (uint)Math.Round(latitudedms.s, 2) * 100;
                uint longituded = (uint)Math.Round(longitudedms.d, 2) * 100;
                uint longitudem = (uint)Math.Round(longitudedms.m, 2) * 100;
                uint longitudes = (uint)Math.Round(longitudedms.s, 2) * 100;
                ExifEnumProperty<GPSLatitudeRef> gpslatituderef = new ExifEnumProperty<GPSLatitudeRef>(ExifTag.GPSLatitudeRef, latituderef);
                GPSLatitudeLongitude gpsatitudeite = new GPSLatitudeLongitude(ExifTag.GPSLatitude, new MathEx.UFraction32[] { new MathEx.UFraction32(latituded, 100), new MathEx.UFraction32(latitudem, 100), new MathEx.UFraction32(latitudes, 100) });
                ExifEnumProperty<GPSLongitudeRef> gpslongituderef = new ExifEnumProperty<GPSLongitudeRef>(ExifTag.GPSLongitudeRef, longituderef);
                GPSLatitudeLongitude gpslongitude = new GPSLatitudeLongitude(ExifTag.GPSLongitude, new MathEx.UFraction32[] { new MathEx.UFraction32(longituded, 100), new MathEx.UFraction32(longitudem, 100), new MathEx.UFraction32(longitudes, 100) });
                //uint hour = (uint)time.Hour;
                //uint miniute = (uint)time.Minute;
                //uint second = (uint)time.Second;
                //GPSTimeStamp gpstime = new GPSTimeStamp(ExifTag.GPSTimeStamp, new MathEx.UFraction32[] { new MathEx.UFraction32(hour, 1), new MathEx.UFraction32(miniute, 1), new MathEx.UFraction32(second, 1) });
                ExifAscii datetimeoriginal = new ExifAscii(ExifTag.DateTimeOriginal, time.ToString("yyyy:MM:dd HH:mm:ss"));
                file.Properties.Add(datetimeoriginal);
                file.Properties.Add(gpslatituderef);
                file.Properties.Add(gpsatitudeite);
                file.Properties.Add(gpslongituderef);
                file.Properties.Add(gpslongitude);
                //file.Properties.Add(gpstime);
                file.Save(filename);
            }
            catch
            {
                file.Save(filename);
                Program.Log.Error("向JPG文件写入GPS信息出错");
            }
        }


 /// <summary>
        /// 往JPG图片上加入GPS信息
        /// </summary>
        /// <param name="filename">JPG文件路径</param>
        /// <returns>如果成功则返回添加了GPS信息的Bitmap,否则返回原图的Bitmap</returns>
        private Bitmap DrawGPSInfo(string filename)
        {
            ImageFile file = null;
            try
            {
                file = ImageFile.FromFile(filename);
                string timestr = file.Properties[ExifTag.DateTimeOriginal].Value.ToString();
                string latituderef = file.Properties[ExifTag.GPSLatitudeRef].Value.ToString();
                string latiude = (file.Properties[ExifTag.GPSLatitude] as ExifProperty).ToString();
                string longituderef = file.Properties[ExifTag.GPSLongitudeRef].Value.ToString();
                string longitude = (file.Properties[ExifTag.GPSLongitude] as ExifProperty).ToString();
                string[] strs1 = latiude.Split(new char[] { '.', '\'', '°' });
                string[] str2 = longitude.Split(new char[] { '.', '\'', '°' });
                string latitudestr = latituderef.Substring(0, 1).ToUpper() + ":" + strs1[0] + "°" + strs1[2] + "'" + strs1[4] + "\"";
                string longitudestr = longituderef.Substring(0, 1).ToUpper() + ":" + str2[0] + "°" + str2[2] + "'" + str2[4] + "\"";
                file.Save(filename);
                Font font = new Font("黑体", 10, FontStyle.Regular); //字体,大小
                SolidBrush brush = new SolidBrush(Color.Red); //笔刷,颜色
                Bitmap tempbitmap = new Bitmap(filename);
                Graphics g = Graphics.FromImage(tempbitmap);
                g.DrawString(timestr, font, brush, 10f, 10f);
                g.DrawString(latitudestr, font, brush, 10f, 30f);
                g.DrawString(longitudestr, font, brush, 10f, 50f);
                return tempbitmap;
            }
            catch
            {
                Program.Log.Error("JPG显示GPS信息出错");
                return new Bitmap(filename);
            }
        }


示例代码  和更改过后的源代码可到这下载

http://download.youkuaiyun.com/detail/xiaibiancheng/4972092
 

我正在编辑【c++】代码,遇到了 【0x00007FFFD5C115E1 (vcruntime140.dll) (test.exe 中)处有未经处理的异常: 0xC0000005: 写入位置 0x00000259FE6D4000 时发生访问冲突。 】 ,请帮我检查并改正错误点。我的原始代码如下: 【#include <iostream> #include <memory> #include <chrono> #include <fstream> #include <string> #include <iomanip> #include <opencv2/highgui.hpp> #include <opencv2/opencv.hpp> #include "gdal_priv.h" #include <gdal_alg_priv.h> #include <gdal.h> using namespace std; using namespace cv; //参考https://blog.youkuaiyun.com/ivan_ljf/article/details/9226463 //计算trans中图片xy点的经纬度信息 //adfGeoTransform的6个参数分别为左上角x坐标,水平分辨率,旋转参数,左上角y坐标,旋转参数,竖直分辨率,一般来说,旋转参数都为0 bool Projection2ImageRowCol(double* adfGeoTransform, double dProjX, double dProjY, int& iCol, int& iRow) { try { double dTemp = adfGeoTransform[1] * adfGeoTransform[5] - adfGeoTransform[2] * adfGeoTransform[4]; double dCol = 0.0, dRow = 0.0; dCol = (adfGeoTransform[5] * (dProjX - adfGeoTransform[0]) - adfGeoTransform[2] * (dProjY - adfGeoTransform[3])) / dTemp + 0.5; dRow = (adfGeoTransform[1] * (dProjY - adfGeoTransform[3]) - adfGeoTransform[4] * (dProjX - adfGeoTransform[0])) / dTemp + 0.5; iCol = int(dCol); iRow = int(dRow); return true; } catch (...) { return false; } } bool ImageRowCol2Projection(double* adfGeoTransform, int iCol, int iRow, double& dProjX, double& dProjY) { try { dProjX = adfGeoTransform[0] + adfGeoTransform[1] * iCol + adfGeoTransform[2] * iRow; dProjY = adfGeoTransform[3] + adfGeoTransform[4] * iCol + adfGeoTransform[5] * iRow; return true; } catch (...) { return false; } } int main() { GDALAllRegister();//注册所有的驱动 CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO"); //设置支持中文路径和文件名 //1、加载tif数据 string file_path_name = "D:\\Downloads\\上海区域九景影像\\ZY3_01a_mynbavp_880146_20120923_104301_0008_SASMAC_CHN_sec_rel_001_1209248618.tif"; //std::cout << "请输入图片路径:" << std::endl; //std::cin >> file_path_name; GDALDataset* poDataset = (GDALDataset*)GDALOpen(file_path_name.c_str(), GA_ReadOnly);//GA_Update和GA_ReadOnly两种模式 if (poDataset == NULL) { std::cout << "指定的文件不能打开!" << std::endl; return 0; } //获取图像的尺寸 int nImgSizeX = poDataset->GetRasterXSize(); int nImgSizeY = poDataset->GetRasterYSize(); std::cout << "ImageX = " << nImgSizeX << ", ImageY = " << nImgSizeY << std::endl; //获取图像的通道数(波段数量) int bandCount = poDataset->GetRasterCount(); std::cout << "bandCount = " << bandCount << std::endl; //获取图像波段 在GDAL中波段数的起始数是1,而非0 GDALRasterBand* poBand1 = poDataset->GetRasterBand(1); //GDAL中的数据类型 由此可知,每一个波段都可以有不同的数据类型 /* 一共包含以下12种数据类型 typedef enum { GDT_Unknown = 0, GDT_Byte = 1, GDT_UInt16 = 2, GDT_Int16 = 3, GDT_UInt32 = 4, GDT_Int32 = 5,GDT_UInt64,GDT_Int64 GDT_Float32 = 6, GDT_Float64 = 7, GDT_CInt16 = 8, GDT_CInt32 = 9,GDT_CInt64 GDT_CFloat32 = 10, GDT_CFloat64 = 11, GDT_TypeCount = 12 } GDALDataType; */ GDALDataType g_type = GDALDataType(poBand1->GetRasterDataType()); std::cout << "g_type = " << g_type << std::endl; //获取坐标变换系数 double trans[6] = { 0,1,0,0,0,1 };//定义为默认值,即x、y分辨率为1,其他信息为0 CPLErr aaa = poDataset->GetGeoTransform(trans); trans[2] = 0.3;//修改x的旋转参数信息 trans[4] = 0.1;//修改y的旋转参数信息 //poDataset->SetGeoTransform(trans);//设置坐标变换系数 std::cout << "trans = " << trans[0] << "," << trans[1] << "," << trans[2] << "," << trans[3] << "," << trans[4] << "," << trans[5] << std::endl; //像素坐标与投影坐标的换算 double dProjX, dProjY; int iCol, iRow; iCol = 111; iRow = 111; ImageRowCol2Projection(trans, iCol, iRow, dProjX, dProjY); std::cout << "在trans中,像素坐标=》经纬度:" << iCol << "," << iRow << "====》" << dProjX << "," << dProjY << std::endl; Projection2ImageRowCol(trans, dProjX, dProjY, iCol, iRow); std::cout << "在trans中,经纬度=》像素坐标:" << dProjX << "," << dProjY << "====》" << iCol << "," << iRow << std::endl; //获取图像投影坐标系信息, std::string projs = poDataset->GetProjectionRef(); //设置地理坐标系信息 //poDataset->SetProjection(projs.c_str()); std::cout << "projs = " << projs << std::endl; //读取gadl中第一个通道的数据到mat中 【通道数是从1开始的】 //RasterIO参数列表的详细说明可以参考 https://blog.51cto.com/u_15469043/4903358 /*从参数列表中是可以看到,GDAL是支持将数据分块读入的内存中的 CPLErr GDALRasterBand::RasterIO ( GDALRWFlag eRWFlag, int nXOff,//x的起始点 int nYOff,//y的起始点 int nXSize,//读取窗口的宽 int nYSize,//读取窗口的高 void * pData, int nBufXSize,//与nXSize相同 int nBufYSize,//与nYSize相同 GDALDataType eBufType, int nPixelSpace,//通常默认为0 int nLineSpace //通常默认为0 ) */ // cv::Mat gdal_mat1(nImgSizeY, nImgSizeX, CV_8UC1, Scalar(0)); cv::Mat gdal_mat2(nImgSizeY, nImgSizeX, CV_8UC1, Scalar(0)); cv::Mat gdal_mat3(nImgSizeY, nImgSizeX, CV_8UC1, Scalar(0)); poDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, 0, nImgSizeX, nImgSizeY, gdal_mat1.data, nImgSizeX, nImgSizeY, g_type, 0, 0); poDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, 0, nImgSizeX, nImgSizeY, gdal_mat2.data, nImgSizeX, nImgSizeY, g_type, 0, 0); poDataset->GetRasterBand(3)->RasterIO(GF_Read, 0, 0, nImgSizeX, nImgSizeY, gdal_mat3.data, nImgSizeX, nImgSizeY, g_type, 0, 0); cv::Mat mg; cv::merge(vector<cv::Mat>{ gdal_mat3, gdal_mat2, gdal_mat1, }, mg); cv::imwrite("read_save.jpg", mg); /* //读取gadl中第一个通道的数据到指针中 //void * malloc(size_t n):给指针分配相应的内存,并返回内存空间的首地址。当内存不再使用的时候,应使用free()函数将内存块释放掉。 uint8_t* srcData = (uint8_t*)malloc(sizeof(uint8_t) * nImgSizeX * nImgSizeY); //void * memset (void * p,int c,size_t n):将p中的n个字节都赋值为c memset(srcData, 0, sizeof(uint8_t) * 1 * nImgSizeX * nImgSizeY);//为空间赋默认值0 poDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, 0, nImgSizeX, nImgSizeY, srcData, nImgSizeX, nImgSizeY, g_type, 0, 0); */ //-----------创建gdal对象 MEM追加,CreateCopy保存支持tif、png、jpg等格式----- int nImgSizeX2 = gdal_mat1.cols; int nImgSizeY2 = gdal_mat1.rows; //获取GDAL驱动,MEM表示为内存对象,可以快速的分块追加写入数据。MEM文件大小是和你的系统内存大小有关系,并不会存储到磁盘中。可用的驱动格式还有:BMP、JPEG、PNG、GTiff、GIF、HFA、BT、ECW、FITS、HDF4、EHdr。分别对应着不同的文件类型 GDALDriver* pDriverMEM = GetGDALDriverManager()->GetDriverByName("MEM"); int nBands = 1; //创建GDAL对象,只保存原图的一个通道 //Create(const char * pszName,int nXSize, int nYSize, int nBands, GDALDataType eType, char** papszOptions) GDALDataset* poDataset2 = pDriverMEM->Create("", nImgSizeX2, nImgSizeY2, nBands, g_type, NULL); //将mat数据写入到GDALDataset中 poDataset2->GetRasterBand(1)->RasterIO(GF_Write, 0, 0, nImgSizeX2, nImgSizeY2, gdal_mat1.data, nImgSizeX2, nImgSizeY2, GDT_Byte, 0, 0); //获取GDAL驱动,PNG表示为用png驱动保存数据 GDALDriver* pDriverSave = GetGDALDriverManager()->GetDriverByName("PNG"); pDriverSave->CreateCopy("saved.png", poDataset2, TRUE, 0, 0, 0); //创建png文件 std::cout << "png 文件保存成功" << std::endl; //-----------创建gdal对象 一次性写入,只支持tiff数据。PEN、JPEG等驱动没有实现相应的Create方法----- int nImgSizeX3 = gdal_mat1.cols; int nImgSizeY3 = gdal_mat1.rows; GDALDriver* pDriverMEM3 = GetGDALDriverManager()->GetDriverByName("GTiff"); if (!pDriverMEM3) { fprintf(stderr, "get driver by name failed\n"); return -1; } int nBands3 = 1; GDALDataset* poDataset3 = pDriverMEM3->Create("saved3.tif", nImgSizeX3, nImgSizeY3, nBands3, g_type, NULL); if (!poDataset3) { fprintf(stderr, "Create GDALDataset failed\n"); return -1; } poDataset3->GetRasterBand(1)->RasterIO(GF_Write, 0, 0, nImgSizeX3, nImgSizeY3, gdal_mat1.data, nImgSizeX3, nImgSizeY3, GDT_Byte, 0, 0); std::cout << "tif 文件保存成功" << std::endl; //关闭GDAL对象,并注销所有驱动 GDALClose(poDataset); GDALClose(poDataset2); GDALClose(poDataset3); GDALDestroyDriverManager(); return -1; }】
最新发布
07-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值