技术标签: jpg Exif C++ 图片 图像知识 GPS
读取Exif基本上就是在懂得Exif的格式的基础上,详细见上文:
bool Cexif::DecodeExif(FILE * hFile)
{
int a;
int HaveCom = 0;
a = fgetc(hFile);
if (a != 0xff || fgetc(hFile) != M_SOI){
return 0;
}
for(;;){
int itemlen;
int marker = 0;
int ll,lh, got;
unsigned char * Data;
if (SectionsRead >= MAX_SECTIONS){
strcpy(m_szLastError,"Too many sections in jpg file");
return 0;
}
for (a=0;a<7;a++){
marker = fgetc(hFile);
if (marker != 0xff) break;
if (a >= 6){
printf("too many padding unsigned chars\n");
return 0;
}
}
if (marker == 0xff){
// 0xff is legal padding, but if we get that many, something's wrong.
strcpy(m_szLastError,"too many padding unsigned chars!");
return 0;
}
Sections[SectionsRead].Type = marker;
// Read the length of the section.
lh = fgetc(hFile);
ll = fgetc(hFile);
itemlen = (lh << 8) | ll;
if (itemlen < 2){
strcpy(m_szLastError,"invalid marker");
return 0;
}
Sections[SectionsRead].Size = itemlen;
Data = (unsigned char *)malloc(itemlen);
if (Data == NULL){
strcpy(m_szLastError,"Could not allocate memory");
return 0;
}
Sections[SectionsRead].Data = Data;
// Store first two pre-read unsigned chars.
Data[0] = (unsigned char)lh;
Data[1] = (unsigned char)ll;
got = fread(Data+2, 1, itemlen-2,hFile); // Read the whole section.
if (got != itemlen-2){
strcpy(m_szLastError,"Premature end of file?");
return 0;
}
SectionsRead += 1;
switch(marker){
case M_SOS: // stop before hitting compressed data
// If reading entire image is requested, read the rest of the data.
/*if (ReadMode & READ_IMAGE){
int cp, ep, size;
// Determine how much file is left.
cp = ftell(infile);
fseek(infile, 0, SEEK_END);
ep = ftell(infile);
fseek(infile, cp, SEEK_SET);
size = ep-cp;
Data = (uchar *)malloc(size);
if (Data == NULL){
strcpy(m_szLastError,"could not allocate data for entire image");
return 0;
}
got = fread(Data, 1, size, infile);
if (got != size){
strcpy(m_szLastError,"could not read the rest of the image");
return 0;
}
Sections[SectionsRead].Data = Data;
Sections[SectionsRead].Size = size;
Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER;
SectionsRead ++;
HaveAll = 1;
}*/
return 1;
case M_EOI: // in case it's a tables-only JPEG stream
printf("No image in jpeg!\n");
return 0;
case M_COM: // Comment section
if (HaveCom){
// Discard this section.
free(Sections[--SectionsRead].Data);
Sections[SectionsRead].Data=0;
}else{
process_COM(Data, itemlen);
HaveCom = 1;
}
break;
case M_JFIF:
// Regular jpegs always have this tag, exif images have the exif
// marker instead, althogh ACDsee will write images with both markers.
// this program will re-create this marker on absence of exif marker.
// hence no need to keep the copy from the file.
free(Sections[--SectionsRead].Data);
Sections[SectionsRead].Data=0;
break;
case M_EXIF:
// Seen files from some 'U-lead' software with Vivitar scanner
// that uses marker 31 for non exif stuff. Thus make sure
// it says 'Exif' in the section before treating it as exif.
if (memcmp(Data+2, "Exif", 4) == 0){
m_exifinfo->IsExif = process_EXIF((unsigned char *)Data+2, itemlen);
}else{
// Discard this section.
free(Sections[--SectionsRead].Data);
Sections[SectionsRead].Data=0;
}
break;
case M_SOF0:
case M_SOF1:
case M_SOF2:
case M_SOF3:
case M_SOF5:
case M_SOF6:
case M_SOF7:
case M_SOF9:
case M_SOF10:
case M_SOF11:
case M_SOF13:
case M_SOF14:
case M_SOF15:
process_SOFn(Data, marker);
break;
default:
// Skip any other sections.
//if (ShowTags) printf("Jpeg section marker 0x%02x size %d\n",marker, itemlen);
break;
}
}
return 1;
}
/*--------------------------------------------------------------------------
Process a EXIF marker
Describes all the drivel that most digital cameras include...
--------------------------------------------------------------------------*/
bool Cexif::process_EXIF(unsigned char * CharBuf, unsigned int length)
{
m_exifinfo->FlashUsed = 0;
/* If it's from a digicam, and it used flash, it says so. */
m_exifinfo->Comments[0] = '\0'; /* Initial value - null string */
ExifImageWidth = 0;
{ /* Check the EXIF header component */
static const unsigned char ExifHeader[] = "Exif\0\0";
if (memcmp(CharBuf+0, ExifHeader,6)){
strcpy(m_szLastError,"Incorrect Exif header");
return 0;
}
}
if (memcmp(CharBuf+6,"II",2) == 0){
MotorolaOrder = 0;
}else{
if (memcmp(CharBuf+6,"MM",2) == 0){
MotorolaOrder = 1;
}else{
strcpy(m_szLastError,"Invalid Exif alignment marker.");
return 0;
}
}
/* Check the next two values for correctness. */
if (Get16u(CharBuf+8) != 0x2a){
strcpy(m_szLastError,"Invalid Exif start (1)");
return 0;
}
int FirstOffset = Get32u(CharBuf+10);
if (FirstOffset < 8 || FirstOffset > 16){
// I used to ensure this was set to 8 (website I used indicated its 8)
// but PENTAX Optio 230 has it set differently, and uses it as offset. (Sept 11 2002)
strcpy(m_szLastError,"Suspicious offset of first IFD value");
return 0;
}
unsigned char * LastExifRefd = CharBuf;
/* First directory starts 16 unsigned chars in. Offsets start at 8 unsigned chars in. */
if (!ProcessExifDir(CharBuf+14, CharBuf+6, length-6, m_exifinfo, &LastExifRefd))
return 0;
/* This is how far the interesting (non thumbnail) part of the exif went. */
// int ExifSettingsLength = LastExifRefd - CharBuf;
/* Compute the CCD width, in milimeters. */
if (m_exifinfo->FocalplaneXRes != 0){
m_exifinfo->CCDWidth = (float)(ExifImageWidth * m_exifinfo->FocalplaneUnits / m_exifinfo->FocalplaneXRes);
}
return 1;
}
/*--------------------------------------------------------------------------
Process one of the nested EXIF directories.
--------------------------------------------------------------------------*/
bool Cexif::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength,
EXIFINFO * const m_exifinfo, unsigned char ** const LastExifRefdP )
{
int de;
int a;
int NumDirEntries;
unsigned ThumbnailOffset = 0;
unsigned ThumbnailSize = 0;
NumDirEntries = Get16u(DirStart);
if ((DirStart+2+NumDirEntries*12) > (OffsetBase+ExifLength)){
strcpy(m_szLastError,"Illegally sized directory");
return 0;
}
for (de=0;de<NumDirEntries;de++){
int Tag, Format, Components;
unsigned char * ValuePtr;
/* This actually can point to a variety of things; it must be
cast to other types when used. But we use it as a unsigned char-by-unsigned char
cursor, so we declare it as a pointer to a generic unsigned char here.
*/
int BytesCount;
unsigned char * DirEntry;
DirEntry = DirStart+2+12*de;
Tag = Get16u(DirEntry);
Format = Get16u(DirEntry+2);
Components = Get32u(DirEntry+4);
if ((Format-1) >= NUM_FORMATS) {
/* (-1) catches illegal zero case as unsigned underflows to positive large */
strcpy(m_szLastError,"Illegal format code in EXIF dir");
return 0;
}
BytesCount = Components * BytesPerFormat[Format];
if (BytesCount > 4){
unsigned OffsetVal;
OffsetVal = Get32u(DirEntry+8);
/* If its bigger than 4 unsigned chars, the dir entry contains an offset.*/
if (OffsetVal+BytesCount > ExifLength){
/* Bogus pointer offset and / or unsigned charcount value */
strcpy(m_szLastError,"Illegal pointer offset value in EXIF.");
return 0;
}
ValuePtr = OffsetBase+OffsetVal;
}else{
/* 4 unsigned chars or less and value is in the dir entry itself */
ValuePtr = DirEntry+8;
}
if (*LastExifRefdP < ValuePtr+BytesCount){
/* Keep track of last unsigned char in the exif header that was
actually referenced. That way, we know where the
discardable thumbnail data begins.
*/
*LastExifRefdP = ValuePtr+BytesCount;
}
/* Extract useful components of tag */
switch(Tag){
case TAG_MAKE:
strncpy(m_exifinfo->CameraMake, (char*)ValuePtr, 31);
break;
case TAG_MODEL:
strncpy(m_exifinfo->CameraModel, (char*)ValuePtr, 39);
break;
case TAG_EXIF_VERSION:
strncpy(m_exifinfo->Version,(char*)ValuePtr, 4);
break;
case TAG_DATETIME_ORIGINAL:
strncpy(m_exifinfo->DateTime, (char*)ValuePtr, 19);
break;
case TAG_USERCOMMENT:
// Olympus has this padded with trailing spaces. Remove these first.
for (a=BytesCount;;){
a--;
if (((char*)ValuePtr)[a] == ' '){
((char*)ValuePtr)[a] = '\0';
}else{
break;
}
if (a == 0) break;
}
/* Copy the comment */
if (memcmp(ValuePtr, "ASCII",5) == 0){
for (a=5;a<10;a++){
char c;
c = ((char*)ValuePtr)[a];
if (c != '\0' && c != ' '){
strncpy(m_exifinfo->Comments, (char*)ValuePtr+a, 199);
break;
}
}
}else{
strncpy(m_exifinfo->Comments, (char*)ValuePtr, 199);
}
break;
case TAG_FNUMBER:
/* Simplest way of expressing aperture, so I trust it the most.
(overwrite previously computd value if there is one)
*/
m_exifinfo->ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
break;
case TAG_APERTURE:
case TAG_MAXAPERTURE:
/* More relevant info always comes earlier, so only
use this field if we don't have appropriate aperture
information yet.
*/
if (m_exifinfo->ApertureFNumber == 0){
m_exifinfo->ApertureFNumber = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5);
}
break;
case TAG_BRIGHTNESS:
m_exifinfo->Brightness = (float)ConvertAnyFormat(ValuePtr, Format);
break;
case TAG_FOCALLENGTH:
/* Nice digital cameras actually save the focal length
as a function of how farthey are zoomed in.
*/
m_exifinfo->FocalLength = (float)ConvertAnyFormat(ValuePtr, Format);
break;
case TAG_SUBJECT_DISTANCE:
/* Inidcates the distacne the autofocus camera is focused to.
Tends to be less accurate as distance increases.
*/
m_exifinfo->Distance = (float)ConvertAnyFormat(ValuePtr, Format);
break;
case TAG_EXPOSURETIME:
/* Simplest way of expressing exposure time, so I
trust it most. (overwrite previously computd value
if there is one)
*/
m_exifinfo->ExposureTime =
(float)ConvertAnyFormat(ValuePtr, Format);
break;
case TAG_SHUTTERSPEED:
/* More complicated way of expressing exposure time,
so only use this value if we don't already have it
from somewhere else.
*/
if (m_exifinfo->ExposureTime == 0){
m_exifinfo->ExposureTime = (float)
(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2)));
}
break;
case TAG_FLASH:
if ((int)ConvertAnyFormat(ValuePtr, Format) & 7){
m_exifinfo->FlashUsed = 1;
}else{
m_exifinfo->FlashUsed = 0;
}
break;
case TAG_ORIENTATION:
m_exifinfo->Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
if (m_exifinfo->Orientation < 1 || m_exifinfo->Orientation > 8){
strcpy(m_szLastError,"Undefined rotation value");
m_exifinfo->Orientation = 0;
}
break;
case TAG_EXIF_IMAGELENGTH:
case TAG_EXIF_IMAGEWIDTH:
/* Use largest of height and width to deal with images
that have been rotated to portrait format.
*/
a = (int)ConvertAnyFormat(ValuePtr, Format);
if (ExifImageWidth < a) ExifImageWidth = a;
break;
case TAG_FOCALPLANEXRES:
m_exifinfo->FocalplaneXRes = (float)ConvertAnyFormat(ValuePtr, Format);
break;
case TAG_FOCALPLANEYRES:
m_exifinfo->FocalplaneYRes = (float)ConvertAnyFormat(ValuePtr, Format);
break;
case TAG_RESOLUTIONUNIT:
switch((int)ConvertAnyFormat(ValuePtr, Format)){
case 1: m_exifinfo->ResolutionUnit = 1.0f; break; /* 1 inch */
case 2: m_exifinfo->ResolutionUnit = 1.0f; break;
case 3: m_exifinfo->ResolutionUnit = 0.3937007874f; break; /* 1 centimeter*/
case 4: m_exifinfo->ResolutionUnit = 0.03937007874f; break; /* 1 millimeter*/
case 5: m_exifinfo->ResolutionUnit = 0.00003937007874f; /* 1 micrometer*/
}
break;
case TAG_FOCALPLANEUNITS:
switch((int)ConvertAnyFormat(ValuePtr, Format)){
case 1: m_exifinfo->FocalplaneUnits = 1.0f; break; /* 1 inch */
case 2: m_exifinfo->FocalplaneUnits = 1.0f; break;
case 3: m_exifinfo->FocalplaneUnits = 0.3937007874f; break; /* 1 centimeter*/
case 4: m_exifinfo->FocalplaneUnits = 0.03937007874f; break; /* 1 millimeter*/
case 5: m_exifinfo->FocalplaneUnits = 0.00003937007874f; /* 1 micrometer*/
}
break;
// Remaining cases contributed by: Volker C. Schoech <schoech(at)gmx(dot)de>
case TAG_EXPOSURE_BIAS:
m_exifinfo->ExposureBias = (float) ConvertAnyFormat(ValuePtr, Format);
break;
case TAG_WHITEBALANCE:
m_exifinfo->Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
break;
case TAG_METERING_MODE:
m_exifinfo->MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
break;
case TAG_EXPOSURE_PROGRAM:
m_exifinfo->ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
break;
case TAG_ISO_EQUIVALENT:
m_exifinfo->ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
if ( m_exifinfo->ISOequivalent < 50 ) m_exifinfo->ISOequivalent *= 200;
break;
case TAG_COMPRESSION_LEVEL:
m_exifinfo->CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format);
break;
case TAG_XRESOLUTION:
m_exifinfo->Xresolution = (float)ConvertAnyFormat(ValuePtr, Format);
break;
case TAG_YRESOLUTION:
m_exifinfo->Yresolution = (float)ConvertAnyFormat(ValuePtr, Format);
break;
case TAG_THUMBNAIL_OFFSET:
ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);
break;
case TAG_THUMBNAIL_LENGTH:
ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format);
break;
}
if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET){
unsigned char * SubdirStart;
SubdirStart = OffsetBase + Get32u(ValuePtr);
if (SubdirStart < OffsetBase ||
SubdirStart > OffsetBase+ExifLength){
strcpy(m_szLastError,"Illegal subdirectory link");
return 0;
}
ProcessExifDir(SubdirStart, OffsetBase, ExifLength, m_exifinfo, LastExifRefdP);
continue;
}
}
{
/* In addition to linking to subdirectories via exif tags,
there's also a potential link to another directory at the end
of each directory. This has got to be the result of a
committee!
*/
unsigned char * SubdirStart;
unsigned Offset;
Offset = Get16u(DirStart+2+12*NumDirEntries);
if (Offset){
SubdirStart = OffsetBase + Offset;
if (SubdirStart < OffsetBase
|| SubdirStart > OffsetBase+ExifLength){
strcpy(m_szLastError,"Illegal subdirectory link");
return 0;
}
ProcessExifDir(SubdirStart, OffsetBase, ExifLength, m_exifinfo, LastExifRefdP);
}
}
if (ThumbnailSize && ThumbnailOffset){
if (ThumbnailSize + ThumbnailOffset <= ExifLength){
/* The thumbnail pointer appears to be valid. Store it. */
m_exifinfo->ThumbnailPointer = OffsetBase + ThumbnailOffset;
m_exifinfo->ThumbnailSize = ThumbnailSize;
}
}
return 1;
}
文章浏览阅读2.7k次,点赞3次,收藏11次。SpringBoot+Maven+MabatisPlusmaven在新建springboot项目引入RELEASE版本出错maven在新建springboot项目引入RELEASE版本出错maven详解maven就是通过pom.xml中的配置,就能够从仓库获取到想要的jar包。仓库分为:本地仓库、第三方仓库(私服)、中央仓库springframework.boot:spring-boot-starter-parent:2.2.1.RELEASE’ not found若出现jar包下载不了只有两_基于微服务的在线教育平台尚硅谷
文章浏览阅读1k次。数据库备份的方法第一种:使用mysqldump结合exec函数进行数据库备份操作。第二种:使用php+mysql+header函数进行数据库备份和下载操作。下面 java 实现数据库备份的方法就是第一种首先我们得知道一些mysqldump的数据库备份语句备份一个数据库格式:mysqldump -h主机名 -P端口 -u用户名 -p密码 --database 数据库名 ..._java数据备份
文章浏览阅读3.4k次,点赞2次,收藏14次。window10_ffmpeg调试环境搭建_win10如何使用mingw64编译ffmpeg
文章浏览阅读6.3k次,点赞9次,收藏14次。给大家推荐《考试脑科学》这本书。作者介绍:池谷裕二,日本东京大学药学系研究科教授,脑科学研究者。1970年生于日本静冈县,1998年取得日本东京大学药学博士学位,2002年起担任美国哥伦比亚大学客座研究员。专业为神经科学与药理学,研究领域为人脑海马体与大脑皮质层的可塑性。现为东京大学药学研究所教授,同时担任日本脑信息通信融合研究中心研究主任,日本药理学会学术评议员、ERATO人脑与AI融合项目负责人。2008年获得日本文部大臣表彰青年科学家奖,2013年获得日本学士院学术奖励奖。这本书作者用非常通俗易懂_考试脑科学pdf百度网盘下载
文章浏览阅读1.4k次。其中,成都鼎桥通信技术有限公司是一家专业从事移动通讯终端产品研发和生产的高科技企业,其发布的TD Tech M40也是华为智选手机系列中的重要代表之一。华为智选手机是由华为品牌方与其他公司合作推出的手机产品,虽然其机身上没有“华为”标识,但是其品质和技术水平都是由华为来保证的。总之,华为智选手机是由华为品牌方和其他公司合作推出的手机产品,虽然外观上没有“华为”标识,但其品质和技术水平都是由华为来保证的。华为智选手机采用了多种处理器品牌,以满足不同用户的需求,同时也可以享受到华为全国联保的服务。_华为智选手机和华为手机的区别
文章浏览阅读7.6k次,点赞6次,收藏17次。目录题目描述输入输出代码打擂法数组排序任意输入n个整数,把它们的最大值求出来.输入只有一行,包括一个整数n(1_n个数中最大的那个数在哪里?输出其位置,若有多个最大数则都要输出。
文章浏览阅读4.8k次,点赞17次,收藏51次。Linux的命令有几百个,对程序员来说,常用的并不多,考虑各位是初学者,先学习本章节前15个命令就可以了,其它的命令以后用到的时候再学习。1、开机 物理机服务器,按下电源开关,就像windows开机一样。 在VMware中点击“开启此虚拟机”。2、登录 启动完成后,输入用户名和密码,一般情况下,不要用root用户..._ls-lmore
文章浏览阅读4.1k次。1.登录MYSQL系统命令打开DOS命令框shengfen,以管理员的身份运行命令1:mysql -u usernae -p password命令2:mysql -u username -p password -h 需要连接的mysql主机名(localhost本地主机名)或是mysql的ip地址(默认为:127.0.0.1)-P 端口号(默认:3306端口)使用其中任意一个就OK,输入命令后DOS命令框得到mysql>就说明已经进入了mysql系统2. 查看mysql当中的._mysql -u user
文章浏览阅读484次。一、lvs简介和推荐阅读的资料二、lvs和keepalived的安装三、LVS VS/DR模式搭建四、LVS VS/TUN模式搭建五、LVS VS/NAT模式搭建六、keepalived多种real server健康检测实例七、lvs持久性工作原理和配置八、lvs数据监控九、lvs+keepalived故障排除一、LVS简介和推荐阅读的资料 学习LVS+Keepalived必须阅读的三个文档。1、 《Keepalived权威指南》下载见http://..._this is the redundant configuration for lvs + keepalived server itself
文章浏览阅读795次,点赞20次,收藏15次。AIDL是使用bind机制来工作。java原生参数Stringparcelablelist & map 元素 需要支持AIDL其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。下图是我进阶学习所积累的历年腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。
文章浏览阅读248次。承接:数据基础02
文章浏览阅读2.8w次,点赞14次,收藏88次。文章目录1. 概念:Narrow Width Effect: 窄宽度效应Short Channel effects:短沟道效应阈值电压 (Threshold voltage)2. 阈值电压与沟道长和沟道宽的关系:Narrow channel 窄沟的分析Short channel 短沟的分析1. 概念:Narrow Width Effect: 窄宽度效应在CMOS器件工艺中,器件的阈值电压Vth 随着沟道宽度的变窄而增大,即窄宽度效应;目前,由于浅沟道隔离工艺的应用,器件的阈值电压 Vth 随着沟道宽度_短沟道效应