zoukankan      html  css  js  c++  java
  • 为现有图像处理程序添加读写exif的功能

    为现有图像处理程序添加读取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读取的信息不实很全
    同时找到另一个代码,但是版本比较老,只能在vc6下面运行
    这个时候,我需要考虑的就是写入的数据是否够长的问题。我进行了边界测试
    经过测试,在这种模式下是没有问题的
    对原有代码进行初步修改就可以。考虑到还是现有集成的比较好用,还是用集成好的。但是集成好的版本没有 版权这个段?这个如何办了?
    反思一想,问题不就出现在位置信息吗?我将正确的版权信息覆盖掉make信息,问题解决。
    最后提供我修改完成的带版权信息的exif.c。
    解决问题的思路很重要。

    附全部代码

    /*
     * File:    exif.cpp
     * Purpose:    cpp EXIF reader
     * 16/Mar/2003 <ing.davide.pizzolato@libero.it>
     * 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]='';
        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
    ");
                    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!
    ");
                    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
    ",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] = '';  /* Initial value - null string */
    
        ExifImageWidth = 0;
    
        {   /* Check the EXIF header component */
            static const unsigned char ExifHeader[] = "Exif";
            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] = '';
                        }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 != '' && 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 == '
    ' && Data[a+1] == '
    ') continue; // Remove cr followed by lf.
    
            if ((ch>=0x20) || ch == '
    ' || ch == '	'){
                Comment[nch++] = (char)ch;
            }else{
                Comment[nch++] = '?';
            }
        }
    
        Comment[nch] = ''; // Null terminate
    
        //if (ShowTags) printf("COM marker comment: %s
    ",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
    ",
        //               ImageInfo.Width, ImageInfo.Height, num_components, data_precision);
    }
    ////////////////////////////////////////////////////////////////////////////////
    
    //#include "stdafx.h"
    /*
     * File:    exif.h
     * Purpose:    cpp EXIF reader
     * 16/Mar/2003 <ing.davide.pizzolato@libero.it>
     * 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
  • 相关阅读:
    关于yyyy-MM-dd格式日期字符串,解析成LocalDateTime遇到的问题
    idea设置代码提示不区分大小写
    不错的Django技术网址
    Django-Rest-Framework 教程: 快速入门
    Djanto static静态文件配置
    Html5 touch event
    Zepto.js touch模块深入分析
    Python单元测试框架之pytest -- fixtures
    Python:高级主题之(属性取值和赋值过程、属性描述符、装饰器)
    Nginx基本配置、性能优化指南
  • 原文地址:https://www.cnblogs.com/jsxyhelu/p/6108138.html
Copyright © 2011-2022 走看看