技术标签: 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;
}
文章浏览阅读198次。好消息:计算机操作员(工种代码:46-207)被确定为2011年深圳市职业技能鉴定计算机类鉴定工种学习对象:Office2003综合应用:1、向有一定电脑基础,特别是对OFFICE办公软件有一定了解,欲从事计算机日常办公的人员进行培训.2、此科目是深圳市招调工种.图形图像处理CorelDraw X3:1、从事或有意从事工艺美术、广告艺术、图文排版、图文印刷、计算机多媒体技术工作人员以及其他需要掌握..._计算机操作员职业代码
文章浏览阅读7.5k次,点赞6次,收藏47次。基于百度文心一言语言大模型的智能文本对话AI机器人API,支持聊天对话、行业咨询、语言学习、代码编写等功能.您的AppKey和uid是重要信息,请务必妥善保存,避免泄漏!您的AppKey和uid是重要信息,请务必妥善保存,避免泄漏!您的AppKey和uid是重要信息,请务必妥善保存,避免泄漏!AppKey申请通过后,登录。请求方式: POST。_文言一心api
文章浏览阅读488次。前言在每个公司的系统中,总有一些拥有复杂业务逻辑的系统,这些系统承载着核心业务逻辑,几乎每个需求都和这些核心业务有关,这些核心业务业务逻辑冗长,涉及内部逻辑运算,缓存操作,持久化操作,外部..._什么业务场景要用到编排工具
文章浏览阅读297次。题目描述若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。例如:给定一个十进制数5656,将5656加6565(即把5656从右向左读),得到121121是一个回文数。又如:对于十进制数8787:STEP1:8787+7878=165165STEP2:165165+561561=726726STEP3:726726+627627=13531..._1、若一个5位数字从左向右读与从右向左读都一样,我们就将其称之为回文串。小申编
文章浏览阅读389次。[font=courier new]86. xdrx_getinters功能:1.求两个AcDbCurve(曲线)实体的交点.2.求一个AcDbCurve(曲线)实体和一个选择集中所有AcDbCurve(曲线)的交点。3.求一个选择集中所有AcDbCurve(曲线)实体的交点.4.求一个选择集SS1中的所有AcDbCurve实体和另个选择集SS2所有AcDbCurve实体的交点。调用格式: 1. ..._lisp inters
文章浏览阅读44次。Problem DescriptionBenny has a spacious farm land to irrigate. The farm land is a rectangle, and is divided into a lot of samll squares. Water pipes are placed in these squares. Different square has...
文章浏览阅读145次。官网文档: http://axis.apache.org/axis2/c/core/docs/axis2c_manual.html从文档中可以总结出:1. Axis2/C是一个用C语言实现的Web Service引擎。Axis2/C基于Axis2架构,支持SOAP1.1和SOAP1.2协议,并且支持RESTful风格的Web Service。基于Axis2/C的Web Service可以..._axis2/c服务端调用axis2_get_instance
文章浏览阅读3k次。目前主要的两种架构方法(准确的说是方法论),具体的方法也是有的,也有可实际操作层面的东西,那要看很多的各个细分专业层面的东西。比如画流程图,业务流程图、数据流程图、系统交互流程图等等。togafzachmanzachman业务建模分析框架,相比于togaf,直观上直接提供了可操作的东西,可能大家更容易接受一些。这里推荐一个架构设计的专业工具,是免费的,即ArchMateArchi – Open Source ArchiMate Modelling (archim..._企业架构方法论
文章浏览阅读123次。堆栈与队列具体的方法区分_判断是栈还是队列还是优先队列
文章浏览阅读352次,点赞8次,收藏8次。小爱老师可以购买两份双拼花束后,将他重新组合成一束百合花+一束郁金香。已知布置会场需要用到x束百合花与y束郁金香,请问小爱老师购买花朵最少花费需多少元?输出共一行,一个正整数,表示小爱老师购买花朵最少花费需多少元。直接购买8束百合+6束郁金香,共计8*8+6*10=124元。内存限制: 256 Mb时间限制: 1000 ms。先购买12束双拼花朵,花费12*8=96元,第一行:两个正整数表示需要的花束数量x,y。第二行:三个正整数表示花束费用a,b,c。再购买2束百合花,花费2*8=16元,
文章浏览阅读518次。使用Python方法比用各种命令方便,可以设置超时时间,到底通不通,端口是否开放一眼能看出来。命令和返回完整权限,可以ping通,端口开放,结果如下:无root权限(省略了ping),端口开放,结果如下:完整权限,可以ping通,远端端口关闭,结果如下:完整权限,可以ping通,本地端口关闭,结果如下:完整权限,不能ping通(端口自然也无法访问),结果如下:pnp.py代码#!/usr/bin/..._python ping ip无管理员权限
文章浏览阅读738次。零极点与系统稳定性的关系 4.状态方程含义 5.使用 zplane 函数 [实验原理] 该实验用 MATLAB 中库函数,如 tf2zp(b,a),ss2zp(A,B,C,D),zplane(z,p),......MATLAB 中相关命令 aa abs 绝对值、模、字符的 ascii 码值 a...零极点与系统稳定性的关系 4.状态方程含义 5.使用 zplane 函数 [实验原理] 该实验用 M..._matlabcla。m文件