android jpeg 이미지 해석 과정

38615 단어 skia그림 처리
JPEG 이미지 분석 프로세스JPEG의 메이커를 해석하는데 EXIF는 그 중의 한 메이커이다.다음에 exif를 해석합니다.
1.
1.main.c
static int loadExifInfo(const char* FileName, int readJPG) {
#ifdef SUPERDEBUG
    ALOGE("loadExifInfo");
#endif
    int Modified = FALSE;
    ReadMode_t ReadMode = READ_METADATA;
    if (readJPG) {
        // Must add READ_IMAGE else we can't write the JPG back out.
        ReadMode |= READ_IMAGE;
    }

#ifdef SUPERDEBUG
    ALOGE("ResetJpgfile");
#endif
    ResetJpgfile();//   0

    // Start with an empty image information structure.
    memset(&ImageInfo, 0, sizeof(ImageInfo));//  ImageInfo
    ImageInfo.FlashUsed = -1;
    ImageInfo.MeteringMode = -1;
    ImageInfo.Whitebalance = -1;

    // Store file date/time.
    {
        struct stat st;
        if (stat(FileName, &st) >= 0) {
            ImageInfo.FileDateTime = st.st_mtime;
            ImageInfo.FileSize = st.st_size;
        }
    }

    strncpy(ImageInfo.FileName, FileName, PATH_MAX);
#ifdef SUPERDEBUG
    ALOGE("ReadJpegFile");
#endif
    return ReadJpegFile(FileName, ReadMode);
}

2.jpgfile.c 파일에서 ImageInfo 읽기
//Storage for simplified info extracted from file.
ImageInfo_t ImageInfo;
//--------------------------------------------------------------------------
// This structure stores Exif header image elements in a simple manner
// Used to store camera data as extracted from the various ways that it can be
// stored in an exif header
typedef struct {
    char  FileName     [PATH_MAX+1];
    time_t FileDateTime;
    unsigned FileSize;
    char  CameraMake   [32];
    char  CameraModel  [40];
    char  DateTime     [20];
    char  DigitizedTime[20];
    // Fractions of seconds for DateTime tag, with milisecond precision.
    char  SubSecTime[SUB_SEC_SIZE];
    // Fractions of seconds for DateTimeOriginal tag, with milisecond precision.
    char  SubSecTimeOrig[SUB_SEC_SIZE];
    // Fractions of seconds for DateTimeDigitized tag, with milisecond precision.
    char  SubSecTimeDig[SUB_SEC_SIZE];
    int   Height, Width;
    int   Orientation;
    int   IsColor;
    int   Process;
    int   FlashUsed;
    rat_t FocalLength;
    float ExposureTime;
    float ApertureFNumber;
    float Distance;
    float CCDWidth;
    float ExposureBias;
    float DigitalZoomRatio;
    int   FocalLength35mmEquiv; // Exif 2.2 tag - usually not present.
    int   Whitebalance;
    int   MeteringMode;
    int   ExposureProgram;
    int   ExposureMode;
    int   ISOequivalent;
    int   LightSource;
    int   DistanceRange;

    char  Comments[MAX_COMMENT_SIZE];
    int   CommentWidchars; // If nonzer, widechar comment, indicates number of chars.

    unsigned ThumbnailOffset;          // Exif offset to thumbnail
    unsigned ThumbnailSize;            // Size of thumbnail.
    unsigned LargestExifOffset;        // Last exif data referenced (to check if thumbnail is at end)

    char  ThumbnailAtEnd;              // Exif header ends with the thumbnail
                                       // (we can only modify the thumbnail if its at the end)
    int   ThumbnailSizeOffset;

    int  DateTimeOffsets[MAX_DATE_COPIES];
    int  numDateTimeTags;

    int GpsInfoPresent;
    char GpsLat[31];
    char GpsLatRaw[MAX_BUF_SIZE];
    char GpsLatRef[2];
    char GpsLong[31];
    char GpsLongRaw[MAX_BUF_SIZE];
    char GpsLongRef[2];
    char GpsAlt[20];
    rat_t GpsAltRaw;
    char GpsAltRef;
    // gps-datestamp is 11 bytes ascii in EXIF 2.2
    char GpsDateStamp[11];
    char GpsTimeStamp[11];
    char GpsProcessingMethod[GPS_PROCESSING_METHOD_LEN + 1];
}ImageInfo_t;

3. JPEG의 메이커를 해석한다. EXIF는 그 중의 한 메이커이다.다음에 exif에 대한 해석
//--------------------------------------------------------------------------
// JPEG markers consist of one or more 0xFF bytes, followed by a marker
// code byte (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.  Also used for XMP data!
#define M_XMP   0x10E1        // Not a real tag (same value in file as Exif!)
#define M_COM   0xFE          // COMment
#define M_DQT   0xDB
#define M_DHT   0xC4
#define M_DRI   0xDD
#define M_IPTC  0xED          // IPTC marker

4.ReadJpegFile, main.c
//--------------------------------------------------------------------------
// Read image data.
//--------------------------------------------------------------------------
int ReadJpegFile(const char * FileName, ReadMode_t ReadMode)
{
    FILE * infile;
    int ret;

    infile = fopen(FileName, "rb"); // Unix ignores 'b', windows needs it.

    if (infile == NULL) {
        ALOGE("can't open '%s'", FileName);
        fprintf(stderr, "can't open '%s'
", FileName); return FALSE; } // Scan the JPEG headers. printf("ReadJpegSections"); ret = ReadJpegSections(infile, ReadMode);//ReadJpegSections(infile, ReadMode) if (!ret){ ALOGV("Cannot parse JPEG sections for file: %s", FileName); fprintf(stderr,"Not JPEG: %s
",FileName); } fclose(infile); if (ret == FALSE){ DiscardData(); } return ret; }

5.ReadJpegSections ,jpgfile.c, Parse the marker stream
//--------------------------------------------------------------------------
// Parse the marker stream until SOS or EOI is seen;
//--------------------------------------------------------------------------
int ReadJpegSections (FILE * infile, ReadMode_t ReadMode)
{
    int a;
    int HaveCom = FALSE;

    a = fgetc(infile);

    if (a != 0xff || fgetc(infile) != M_SOI){
        return FALSE;
    }
    for(;;){
        int itemlen;
        int marker = 0;
        int ll,lh, got;
        uchar * Data;

        CheckSectionsAllocated();

        for (a=0;a<=16;a++){
            marker = fgetc(infile);
            if (marker != 0xff) break;

            if (a >= 16){
                fprintf(stderr,"too many padding bytes
"); return FALSE; } } Sections[SectionsRead].Type = marker; Sections[SectionsRead].Offset = ftell(infile); // Read the length of the section. lh = fgetc(infile); ll = fgetc(infile); itemlen = (lh << 8) | ll; if (itemlen < 2){ // ErrFatal("invalid marker"); ALOGE("invalid marker"); return FALSE; } Sections[SectionsRead].Size = itemlen; Data = (uchar *)malloc(itemlen); if (Data == NULL){ // ErrFatal("Could not allocate memory"); ALOGE("Could not allocate memory"); return 0; } Sections[SectionsRead].Data = Data; // Store first two pre-read bytes. Data[0] = (uchar)lh; Data[1] = (uchar)ll; got = fread(Data+2, 1, itemlen-2, infile); // Read the whole section. if (got != itemlen-2){ // ErrFatal("Premature end of file?"); ALOGE("Premature end of file?"); return FALSE; } SectionsRead += 1; printf("reading marker %d", marker); 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){ // ErrFatal("could not allocate data for entire image"); ALOGE("could not allocate data for entire image"); return FALSE; } got = fread(Data, 1, size, infile); if (got != size){ // ErrFatal("could not read the rest of the image"); ALOGE("could not read the rest of the image"); return FALSE; } CheckSectionsAllocated(); Sections[SectionsRead].Data = Data; Sections[SectionsRead].Offset = cp; Sections[SectionsRead].Size = size; Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER; SectionsRead ++; HaveAll = 1; } return TRUE; case M_EOI: // in case it's a tables-only JPEG stream fprintf(stderr,"No image in jpeg!
"); return FALSE; case M_COM: // Comment section if (HaveCom || ((ReadMode & READ_METADATA) == 0)){ // Discard this section. free(Sections[--SectionsRead].Data); }else{ process_COM(Data, itemlen); HaveCom = TRUE; } 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); break; case M_EXIF: // There can be different section using the same marker. if (ReadMode & READ_METADATA){ if (memcmp(Data+2, "Exif", 4) == 0){ process_EXIF(Data, itemlen);// process_EXIF(Data, itemlen) break; }else if (memcmp(Data+2, "http:", 5) == 0){ Sections[SectionsRead-1].Type = M_XMP; // Change tag for internal purposes. if (ShowTags){ printf("Image cotains XMP section, %d bytes long
", itemlen); if (ShowTags){ ShowXmp(Sections[SectionsRead-1]); } } break; } } // Oterwise, discard this section. free(Sections[--SectionsRead].Data); break; case M_IPTC: if (ReadMode & READ_METADATA){ if (ShowTags){ printf("Image cotains IPTC section, %d bytes long
", itemlen); } // Note: We just store the IPTC section. Its relatively straightforward // and we don't act on any part of it, so just display it at parse time. }else{ free(Sections[--SectionsRead].Data); } 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 TRUE; }

6.Process a EXIF marker, exif.c
//--------------------------------------------------------------------------
// Process a EXIF marker
// Describes all the drivel that most digital cameras include...
//--------------------------------------------------------------------------
void process_EXIF (unsigned char * ExifSection, unsigned int length)
{
    int FirstOffset;

    FocalplaneXRes = 0;
    FocalplaneUnits = 0;
    ExifImageWidth = 0;
    NumOrientations = 0;

    if (ShowTags){
        printf("Exif header %d bytes long
",length); } { // Check the EXIF header component static uchar ExifHeader[] = "Exif\0\0"; if (memcmp(ExifSection+2, ExifHeader,6)){ ErrNonfatal("Incorrect Exif header",0,0); return; } } if (memcmp(ExifSection+8,"II",2) == 0){ if (ShowTags) printf("Exif section in Intel order
"); MotorolaOrder = 0; }else{ if (memcmp(ExifSection+8,"MM",2) == 0){ if (ShowTags) printf("Exif section in Motorola order
"); MotorolaOrder = 1; }else{ ErrNonfatal("Invalid Exif alignment marker.",0,0); return; } } // Check the next value for correctness. if (Get16u(ExifSection+10) != 0x2a){ ErrNonfatal("Invalid Exif start (1)",0,0); return; } FirstOffset = Get32u(ExifSection+12); if (FirstOffset < 8 || FirstOffset > 16){ // Usually set to 8, but other values valid too. ErrNonfatal("Suspicious offset of first IFD value",0,0); return; } DirWithThumbnailPtrs = NULL; // First directory starts 16 bytes in. All offset are relative to 8 bytes in. ProcessExifDir(ExifSection+8+FirstOffset, ExifSection+8, length-8, 0); ImageInfo.ThumbnailAtEnd = ImageInfo.ThumbnailOffset >= ImageInfo.LargestExifOffset ? TRUE : FALSE; #ifdef SUPERDEBUG printf("Thumbnail %s end", (ImageInfo.ThumbnailAtEnd ? "at" : "NOT at")); #endif if (DumpExifMap){ unsigned a,b; printf("Map: %05d- End of exif
",length-8); // for (a=0;a

7.exif.c
//--------------------------------------------------------------------------
// Process one of the nested EXIF directories.
//--------------------------------------------------------------------------
static void ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase,
        unsigned ExifLength, int NestingLevel)
{
    int de;
    int a;
    int NumDirEntries;
    unsigned ThumbnailOffset = 0;
    unsigned ThumbnailSize = 0;
    char IndentString[25];

    printf("ProcessExifDir");
    if (NestingLevel > 4){
        ErrNonfatal("Maximum directory nesting exceeded (corrupt exif header)", 0,0);
        return;
    }

    memset(IndentString, ' ', 25);
    IndentString[NestingLevel * 4] = '\0';


    NumDirEntries = Get16u(DirStart);
    #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))

    {
        unsigned char * DirEnd;
        DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
        if (DirEnd+4 > (OffsetBase+ExifLength)){
            if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength){
                // Version 1.3 of jhead would truncate a bit too much.
                // This also caught later on as well.
            }else{
                ErrNonfatal("Illegally sized exif subdirectory (%d entries)",NumDirEntries,0);
                return;
            }
        }
        if (DumpExifMap){
            printf("Map: %05d-%05d: Directory
",(int)(DirStart-OffsetBase), (int)(DirEnd+4-OffsetBase)); } } if (ShowTags){ printf("(dir has %d entries)
",NumDirEntries); } for (de=0;de= NUM_FORMATS) { // (-1) catches illegal zero case as unsigned underflows to positive large. ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag); continue; } if ((unsigned)Components > 0x10000){ ErrNonfatal("Illegal number of components %d for tag %04x", Components, Tag); continue; } ByteCount = Components * BytesPerFormat[Format]; if (ByteCount > 4){ unsigned OffsetVal; OffsetVal = Get32u(DirEntry+8); // If its bigger than 4 bytes, the dir entry contains an offset. if (OffsetVal+ByteCount > ExifLength){ // Bogus pointer offset and / or bytecount value ErrNonfatal("Illegal value pointer for tag %04x", Tag,0); continue; } ValuePtr = OffsetBase+OffsetVal; if (OffsetVal > ImageInfo.LargestExifOffset){ ImageInfo.LargestExifOffset = OffsetVal; } if (DumpExifMap){ printf("Map: %05d-%05d: Data for tag %04x
",OffsetVal, OffsetVal+ByteCount, Tag); } }else{ // 4 bytes or less and value is in the dir entry itself ValuePtr = DirEntry+8; } if (Tag == TAG_MAKER_NOTE){ if (ShowTags){ printf("%s Maker note: ",IndentString); } ProcessMakerNote(ValuePtr, ByteCount, OffsetBase, ExifLength); continue; } if (ShowTags){ // Show tag name for (a=0;;a++){ if (a >= (int)TAG_TABLE_SIZE){ printf("%s", IndentString); printf(" Unknown Tag %04x Value = ", Tag); break; } if (TagTable[a].Tag == Tag){ printf("%s", IndentString); printf(" %s = ",TagTable[a].Desc); break; } } // Show tag value. switch(Format){ case FMT_BYTE: if(ByteCount>1){ printf("%.*ls
", ByteCount/2, (wchar_t *)ValuePtr); }else{ PrintFormatNumber(ValuePtr, Format, ByteCount); printf("
"); } break; case FMT_UNDEFINED: // Undefined is typically an ascii string. case FMT_STRING: // String arrays printed without function call (different from int arrays) { printf("\"%s\"", ValuePtr); // int NoPrint = 0; // printf("\""); // for (a=0;a= 32){ // putchar(ValuePtr[a]); // NoPrint = 0; // }else{ // // Avoiding indicating too many unprintable characters of proprietary // // bits of binary information this program may not know how to parse. // if (!NoPrint && a != ByteCount-1){ // putchar('?'); // NoPrint = 1; // } // } // } // printf("\"
"); } break; default: // Handle arrays of numbers later (will there ever be?) PrintFormatNumber(ValuePtr, Format, ByteCount); printf("
"); } } // Extract useful components of tag switch(Tag){ case TAG_MAKE: strncpy(ImageInfo.CameraMake, (char *)ValuePtr, ByteCount < 31 ? ByteCount : 31); break; case TAG_MODEL: strncpy(ImageInfo.CameraModel, (char *)ValuePtr, ByteCount < 39 ? ByteCount : 39); break; case TAG_SUBSEC_TIME: strlcpy(ImageInfo.SubSecTime, (char *)ValuePtr, sizeof(ImageInfo.SubSecTime)); break; case TAG_SUBSEC_TIME_ORIG: strlcpy(ImageInfo.SubSecTimeOrig, (char *)ValuePtr, sizeof(ImageInfo.SubSecTimeOrig)); break; case TAG_SUBSEC_TIME_DIG: strlcpy(ImageInfo.SubSecTimeDig, (char *)ValuePtr, sizeof(ImageInfo.SubSecTimeDig)); break; case TAG_DATETIME_DIGITIZED: strlcpy(ImageInfo.DigitizedTime, (char *)ValuePtr, sizeof(ImageInfo.DigitizedTime)); if (ImageInfo.numDateTimeTags >= MAX_DATE_COPIES){ ErrNonfatal("More than %d date fields! This is nuts", MAX_DATE_COPIES, 0); break; } ImageInfo.DateTimeOffsets[ImageInfo.numDateTimeTags++] = (char *)ValuePtr - (char *)OffsetBase; break; case TAG_DATETIME_ORIGINAL: // If we get a DATETIME_ORIGINAL, we use that one. strncpy(ImageInfo.DateTime, (char *)ValuePtr, 19); // Fallthru... case TAG_DATETIME: if (!isdigit(ImageInfo.DateTime[0])){ // If we don't already have a DATETIME_ORIGINAL, use whatever // time fields we may have. strncpy(ImageInfo.DateTime, (char *)ValuePtr, 19); } if (ImageInfo.numDateTimeTags >= MAX_DATE_COPIES){ ErrNonfatal("More than %d date fields! This is nuts", MAX_DATE_COPIES, 0); break; } ImageInfo.DateTimeOffsets[ImageInfo.numDateTimeTags++] = (char *)ValuePtr - (char *)OffsetBase; break; case TAG_WINXP_COMMENT: if (ImageInfo.Comments[0]){ // We already have a jpeg comment. // Already have a comment (probably windows comment), skip this one. if (ShowTags) printf("Windows XP commend and other comment in header
"); break; // Already have a windows comment, skip this one. } if (ByteCount > 1){ if (ByteCount > MAX_COMMENT_SIZE) ByteCount = MAX_COMMENT_SIZE; memcpy(ImageInfo.Comments, ValuePtr, ByteCount); ImageInfo.CommentWidchars = ByteCount/2; } break; case TAG_USERCOMMENT: if (ImageInfo.Comments[0]){ // We already have a jpeg comment. // Already have a comment (probably windows comment), skip this one. if (ShowTags) printf("Multiple comments in exif header
"); break; // Already have a windows comment, skip this one. } // Comment is often padded with trailing spaces. Remove these first. for (a=ByteCount;;){ a--; if ((ValuePtr)[a] == ' '){ (ValuePtr)[a] = '\0'; }else{ break; } if (a == 0) break; } // Copy the comment { // We want to set copied comment length (msize) to be the // minimum of: // (1) The space still available in Exif // (2) The given comment length (ByteCount) // (3) MAX_COMMENT_SIZE - 1 int msiz = ExifLength - (ValuePtr-OffsetBase); if (msiz > ByteCount) msiz = ByteCount; if (msiz > MAX_COMMENT_SIZE - 1) msiz = MAX_COMMENT_SIZE - 1; if (msiz > 5 && memcmp(ValuePtr, "ASCII", 5) == 0) { for (a = 5; a < 10 && a < msiz; a++) { int c = (ValuePtr)[a]; if (c != '\0' && c != ' ') { strncpy(ImageInfo.Comments, (char *)ValuePtr + a, msiz - a); break; } } } else { strncpy(ImageInfo.Comments, (char *)ValuePtr, msiz); } } break; case TAG_FNUMBER: // Simplest way of expressing aperture, so I trust it the most. // (overwrite previously computd value if there is one) ImageInfo.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 (ImageInfo.ApertureFNumber == 0){ ImageInfo.ApertureFNumber = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5); } break; case TAG_FOCALLENGTH: // Nice digital cameras actually save the focal length as a function // of how farthey are zoomed in. ImageInfo.FocalLength.num = Get32u(ValuePtr); ImageInfo.FocalLength.denom = Get32u(4+(char *)ValuePtr); break; case TAG_SUBJECT_DISTANCE: // Inidcates the distacne the autofocus camera is focused to. // Tends to be less accurate as distance increases. ImageInfo.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) ImageInfo.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 (ImageInfo.ExposureTime == 0){ ImageInfo.ExposureTime = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2))); } break; case TAG_FLASH: ImageInfo.FlashUsed=(int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_ORIENTATION: if (NumOrientations >= 2){ // Can have another orientation tag for the thumbnail, but if there's // a third one, things are stringae. ErrNonfatal("More than two orientation tags!",0,0); break; } OrientationPtr[NumOrientations] = ValuePtr; OrientationNumFormat[NumOrientations] = Format; if (NumOrientations == 0){ ImageInfo.Orientation = (int)ConvertAnyFormat(ValuePtr, Format); } if (ImageInfo.Orientation < 0 || ImageInfo.Orientation > 8){ ErrNonfatal("Undefined rotation value %d", ImageInfo.Orientation, 0); ImageInfo.Orientation = 0; } NumOrientations += 1; 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_FOCAL_PLANE_XRES: FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format); break; case TAG_FOCAL_PLANE_UNITS: switch((int)ConvertAnyFormat(ValuePtr, Format)){ case 1: FocalplaneUnits = 25.4; break; // inch case 2: // According to the information I was using, 2 means meters. // But looking at the Cannon powershot's files, inches is the only // sensible value. FocalplaneUnits = 25.4; break; case 3: FocalplaneUnits = 10; break; // centimeter case 4: FocalplaneUnits = 1; break; // millimeter case 5: FocalplaneUnits = .001; break; // micrometer } break; case TAG_EXPOSURE_BIAS: ImageInfo.ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format); break; case TAG_WHITEBALANCE: ImageInfo.Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_LIGHT_SOURCE: ImageInfo.LightSource = (int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_METERING_MODE: ImageInfo.MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_EXPOSURE_PROGRAM: ImageInfo.ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_EXPOSURE_INDEX: if (ImageInfo.ISOequivalent == 0){ // Exposure index and ISO equivalent are often used interchangeably, // so we will do the same in jhead. // http://photography.about.com/library/glossary/bldef_ei.htm ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format); } break; case TAG_EXPOSURE_MODE: ImageInfo.ExposureMode = (int)ConvertAnyFormat(ValuePtr, Format); break; case TAG_ISO_EQUIVALENT: ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format); if ( ImageInfo.ISOequivalent < 50 ){ // Fixes strange encoding on some older digicams. ImageInfo.ISOequivalent *= 200; } break; case TAG_DIGITALZOOMRATIO: ImageInfo.DigitalZoomRatio = (float)ConvertAnyFormat(ValuePtr, Format); break; case TAG_THUMBNAIL_OFFSET: ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format); DirWithThumbnailPtrs = DirStart; break; case TAG_THUMBNAIL_LENGTH: ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format); ImageInfo.ThumbnailSizeOffset = ValuePtr-OffsetBase; break; case TAG_EXIF_OFFSET: if (ShowTags) printf("%s Exif Dir:",IndentString); case TAG_INTEROP_OFFSET: if (Tag == TAG_INTEROP_OFFSET && ShowTags) printf("%s Interop Dir:",IndentString); { unsigned char * SubdirStart; SubdirStart = OffsetBase + Get32u(ValuePtr); if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){ ErrNonfatal("Illegal exif or interop ofset directory link",0,0); }else{ ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1); } continue; } break; case TAG_GPSINFO: if (ShowTags) printf("%s GPS info dir:",IndentString); { unsigned char * SubdirStart; SubdirStart = OffsetBase + Get32u(ValuePtr); if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){ ErrNonfatal("Illegal GPS directory link",0,0); }else{ ProcessGpsInfo(SubdirStart, ByteCount, OffsetBase, ExifLength); } continue; } break; case TAG_FOCALLENGTH_35MM: // The focal length equivalent 35 mm is a 2.2 tag (defined as of April 2002) // if its present, use it to compute equivalent focal length instead of // computing it from sensor geometry and actual focal length. ImageInfo.FocalLength35mmEquiv = (unsigned)ConvertAnyFormat(ValuePtr, Format); break; case TAG_DISTANCE_RANGE: // Three possible standard values: // 1 = macro, 2 = close, 3 = distant ImageInfo.DistanceRange = (int)ConvertAnyFormat(ValuePtr, Format); break; } } { // 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; if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){ printf("DirStart %p offset from dirstart %d", DirStart, 2+12*NumDirEntries); Offset = Get32u(DirStart+2+12*NumDirEntries); if (Offset){ SubdirStart = OffsetBase + Offset; if (SubdirStart > OffsetBase+ExifLength || SubdirStart < OffsetBase){ printf("SubdirStart %p OffsetBase %p ExifLength %d Offset %d", SubdirStart, OffsetBase, ExifLength, Offset); if (SubdirStart > OffsetBase && SubdirStart < OffsetBase+ExifLength+20){ // Jhead 1.3 or earlier would crop the whole directory! // As Jhead produces this form of format incorrectness, // I'll just let it pass silently if (ShowTags) printf("Thumbnail removed with Jhead 1.3 or earlier
"); }else{ ErrNonfatal("Illegal subdirectory link",0,0); } }else{ if (SubdirStart <= OffsetBase+ExifLength){ if (ShowTags) printf("%s Continued directory ",IndentString); ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1); } } if (Offset > ImageInfo.LargestExifOffset){ ImageInfo.LargestExifOffset = Offset; } } }else{ // The exif header ends before the last next directory pointer. } } if (ThumbnailOffset){ ImageInfo.ThumbnailAtEnd = FALSE; if (DumpExifMap){ printf("Map: %05d-%05d: Thumbnail
",ThumbnailOffset, ThumbnailOffset+ThumbnailSize); } if (ThumbnailOffset <= ExifLength){ if (ThumbnailSize > ExifLength-ThumbnailOffset){ // If thumbnail extends past exif header, only save the part that // actually exists. Canon's EOS viewer utility will do this - the // thumbnail extracts ok with this hack. ThumbnailSize = ExifLength-ThumbnailOffset; if (ShowTags) printf("Thumbnail incorrectly placed in header
"); } // The thumbnail pointer appears to be valid. Store it. ImageInfo.ThumbnailOffset = ThumbnailOffset; ImageInfo.ThumbnailSize = ThumbnailSize; if (ShowTags){ printf("Thumbnail size: %d bytes
",ThumbnailSize); } } } printf("returning from ProcessExifDir"); }

좋은 웹페이지 즐겨찾기