首页 > 编程语言 >为现有图像处理程序添加读写exif的功能

为现有图像处理程序添加读写exif的功能

时间:2022-12-24 10:01:40浏览次数:40  
标签:case exif 读写 unsigned char TAG 图像处理 exifinfo define

为现有图像处理程序添加读取exif的功能



exif是图片的重要参数,在使用过程中很关键的一点是exif的数据能够和图片一起存在。exif的相关功能在操作系统中就集成了,在csharp中也似乎有了实现。但是使用mfc来实现这个功能,的确费了我的一些时间。下面是我的实现方式。



读取exif,参考了网络资料



添加cexif.h和cexif.cpp,添加入现有程序



在需要读取的地方添加相关代码



 



FILE* hFile=fopen(FilePathName.c_str(),"rb");
if (hFile){
memset(&m_exifinfo,0,sizeof(EXIFINFO));
Cexif exif(&m_exifinfo);
exif.DecodeExif(hFile);
fclose(hFile);
if (m_exifinfo.IsExif)
{
string cameramaker = m_exifinfo.CopyRight;//获得CopyRight
vector<string> vecParams;
if ("@@" == cameramaker.substr(0,2)) //确认为带参数图片
{
cameramaker = cameramaker.substr(2,cameramaker.length()-2);
SplitString(cameramaker,vecParams,"|");//保存各参数到vecParams中去
//updateGuides给的是图像真实像素值
if (vecParams.size()<13)
return;
m_freal2screen = Str2RealPixF(vecParams[12]);//获得之前保存的比值
if (m_freal2screen<0)
return;
UpdateGuides(Str2RealPix(vecParams[0]),Str2RealPix(vecParams[1]),Str2RealPix(vecParams[2]),Str2RealPix(vecParams[3]),Str2RealPix(vecParams[4]),Str2RealPix(vecParams[5]),Str2RealPix(vecParams[6]),Str2RealPix(vecParams[7]),Str2RealPix(vecParams[8]),Str2RealPix(vecParams[9]),Str2RealPix(vecParams[10]),Str2RealPix(vecParams[11]));
}
}
else
MessageBox("没有找到矢量数据信息!","EXIF",MB_OK);
}
fclose(hFile);



  



 




为现有图像处理程序添加读写exif的功能_sed


但是这里的exif读取的信息不实很全


同时找到另一个代码,但是版本比较老,只能在vc6下面运行



为现有图像处理程序添加读写exif的功能_数据_02


这个时候,我需要考虑的就是写入的数据是否够长的问题。我进行了边界测试


经过测试,在这种模式下是没有问题的



为现有图像处理程序添加读写exif的功能_Data_03


对原有代码进行初步修改就可以。考虑到还是现有集成的比较好用,还是用集成好的。但是集成好的版本没有 版权这个段?这个如何办了?


反思一想,问题不就出现在位置信息吗?我将正确的版权信息覆盖掉make信息,问题解决。


最后提供我修改完成的带版权信息的exif.c。


解决问题的思路很重要。


附全部代码


/*
* File: exif.cpp
* Purpose: cpp EXIF reader
* 16/Mar/2003 <[email protected]>
* based on jhead-1.8 by Matthias Wandel <mwandel(at)rim(dot)net>
*/
#include "stdafx.h"
#include "Exif.h"

////
Cexif::Cexif(EXIFINFO* info)
{
if (info) {
m_exifinfo = info;
freeinfo = false;
} else {
m_exifinfo = new EXIFINFO;
memset(m_exifinfo,0,sizeof(EXIFINFO));
freeinfo = true;
}

m_szLastError[0]='\0';
ExifImageWidth = MotorolaOrder = 0;
SectionsRead=0;
memset(&Sections, 0, MAX_SECTIONS * sizeof(Section_t));
}
////
Cexif::~Cexif()
{
for(int i=0;i<MAX_SECTIONS;i++) if(Sections[i].Data) free(Sections[i].Data);
if (freeinfo) delete m_exifinfo;
}
////
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;
}
//--------------------------------------------------------------------------
// Get 16 bits motorola order (always) for jpeg header stuff.
//--------------------------------------------------------------------------
int Cexif::Get16m(void * Short)
{
return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1];
}
////
/*--------------------------------------------------------------------------
Convert a 16 bit unsigned value from file's native unsigned char order
--------------------------------------------------------------------------*/
int Cexif::Get16u(void * Short)
{
if (MotorolaOrder){
return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1];
}else{
return (((unsigned char *)Short)[1] << 8) | ((unsigned char *)Short)[0];
}
}
////
/*--------------------------------------------------------------------------
Convert a 32 bit signed value from file's native unsigned char order
--------------------------------------------------------------------------*/
long Cexif::Get32s(void * Long)
{
if (MotorolaOrder){
return ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16)
| (((unsigned char *)Long)[2] << 8 ) | (((unsigned char *)Long)[3] << 0 );
}else{
return ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16)
| (((unsigned char *)Long)[1] << 8 ) | (((unsigned char *)Long)[0] << 0 );
}
}
////
/*--------------------------------------------------------------------------
Convert a 32 bit unsigned value from file's native unsigned char order
--------------------------------------------------------------------------*/
unsigned long Cexif::Get32u(void * Long)
{
return (unsigned long)Get32s(Long) & 0xffffffff;
}
////

/* Describes format descriptor */
static const int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
#define NUM_FORMATS 12

#define FMT_BYTE 1
#define FMT_STRING 2
#define FMT_USHORT 3
#define FMT_ULONG 4
#define FMT_URATIONAL 5
#define FMT_SBYTE 6
#define FMT_UNDEFINED 7
#define FMT_SSHORT 8
#define FMT_SLONG 9
#define FMT_SRATIONAL 10
#define FMT_SINGLE 11
#define FMT_DOUBLE 12

/* Describes tag values */

#define TAG_EXIF_VERSION 0x9000
#define TAG_EXIF_OFFSET 0x8769
#define TAG_INTEROP_OFFSET 0xa005

//2016年11月25日15:55:46 修改TAG_MAKE
#define TAG_MAKE 0x010F
#define TAG_CP 0x8298
#define TAG_MODEL 0x0110

#define TAG_ORIENTATION 0x0112
#define TAG_XRESOLUTION 0x011A
#define TAG_YRESOLUTION 0x011B
#define TAG_RESOLUTIONUNIT 0x0128

#define TAG_EXPOSURETIME 0x829A
#define TAG_FNUMBER 0x829D

#define TAG_SHUTTERSPEED 0x9201
#define TAG_APERTURE 0x9202
#define TAG_BRIGHTNESS 0x9203
#define TAG_MAXAPERTURE 0x9205
#define TAG_FOCALLENGTH 0x920A

#define TAG_DATETIME_ORIGINAL 0x9003
#define TAG_USERCOMMENT 0x9286

#define TAG_SUBJECT_DISTANCE 0x9206
#define TAG_FLASH 0x9209

#define TAG_FOCALPLANEXRES 0xa20E
#define TAG_FOCALPLANEYRES 0xa20F
#define TAG_FOCALPLANEUNITS 0xa210
#define TAG_EXIF_IMAGEWIDTH 0xA002
#define TAG_EXIF_IMAGELENGTH 0xA003

/* the following is added 05-jan-2001 vcs */
#define TAG_EXPOSURE_BIAS 0x9204
#define TAG_WHITEBALANCE 0x9208
#define TAG_METERING_MODE 0x9207
#define TAG_EXPOSURE_PROGRAM 0x8822
#define TAG_ISO_EQUIVALENT 0x8827
#define TAG_COMPRESSION_LEVEL 0x9102

#define TAG_THUMBNAIL_OFFSET 0x0201
#define TAG_THUMBNAIL_LENGTH 0x0202


/*--------------------------------------------------------------------------
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_CP:
strncpy(m_exifinfo->CopyRight, (char*)ValuePtr,MAX_COMMENT-1);
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)*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.0)));
}
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;
}
////
/*--------------------------------------------------------------------------
Evaluate number, be it int, rational, or float from directory.
--------------------------------------------------------------------------*/
double Cexif::ConvertAnyFormat(void * ValuePtr, int Format)
{
double Value;
Value = 0;

switch(Format){
case FMT_SBYTE: Value = *(signed char *)ValuePtr; break;
case FMT_BYTE: Value = *(unsigned char *)ValuePtr; break;

case FMT_USHORT: Value = Get16u(ValuePtr); break;
case FMT_ULONG: Value = Get32u(ValuePtr); break;

case FMT_URATIONAL:
case FMT_SRATIONAL:
{
int Num,Den;
Num = Get32s(ValuePtr);
Den = Get32s(4+(char *)ValuePtr);
if (Den == 0){
Value = 0;
}else{
Value = (double)Num/Den;
}
break;
}

case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break;
case FMT_SLONG: Value = Get32s(ValuePtr); break;

/* Not sure if this is correct (never seen float used in Exif format)
*/
case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break;
case FMT_DOUBLE: Value = *(double *)ValuePtr; break;
}
return Value;
}
////
void Cexif::process_COM (const unsigned char * Data, int length)
{
int ch;
char Comment[MAX_COMMENT+1];
int nch;
int a;

nch = 0;

if (length > MAX_COMMENT) length = MAX_COMMENT; // Truncate if it won't fit in our structure.

for (a=2;a<length;a++){
ch = Data[a];

if (ch == '\r' && Data[a+1] == '\n') continue; // Remove cr followed by lf.

if ((ch>=0x20) || ch == '\n' || ch == '\t'){
Comment[nch++] = (char)ch;
}else{
Comment[nch++] = '?';
}
}

Comment[nch] = '\0'; // Null terminate

//if (ShowTags) printf("COM marker comment: %s\n",Comment);

strcpy(m_exifinfo->Comments,Comment);
}
////
void Cexif::process_SOFn (const unsigned char * Data, int marker)
{
int data_precision, num_components;

data_precision = Data[2];
m_exifinfo->Height = Get16m((void*)(Data+3));
m_exifinfo->Width = Get16m((void*)(Data+5));
num_components = Data[7];

if (num_components == 3){
m_exifinfo->IsColor = 1;
}else{
m_exifinfo->IsColor = 0;
}

m_exifinfo->Process = marker;

//if (ShowTags) printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n",
// ImageInfo.Width, ImageInfo.Height, num_components, data_precision);
}
////

//#include "stdafx.h"


/*
* File: exif.h
* Purpose: cpp EXIF reader
* 16/Mar/2003 <[email protected]>
* based on jhead-1.8 by Matthias Wandel <mwandel(at)rim(dot)net>
*/
//2016年11月25日 jsxyhelu 修改添加版权信息
#if !defined(__exif_h)
#define __exif_h

#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <malloc.h>

#define MAX_COMMENT 65535
#define MAX_SECTIONS 20


typedef struct tag_ExifInfo {
char Version [5];
char CameraMake [32];
char CameraModel [40];
char DateTime [20];
char CopyRight [MAX_COMMENT];
int Height, Width;
int Orientation;
int IsColor;
int Process;
int FlashUsed;
float FocalLength;
float ExposureTime;
float ApertureFNumber;
float Distance;
float CCDWidth;
float ExposureBias;
int Whitebalance;
int MeteringMode;
int ExposureProgram;
int ISOequivalent;
int CompressionLevel;
float FocalplaneXRes;
float FocalplaneYRes;
float FocalplaneUnits;
float Xresolution;
float Yresolution;
float ResolutionUnit;
float Brightness;
char Comments[MAX_COMMENT];

unsigned char * ThumbnailPointer; /* Pointer at the thumbnail */
unsigned ThumbnailSize; /* Size of thumbnail. */

bool IsExif;
} EXIFINFO;

//--------------------------------------------------------------------------
// JPEG markers consist of one or more 0xFF unsigned chars, followed by a marker
// code unsigned char (which is not an FF). Here are the marker codes of interest
// in this program. (See jdmarker.c for a more complete list.)
//--------------------------------------------------------------------------

#define M_SOF0 0xC0 // Start Of Frame N
#define M_SOF1 0xC1 // N indicates which compression process
#define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use
#define M_SOF3 0xC3
#define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers
#define M_SOF6 0xC6
#define M_SOF7 0xC7
#define M_SOF9 0xC9
#define M_SOF10 0xCA
#define M_SOF11 0xCB
#define M_SOF13 0xCD
#define M_SOF14 0xCE
#define M_SOF15 0xCF
#define M_SOI 0xD8 // Start Of Image (beginning of datastream)
#define M_EOI 0xD9 // End Of Image (end of datastream)
#define M_SOS 0xDA // Start Of Scan (begins compressed data)
#define M_JFIF 0xE0 // Jfif marker
#define M_EXIF 0xE1 // Exif marker
#define M_COM 0xFE // COMment

class Cexif
{

typedef struct tag_Section_t{
unsigned char* Data;
int Type;
unsigned Size;
} Section_t;

public:
EXIFINFO* m_exifinfo;
char m_szLastError[256];
Cexif(EXIFINFO* info = NULL);
~Cexif();
bool DecodeExif(FILE* hFile);
protected:
bool process_EXIF(unsigned char * CharBuf, unsigned int length);
void process_COM (const unsigned char * Data, int length);
void process_SOFn (const unsigned char * Data, int marker);
int Get16u(void * Short);
int Get16m(void * Short);
long Get32s(void * Long);
unsigned long Get32u(void * Long);
double ConvertAnyFormat(void * ValuePtr, int Format);
bool ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength,
EXIFINFO * const pInfo, unsigned char ** const LastExifRefdP);
int ExifImageWidth;
int MotorolaOrder;
Section_t Sections[MAX_SECTIONS];
int SectionsRead;
bool freeinfo;
};

#endif


 


为现有图像处理程序添加读取exif的功能


exif是图片的重要参数,在使用过程中很关键的一点是exif的数据能够和图片一起存在。exif的相关功能在操作系统中就集成了,在csharp中也似乎有了实现。但是使用mfc来实现这个功能,的确费了我的一些时间。下面是我的实现方式。


读取exif,参考了网络资料


添加cexif.h和cexif.cpp,添加入现有程序


在需要读取的地方添加相关代码


 


FILE* hFile=fopen(FilePathName.c_str(),"rb");
if (hFile){
memset(&m_exifinfo,0,sizeof(EXIFINFO));
Cexif exif(&m_exifinfo);
exif.DecodeExif(hFile);
fclose(hFile);
if (m_exifinfo.IsExif)
{
string cameramaker = m_exifinfo.CopyRight;//获得CopyRight
vector<string> vecParams;
if ("@@" == cameramaker.substr(0,2)) //确认为带参数图片
{
cameramaker = cameramaker.substr(2,cameramaker.length()-2);
SplitString(cameramaker,vecParams,"|");//保存各参数到vecParams中去
//updateGuides给的是图像真实像素值
if (vecParams.size()<13)
return;
m_freal2screen = Str2RealPixF(vecParams[12]);//获得之前保存的比值
if (m_freal2screen<0)
return;
UpdateGuides(Str2RealPix(vecParams[0]),Str2RealPix(vecParams[1]),Str2RealPix(vecParams[2]),Str2RealPix(vecParams[3]),Str2RealPix(vecParams[4]),Str2RealPix(vecParams[5]),Str2RealPix(vecParams[6]),Str2RealPix(vecParams[7]),Str2RealPix(vecParams[8]),Str2RealPix(vecParams[9]),Str2RealPix(vecParams[10]),Str2RealPix(vecParams[11]));
}
}
else
MessageBox("没有找到矢量数据信息!","EXIF",MB_OK);
}
fclose(hFile);


  


 



为现有图像处理程序添加读写exif的功能_sed


但是这里的exif读取的信息不实很全


同时找到另一个代码,但是版本比较老,只能在vc6下面运行



为现有图像处理程序添加读写exif的功能_数据_02


这个时候,我需要考虑的就是写入的数据是否够长的问题。我进行了边界测试


经过测试,在这种模式下是没有问题的



为现有图像处理程序添加读写exif的功能_Data_03


对原有代码进行初步修改就可以。考虑到还是现有集成的比较好用,还是用集成好的。但是集成好的版本没有 版权这个段?这个如何办了?


反思一想,问题不就出现在位置信息吗?我将正确的版权信息覆盖掉make信息,问题解决。


最后提供我修改完成的带版权信息的exif.c。


解决问题的思路很重要。


附全部代码


/*
* File: exif.cpp
* Purpose: cpp EXIF reader
* 16/Mar/2003 <[email protected]>
* based on jhead-1.8 by Matthias Wandel <mwandel(at)rim(dot)net>
*/
#include "stdafx.h"
#include "Exif.h"

////
Cexif::Cexif(EXIFINFO* info)
{
if (info) {
m_exifinfo = info;
freeinfo = false;
} else {
m_exifinfo = new EXIFINFO;
memset(m_exifinfo,0,sizeof(EXIFINFO));
freeinfo = true;
}

m_szLastError[0]='\0';
ExifImageWidth = MotorolaOrder = 0;
SectionsRead=0;
memset(&Sections, 0, MAX_SECTIONS * sizeof(Section_t));
}
////
Cexif::~Cexif()
{
for(int i=0;i<MAX_SECTIONS;i++) if(Sections[i].Data) free(Sections[i].Data);
if (freeinfo) delete m_exifinfo;
}
////
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;
}
//--------------------------------------------------------------------------
// Get 16 bits motorola order (always) for jpeg header stuff.
//--------------------------------------------------------------------------
int Cexif::Get16m(void * Short)
{
return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1];
}
////
/*--------------------------------------------------------------------------
Convert a 16 bit unsigned value from file's native unsigned char order
--------------------------------------------------------------------------*/
int Cexif::Get16u(void * Short)
{
if (MotorolaOrder){
return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1];
}else{
return (((unsigned char *)Short)[1] << 8) | ((unsigned char *)Short)[0];
}
}
////
/*--------------------------------------------------------------------------
Convert a 32 bit signed value from file's native unsigned char order
--------------------------------------------------------------------------*/
long Cexif::Get32s(void * Long)
{
if (MotorolaOrder){
return ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16)
| (((unsigned char *)Long)[2] << 8 ) | (((unsigned char *)Long)[3] << 0 );
}else{
return ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16)
| (((unsigned char *)Long)[1] << 8 ) | (((unsigned char *)Long)[0] << 0 );
}
}
////
/*--------------------------------------------------------------------------
Convert a 32 bit unsigned value from file's native unsigned char order
--------------------------------------------------------------------------*/
unsigned long Cexif::Get32u(void * Long)
{
return (unsigned long)Get32s(Long) & 0xffffffff;
}
////

/* Describes format descriptor */
static const int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
#define NUM_FORMATS 12

#define FMT_BYTE 1
#define FMT_STRING 2
#define FMT_USHORT 3
#define FMT_ULONG 4
#define FMT_URATIONAL 5
#define FMT_SBYTE 6
#define FMT_UNDEFINED 7
#define FMT_SSHORT 8
#define FMT_SLONG 9
#define FMT_SRATIONAL 10
#define FMT_SINGLE 11
#define FMT_DOUBLE 12

/* Describes tag values */

#define TAG_EXIF_VERSION 0x9000
#define TAG_EXIF_OFFSET 0x8769
#define TAG_INTEROP_OFFSET 0xa005

//2016年11月25日15:55:46 修改TAG_MAKE
#define TAG_MAKE 0x010F
#define TAG_CP 0x8298
#define TAG_MODEL 0x0110

#define TAG_ORIENTATION 0x0112
#define TAG_XRESOLUTION 0x011A
#define TAG_YRESOLUTION 0x011B
#define TAG_RESOLUTIONUNIT 0x0128

#define TAG_EXPOSURETIME 0x829A
#define TAG_FNUMBER 0x829D

#define TAG_SHUTTERSPEED 0x9201
#define TAG_APERTURE 0x9202
#define TAG_BRIGHTNESS 0x9203
#define TAG_MAXAPERTURE 0x9205
#define TAG_FOCALLENGTH 0x920A

#define TAG_DATETIME_ORIGINAL 0x9003
#define TAG_USERCOMMENT 0x9286

#define TAG_SUBJECT_DISTANCE 0x9206
#define TAG_FLASH 0x9209

#define TAG_FOCALPLANEXRES 0xa20E
#define TAG_FOCALPLANEYRES 0xa20F
#define TAG_FOCALPLANEUNITS 0xa210
#define TAG_EXIF_IMAGEWIDTH 0xA002
#define TAG_EXIF_IMAGELENGTH 0xA003

/* the following is added 05-jan-2001 vcs */
#define TAG_EXPOSURE_BIAS 0x9204
#define TAG_WHITEBALANCE 0x9208
#define TAG_METERING_MODE 0x9207
#define TAG_EXPOSURE_PROGRAM 0x8822
#define TAG_ISO_EQUIVALENT 0x8827
#define TAG_COMPRESSION_LEVEL 0x9102

#define TAG_THUMBNAIL_OFFSET 0x0201
#define TAG_THUMBNAIL_LENGTH 0x0202


/*--------------------------------------------------------------------------
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_CP:
strncpy(m_exifinfo->CopyRight, (char*)ValuePtr,MAX_COMMENT-1);
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)*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.0)));
}
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;
}
////
/*--------------------------------------------------------------------------
Evaluate number, be it int, rational, or float from directory.
--------------------------------------------------------------------------*/
double Cexif::ConvertAnyFormat(void * ValuePtr, int Format)
{
double Value;
Value = 0;

switch(Format){
case FMT_SBYTE: Value = *(signed char *)ValuePtr; break;
case FMT_BYTE: Value = *(unsigned char *)ValuePtr; break;

case FMT_USHORT: Value = Get16u(ValuePtr); break;
case FMT_ULONG: Value = Get32u(ValuePtr); break;

case FMT_URATIONAL:
case FMT_SRATIONAL:
{
int Num,Den;
Num = Get32s(ValuePtr);
Den = Get32s(4+(char *)ValuePtr);
if (Den == 0){
Value = 0;
}else{
Value = (double)Num/Den;
}
break;
}

case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break;
case FMT_SLONG: Value = Get32s(ValuePtr); break;

/* Not sure if this is correct (never seen float used in Exif format)
*/
case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break;
case FMT_DOUBLE: Value = *(double *)ValuePtr; break;
}
return Value;
}
////
void Cexif::process_COM (const unsigned char * Data, int length)
{
int ch;
char Comment[MAX_COMMENT+1];
int nch;
int a;

nch = 0;

if (length > MAX_COMMENT) length = MAX_COMMENT; // Truncate if it won't fit in our structure.

for (a=2;a<length;a++){
ch = Data[a];

if (ch == '\r' && Data[a+1] == '\n') continue; // Remove cr followed by lf.

if ((ch>=0x20) || ch == '\n' || ch == '\t'){
Comment[nch++] = (char)ch;
}else{
Comment[nch++] = '?';
}
}

Comment[nch] = '\0'; // Null terminate

//if (ShowTags) printf("COM marker comment: %s\n",Comment);

strcpy(m_exifinfo->Comments,Comment);
}
////
void Cexif::process_SOFn (const unsigned char * Data, int marker)
{
int data_precision, num_components;

data_precision = Data[2];
m_exifinfo->Height = Get16m((void*)(Data+3));
m_exifinfo->Width = Get16m((void*)(Data+5));
num_components = Data[7];

if (num_components == 3){
m_exifinfo->IsColor = 1;
}else{
m_exifinfo->IsColor = 0;
}

m_exifinfo->Process = marker;

//if (ShowTags) printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n",
// ImageInfo.Width, ImageInfo.Height, num_components, data_precision);
}
////

//#include "stdafx.h"


/*
* File: exif.h
* Purpose: cpp EXIF reader
* 16/Mar/2003 <[email protected]>
* based on jhead-1.8 by Matthias Wandel <mwandel(at)rim(dot)net>
*/
//2016年11月25日 jsxyhelu 修改添加版权信息
#if !defined(__exif_h)
#define __exif_h

#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <malloc.h>

#define MAX_COMMENT 65535
#define MAX_SECTIONS 20


typedef struct tag_ExifInfo {
char Version [5];
char CameraMake [32];
char CameraModel [40];
char DateTime [20];
char CopyRight [MAX_COMMENT];
int Height, Width;
int Orientation;
int IsColor;
int Process;
int FlashUsed;
float FocalLength;
float ExposureTime;
float ApertureFNumber;
float Distance;
float CCDWidth;
float ExposureBias;
int Whitebalance;
int MeteringMode;
int ExposureProgram;
int ISOequivalent;
int CompressionLevel;
float FocalplaneXRes;
float FocalplaneYRes;
float FocalplaneUnits;
float Xresolution;
float Yresolution;
float ResolutionUnit;
float Brightness;
char Comments[MAX_COMMENT];

unsigned char * ThumbnailPointer; /* Pointer at the thumbnail */
unsigned ThumbnailSize; /* Size of thumbnail. */

bool IsExif;
} EXIFINFO;

//--------------------------------------------------------------------------
// JPEG markers consist of one or more 0xFF unsigned chars, followed by a marker
// code unsigned char (which is not an FF). Here are the marker codes of interest
// in this program. (See jdmarker.c for a more complete list.)
//--------------------------------------------------------------------------

#define M_SOF0 0xC0 // Start Of Frame N
#define M_SOF1 0xC1 // N indicates which compression process
#define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use
#define M_SOF3 0xC3
#define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers
#define M_SOF6 0xC6
#define M_SOF7 0xC7
#define M_SOF9 0xC9
#define M_SOF10 0xCA
#define M_SOF11 0xCB
#define M_SOF13 0xCD
#define M_SOF14 0xCE
#define M_SOF15 0xCF
#define M_SOI 0xD8 // Start Of Image (beginning of datastream)
#define M_EOI 0xD9 // End Of Image (end of datastream)
#define M_SOS 0xDA // Start Of Scan (begins compressed data)
#define M_JFIF 0xE0 // Jfif marker
#define M_EXIF 0xE1 // Exif marker
#define M_COM 0xFE // COMment

class Cexif
{

typedef struct tag_Section_t{
unsigned char* Data;
int Type;
unsigned Size;
} Section_t;

public:
EXIFINFO* m_exifinfo;
char m_szLastError[256];
Cexif(EXIFINFO* info = NULL);
~Cexif();
bool DecodeExif(FILE* hFile);
protected:
bool process_EXIF(unsigned char * CharBuf, unsigned int length);
void process_COM (const unsigned char * Data, int length);
void process_SOFn (const unsigned char * Data, int marker);
int Get16u(void * Short);
int Get16m(void * Short);
long Get32s(void * Long);
unsigned long Get32u(void * Long);
double ConvertAnyFormat(void * ValuePtr, int Format);
bool ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength,
EXIFINFO * const pInfo, unsigned char ** const LastExifRefdP);
int ExifImageWidth;
int MotorolaOrder;
Section_t Sections[MAX_SECTIONS];
int SectionsRead;
bool freeinfo;
};

#endif


 

标签:case,exif,读写,unsigned,char,TAG,图像处理,exifinfo,define
From: https://blog.51cto.com/jsxyhelu2017/5967070

相关文章

  • C++读写文本文件
    std::stringreadText(std::string&filename){std::stringshaderCodeStr("");std::ifstreamshaderFile;shaderFile.exceptions(std::ifstream::failb......
  • java处理excel文件的读写
    简述1、一般会将文件地址作为入参,对文件进行处理2、将文件放到File中:Filefile=newFile(fileName)3、判断文件是否存在:if(!file.exists()){returnnull;}4、将文件......
  • VC 读写Excel (第三方类CSpreadSheet)
    1. 用VC6新建一个基于对话框的项目;2. 添加 CSpreadSheet.h,CSpreadSheet.cpp到项目中;3. 在C*Dlg.h 中添加 : #include "CSpreadSheet.h"4. 添加对应的读写函数5. 读......
  • GOCVHelper图像处理算法库实例整编
       GOCVHelper主要包含图像处理、图像增强和基础文件处理三个部分。由于前两个部分较具有通用性,而且我在不同项目中都进行了反复使用,为了进一步说明类库内容,这里反过来......
  • 图像处理的云实验
    一直以来,我都在思考,如何将图像处理和手机等移动终端结合起来。结合起来的方法,大体应该说是两类,一类就是直接在android手机上写native的程序,但是由于工具链的搭建比较复杂,再......
  • 《DFZU2EG_4EV MPSoc之FPGA开发指南》第二十七章 MDIO接口读写测试实验​
    MDIO接口读写测试实验​在以太网通信中,设备之间的物理层链路均由PHY芯片(物理层芯片,本文指YT8521)建立。PHY芯片有一个配置接口,即MDIO接口,可以配置PHY芯片的工作模式以及获取P......
  • GOCVHelper图像处理算法库
      GOCVHelper(GreenOpenComputerVersionHelper)是我在这几年编写图像处理程序的过程中积累下来的函数库。主要是对Opencv的适当扩展和在实现Mfc程序时候的功能增......
  • 百倍加速IO读写!快使用Parquet和Feather格式!⛵
    ......
  • python 文件读写
    1.1文件夹与文件路径d:\python\1.py路径是:d:\python文件是:1.py1.1.1绝对路径与相对路径绝对路径:从根目录开始的路径相对路径:从当前工作目录开始的路径相对路......
  • 百倍加速IO读写!快使用Parquet和Feather格式!⛵
    ......