Example #1
0
/*--------------------------------------------------------------------------
   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;
}
Example #2
0
/*--------------------------------------------------------------------------
   Process a EXIF marker
   Describes all the drivel that most digital cameras include...
--------------------------------------------------------------------------*/
bool CxImageJPG::CxExifInfo::exif_process(unsigned char * CharBuf, unsigned int length, EXIFINFO* pInfo)
{
    int ExifSettingsLength;
    unsigned char * LastExifRefd;

    pInfo->FlashUsed = 0; 
    /* If it's from a digicam, and it used flash, it says so. */
    pInfo->Comments[0] = '\0';  /* Initial value - null string */

    FocalplaneXRes = 0;
    FocalplaneUnits = 0;
    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 false;
		}
    }

    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 false;
        }
    }

    /* Check the next two values for correctness. */
    if (Get16u(CharBuf+8) != 0x2a || Get32u(CharBuf+10) != 0x08){
        strcpy(m_szLastError,"Invalid Exif start (1)");
		return false;
    }

    LastExifRefd = CharBuf;

    /* First directory starts 16 bytes in.  Offsets start at 8 bytes in. */
    if (!ProcessExifDir(CharBuf+14, CharBuf+6, length-6, pInfo, &LastExifRefd))
		return false;

    /* This is how far the interesting (non thumbnail) part of the exif went.
     */
    ExifSettingsLength = LastExifRefd - CharBuf;

    /* Compute the CCD width, in milimeters. */
    if (FocalplaneXRes != 0){
        pInfo->CCDWidth = 
            (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes);
    }

	return true;
}
Example #3
0
//--------------------------------------------------------------------------
// Process a EXIF marker
// Describes all the drivel that most digital cameras include...
//--------------------------------------------------------------------------
void process_EXIF (char * CharBuf, unsigned int length)
{
    ImageInfo.FlashUsed = 0; // If it s from a digicam, and it used flash, it says so.

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

    if (ShowTags){
        printf("Exif header %d bytes long\n",length);
    }

    {   // Check the EXIF header component
        static const uchar ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
        if (memcmp(CharBuf+2, ExifHeader,6)){
            ErrExit("Incorrect Exif header");
        }
    }

    if (memcmp(CharBuf+8,"II",2) == 0){
        if (ShowTags) printf("Exif section in Intel order\n");
        MotorolaOrder = 0;
    }else{
        if (memcmp(CharBuf+8,"MM",2) == 0){
            if (ShowTags) printf("Exif section in Motorola order\n");
            MotorolaOrder = 1;
        }else{
            ErrExit("Invalid Exif alignment marker.");
        }
    }

    // Check the next two values for correctness.
    if (Get16u(CharBuf+10) != 0x2a
      || Get32u(CharBuf+12) != 0x08){
        ErrExit("Invalid Exif start (1)");
    }

    LastExifRefd = CharBuf;

    // First directory starts 16 bytes in.  Offsets start at 8 bytes in.
    ProcessExifDir(CharBuf+16, CharBuf+8, length-6);

    // This is how far the interesting (non thumbnail) part of the exif went.
    ExifNonThumbnailLength = LastExifRefd - CharBuf;

    // Compute the CCD width, in milimeters.
    if (FocalplaneXRes != 0){
        ImageInfo.CCDWidth = (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes);
    }

    if (ShowTags){
        printf("Thunbnail size of Exif header: %d\n",length-ExifNonThumbnailLength);
    }
}
Example #4
0
//--------------------------------------------------------------------------
// Process a EXIF marker
// Describes all the drivel that most digital cameras include...
//--------------------------------------------------------------------------
void ExifData::process_EXIF(unsigned char * CharBuf, unsigned int length)
{
    ExifData::FlashUsed = 0; // If it s from a digicam, and it used flash, it says so.

    FocalplaneXRes = 0;
    FocalplaneUnits = 0;
    ExifImageWidth = 0;
    ExifImageLength = 0;

    {   // Check the EXIF header component
        static const uchar ExifHeader[] = "Exif\0\0";
        if (memcmp(CharBuf+2, ExifHeader,6)) {
            throw FatalError("Incorrect Exif header");
        }
    }

    if (memcmp(CharBuf+8,"II",2) == 0) {
        // printf("Exif section in Intel order\n");
        MotorolaOrder = 0;
    } else {
        if (memcmp(CharBuf+8,"MM",2) == 0) {
            // printf("Exif section in Motorola order\n");
            MotorolaOrder = 1;
        } else {
            throw FatalError("Invalid Exif alignment marker.");
        }
    }

    // Check the next two values for correctness.
    if (Get16u(CharBuf+10) != 0x2a) {
        throw FatalError("Invalid Exif start (1)");
    }

    long IFDoffset = Get32u(CharBuf+12);

    LastExifRefd = CharBuf;

    // First directory starts 16 bytes in.  Offsets start at 8 bytes in.
    ProcessExifDir(&CharBuf[8+IFDoffset], CharBuf+8, length-6, 0);

    // This is how far the interesting (non thumbnail) part of the exif went.
    ExifSettingsLength = LastExifRefd - CharBuf;

    // Compute the CCD width, in milimeters.
    if (FocalplaneXRes != 0) {
        kdDebug(7034) << "ExifImageWidth " << ExifImageWidth << " FocalplaneUnits " << FocalplaneUnits << " FocalplaneXRes " << FocalplaneXRes << endl;
        ExifData::CCDWidth = (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes);
    }
}
Example #5
0
//--------------------------------------------------------------------------
// Process a EXIF marker
// Describes all the drivel that most digital cameras include...
//--------------------------------------------------------------------------
void ExifData::process_EXIF ( unsigned char * CharBuf, unsigned int length )
{
	ExifData::FlashUsed = 0; // If it s from a digicam, and it used flash, it says so.

	FocalplaneXRes = 0;
	FocalplaneUnits = 0;
	ExifImageWidth = 0;
	ExifImageLength = 0;

// Check the EXIF header component
	static const uchar ExifHeader[] = "Exif\0\0";
	if ( memcmp ( CharBuf+2, ExifHeader,6 ) )
		return ;

	if ( memcmp ( CharBuf+8,"II",2 ) == 0 )
		MotorolaOrder = 0;
	else
	{
		if ( memcmp ( CharBuf+8,"MM",2 ) == 0 )
			MotorolaOrder = 1;
		else
			return ;
	}

	// Check the next two values for correctness.
	if ( Get16u ( CharBuf+10 ) != 0x2a || Get32u ( CharBuf+12 ) != 0x08 )
		return ;
	long IFDoffset = Get32u(CharBuf+12);
	LastExifRefd = CharBuf;

	// First directory starts 16 bytes in.  Offsets start at 8 bytes in.
	ProcessExifDir(&CharBuf[8+IFDoffset], CharBuf+8, length-6);
	recurseLevel--;
	// This is how far the interesting (non thumbnail) part of the exif went.
	ExifSettingsLength = LastExifRefd - CharBuf;

	// Compute the CCD width, in milimeters.
	if ( FocalplaneXRes != 0 )
	{
		ExifData::CCDWidth = ( float ) ( ExifImageWidth * FocalplaneUnits / FocalplaneXRes );
	}
}
Example #6
0
bool Cexif::process_EXIF(unsigned char * CharBuf, unsigned int length)
{
	m_exifinfo->Comments[0] = '\0';
	ExifImageWidth = 0;

	static const unsigned char ExifHeader[] = "Exif\0\0";
	if(memcmp(CharBuf+0, ExifHeader,6))
	{
		strcpy(m_szLastError,"Incorrect Exif header"); return false;
	}

	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 false;
		}
	}

	if (Get16u(CharBuf+8) != 0x2a)
	{
		strcpy(m_szLastError,"Invalid Exif start (1)"); return false;
	}
	int FirstOffset = Get32u(CharBuf+10);
	if (FirstOffset < 8 || FirstOffset > 16)
	{
		strcpy(m_szLastError,"Suspicious offset of first IFD value"); return 0;
	}
	unsigned char * LastExifRefd = CharBuf;

	if (!ProcessExifDir(CharBuf+14, CharBuf+6, length-6, m_exifinfo, &LastExifRefd)) return false;

	if (m_exifinfo->FocalplaneXRes != 0)
		m_exifinfo->CCDWidth = (float)(ExifImageWidth * m_exifinfo->FocalplaneUnits / m_exifinfo->FocalplaneXRes);

	return true;
}
Example #7
0
/*--------------------------------------------------------------------------
   Process one of the nested EXIF directories.
--------------------------------------------------------------------------*/
bool CxImageJPG::CxExifInfo::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength,
                           EXIFINFO * const pInfo, 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 false;
    }

    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 byte-by-byte
               cursor, so we declare it as a pointer to a generic byte here.
            */
        int ByteCount;
        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 false;
		}

        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 */
                strcpy(m_szLastError,"Illegal pointer offset value in EXIF.");
				return false;
            }
            ValuePtr = OffsetBase+OffsetVal;
        }else{
            /* 4 bytes or less and value is in the dir entry itself */
            ValuePtr = DirEntry+8;
        }

        if (*LastExifRefdP < ValuePtr+ByteCount){
            /* Keep track of last byte in the exif header that was
               actually referenced.  That way, we know where the
               discardable thumbnail data begins.
            */
            *LastExifRefdP = ValuePtr+ByteCount;
        }

        /* Extract useful components of tag */
        switch(Tag){

            case TAG_MAKE:
                strncpy(pInfo->CameraMake, (char*)ValuePtr, 31);
                break;

            case TAG_MODEL:
                strncpy(pInfo->CameraModel, (char*)ValuePtr, 39);
                break;

            case TAG_DATETIME_ORIGINAL:
                strncpy(pInfo->DateTime, (char*)ValuePtr, 19);
                break;

            case TAG_USERCOMMENT:
                /* Olympus has this padded with trailing spaces.
                   Remove these first. 
                */
                for (a=ByteCount;;){
                    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(pInfo->Comments, (char*)ValuePtr+a, 
                                    199);
                            break;
                        }
                    }
                    
                }else{
                    strncpy(pInfo->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)
                   */
                pInfo->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 (pInfo->ApertureFNumber == 0){
                    pInfo->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. 
                */

                pInfo->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.
                */
                pInfo->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) 
                */
                pInfo->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 (pInfo->ExposureTime == 0){
                    pInfo->ExposureTime = (float)
                        (1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2)));
                }
                break;

            case TAG_FLASH:
                if (ConvertAnyFormat(ValuePtr, Format)){
                    pInfo->FlashUsed = 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_FOCALPLANEXRES:
                FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_FOCALPLANEUNITS:
                switch((int)ConvertAnyFormat(ValuePtr, Format)){
                    case 1: FocalplaneUnits = 25.4; break; /* 1 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;  /* 1 centimeter*/
                    case 4: FocalplaneUnits = 1;    break;  /* 1 millimeter*/
                    case 5: FocalplaneUnits = .001; break;  /* 1 micrometer*/
                }
                break;

                /* Remaining cases contributed by: Volker C. Schoech
                   ([email protected])
                */

            case TAG_EXPOSURE_BIAS:
                pInfo->ExposureBias = 
                    (float) ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_WHITEBALANCE:
                pInfo->Whitebalance = 
                    (int)ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_METERING_MODE:
                pInfo->MeteringMode = 
                    (int)ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_EXPOSURE_PROGRAM:
                pInfo->ExposureProgram = 
                    (int)ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_ISO_EQUIVALENT:
                pInfo->ISOequivalent = 
                    (int)ConvertAnyFormat(ValuePtr, Format);
                if ( pInfo->ISOequivalent < 50 ) 
                    pInfo->ISOequivalent *= 200;
                break;

            case TAG_COMPRESSION_LEVEL:
                pInfo->CompressionLevel = 
                    (int)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 false;
            }
            ProcessExifDir(SubdirStart, OffsetBase, ExifLength, pInfo, 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 false;
            }
            ProcessExifDir(SubdirStart, OffsetBase, ExifLength, pInfo, LastExifRefdP);
        }
    }


    if (ThumbnailSize && ThumbnailOffset){
        if (ThumbnailSize + ThumbnailOffset <= ExifLength){
            /* The thumbnail pointer appears to be valid.  Store it. */
            pInfo->ThumbnailPointer = OffsetBase + ThumbnailOffset;
            pInfo->ThumbnailSize = ThumbnailSize;
        }
    }

	return true;
}
Example #8
0
bool Cexif::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength, EXIFINFO * const m_exifinfo, unsigned char ** const LastExifRefdP )
{
	int de, a, 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;
		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)
		{
			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 (OffsetVal+BytesCount > ExifLength)
			{
        			strcpy(m_szLastError,"Illegal pointer offset value in EXIF."); return 0;
        		}
        		ValuePtr = OffsetBase+OffsetVal;
        	}
		else ValuePtr = DirEntry+8;

	        if (*LastExifRefdP < ValuePtr+BytesCount) *LastExifRefdP = ValuePtr+BytesCount;

        	switch(Tag)
		{
		case TAG_MAKE:
			strncpy(m_exifinfo->CameraMake, (char*)ValuePtr, 31);
			break;
		case TAG_MODEL:
			strncpy(m_exifinfo->CameraModel, (char*)ValuePtr, 39);
			break;
		case TAG_EXIF_VERSION:
			strncpy(m_exifinfo->Version,(char*)ValuePtr, 4);
			break;
		case TAG_DATETIME_ORIGINAL:
			strncpy(m_exifinfo->DateTime, (char*)ValuePtr, 19);
			break;
		case TAG_USERCOMMENT:
			for (a=BytesCount;;)
			{
				a--;
				if (((char*)ValuePtr)[a] == ' ') ((char*)ValuePtr)[a] = '\0';
				else break;

				if (a == 0) break;
			}

			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:
			m_exifinfo->ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
			break;
		case TAG_APERTURE:
		case TAG_MAXAPERTURE:
			if (m_exifinfo->ApertureFNumber == 0)
			{
				//m_exifinfo->ApertureFNumber = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5);
			}
			break;
		case TAG_BRIGHTNESS:
			m_exifinfo->Brightness = (float)ConvertAnyFormat(ValuePtr, Format);
			break;
		case TAG_FOCALLENGTH:
			m_exifinfo->FocalLength = (float)ConvertAnyFormat(ValuePtr, Format);
			break;
		case TAG_SUBJECT_DISTANCE:
			m_exifinfo->Distance = (float)ConvertAnyFormat(ValuePtr, Format);
			break;
		case TAG_EXPOSURETIME:
			m_exifinfo->ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format);
			break;
		case TAG_SHUTTERSPEED:
			if (m_exifinfo->ExposureTime == 0)
			{
				//m_exifinfo->ExposureTime = (float) (1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2)));
			}
			break;
		case TAG_FLASH:
			if ((int)ConvertAnyFormat(ValuePtr, Format) & 7) strcpy(m_exifinfo->FlashUsed,"fire");
			else strcpy(m_exifinfo->FlashUsed,"not fired");
			break;
		case TAG_ORIENTATION:
			m_exifinfo->Orient = (int)ConvertAnyFormat(ValuePtr, Format);
			switch((int)ConvertAnyFormat(ValuePtr, Format))
			{
			case 1:		strcpy(m_exifinfo->Orientation,"Top-Left"); break;
			case 2:		strcpy(m_exifinfo->Orientation,"Top-Right"); break;
			case 3:		strcpy(m_exifinfo->Orientation,"Bottom-Right"); break;
			case 4:		strcpy(m_exifinfo->Orientation,"Bottom-Left"); break;
			case 5:		strcpy(m_exifinfo->Orientation,"Left-Top"); break;
			case 6:		strcpy(m_exifinfo->Orientation,"Right-Top"); break;
			case 7:		strcpy(m_exifinfo->Orientation,"Right-Bottom"); break;
			case 8:		strcpy(m_exifinfo->Orientation,"Left-Bottom"); break;
			default:	strcpy(m_exifinfo->Orientation,"Undefined"); break;
			}
			break;
		case TAG_EXIF_IMAGELENGTH:
		case TAG_EXIF_IMAGEWIDTH:
			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 2: strcpy(m_exifinfo->ResolutionUnit,"inches"); break;
				case 3: strcpy(m_exifinfo->ResolutionUnit,"centimeters"); break;
				default: strcpy(m_exifinfo->ResolutionUnit,"reserved");
			}
			break;
		case TAG_FOCALPLANEUNITS:
			switch((int)ConvertAnyFormat(ValuePtr, Format))
			{
				case 1: m_exifinfo->FocalplaneUnits = 1.0f; break;
				case 2: m_exifinfo->FocalplaneUnits = 1.0f; break;
				case 3: m_exifinfo->FocalplaneUnits = 0.3937007874f; break;
				case 4: m_exifinfo->FocalplaneUnits = 0.03937007874f; break;
				case 5: m_exifinfo->FocalplaneUnits = 0.00003937007874f;
			}
			break;
		case TAG_EXPOSURE_BIAS:
			m_exifinfo->ExposureBias = (float) ConvertAnyFormat(ValuePtr, Format);
			break;
		case TAG_WHITEBALANCE:
			switch((int)ConvertAnyFormat(ValuePtr, Format))
			{
				case 0: strcpy(m_exifinfo->LightSource,"unknown"); break;
				case 1: strcpy(m_exifinfo->LightSource,"Daylight"); break;
				case 2: strcpy(m_exifinfo->LightSource,"Fluorescent"); break;
				case 3: strcpy(m_exifinfo->LightSource,"Tungsten"); break;
				case 17: strcpy(m_exifinfo->LightSource,"Standard light A"); break;
				case 18: strcpy(m_exifinfo->LightSource,"Standard light B"); break;
				case 19: strcpy(m_exifinfo->LightSource,"Standard light C"); break;
				case 20: strcpy(m_exifinfo->LightSource,"D55"); break;
				case 21: strcpy(m_exifinfo->LightSource,"D65"); break;
				case 22: strcpy(m_exifinfo->LightSource,"D75"); break;
				default: strcpy(m_exifinfo->LightSource,"other"); break;
			}
			break;
		case TAG_METERING_MODE:
			switch((int)ConvertAnyFormat(ValuePtr, Format))
			{
				case 0: strcpy(m_exifinfo->MeteringMode,"unknown"); break;
				case 1: strcpy(m_exifinfo->MeteringMode,"Average"); break;
				case 2: strcpy(m_exifinfo->MeteringMode,"Center-Weighted-Average"); break;
				case 3: strcpy(m_exifinfo->MeteringMode,"Spot"); break;
				case 4: strcpy(m_exifinfo->MeteringMode,"MultiSpot"); break;
				case 5: strcpy(m_exifinfo->MeteringMode,"Pattern"); break;
				case 6: strcpy(m_exifinfo->MeteringMode,"Partial"); break;
				default: strcpy(m_exifinfo->MeteringMode,"other"); break;
			}
			break;
		case TAG_EXPOSURE_PROGRAM:
			switch((int)ConvertAnyFormat(ValuePtr, Format))
			{
				case 0: strcpy(m_exifinfo->ExposureProgram,"not defined"); break;
				case 1: strcpy(m_exifinfo->ExposureProgram,"Manual"); break;
				case 2: strcpy(m_exifinfo->ExposureProgram,"Normal program"); break;
				case 3: strcpy(m_exifinfo->ExposureProgram,"Aperture priority"); break;
				case 4: strcpy(m_exifinfo->ExposureProgram,"Shutter priority"); break;
				case 5: strcpy(m_exifinfo->ExposureProgram,"Creative program"); break;
				case 6: strcpy(m_exifinfo->ExposureProgram,"Action program"); break;
				case 7: strcpy(m_exifinfo->ExposureProgram,"Portrait mode"); break;
				case 8: strcpy(m_exifinfo->ExposureProgram,"Landscape mode"); break;
				default: strcpy(m_exifinfo->ExposureProgram,"reserved"); break;
			}
			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;
		}
	}


	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 && m_exifinfo->Thumnailstate)
	{
		if (ThumbnailSize + ThumbnailOffset <= ExifLength)
		{
			if(FILE *tf = fopen(THUMBNAILTMPFILE, "w"))
			{
				fwrite( OffsetBase + ThumbnailOffset, ThumbnailSize, 1, tf);
				fclose(tf);
				m_exifinfo->Thumnailstate = 2;
			}
		}
	}

	return 1;
}
Example #9
0
/*--------------------------------------------------------------------------
   Process one of the nested EXIF directories.
--------------------------------------------------------------------------*/
bool CExifRead::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned int ExifLength, 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))
	{
#ifdef GetErrorCode
        strcpy(m_szLastError,"Illegally sized directory");
#endif
		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) 
		{
#ifdef GetErrorCode            
			/* (-1) catches illegal zero case as unsigned underflows to positive large */
            strcpy(m_szLastError,"Illegal format code in EXIF dir");
#endif
			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)
			{
#ifdef GetErrorCode                
				/* Bogus pointer offset and / or unsigned charcount value */
                strcpy(m_szLastError,"Illegal pointer offset value in EXIF.");
#endif
				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:
				if ( m_flags & EXIF_CAMERA_MAKER)
					strncpy(m_pExifInfo->CameraMake, (char*)ValuePtr, 31);
                break;

            case TAG_MODEL:
				if ( m_flags & EXIF_CAMERA_MODEL)
					strncpy_s(m_pExifInfo->CameraModel,40, (char*)ValuePtr, 39);
                break;

			case TAG_EXIF_VERSION:
				if ( m_flags & EXIF_VERSION)
					strncpy_s(m_pExifInfo->Version,5,(char*)ValuePtr, 4);
				break;

            case TAG_DATETIME_ORIGINAL:
				if ( m_flags & EXIF_DATA_TIME)
					strncpy_s(m_pExifInfo->DateTime,20, (char*)ValuePtr, 19);
                break;

            case TAG_USERCOMMENT:
				if ( m_flags & EXIF_USER_COMMENT)
				{
					// 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_s(m_pExifInfo->Comments,MAX_COMMENT, (char*)ValuePtr+a, 199);
								break;
							}
						}

					}else
					{
						strncpy_s(m_pExifInfo->Comments,MAX_COMMENT, (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)
                   */
				if ( m_flags & EXIF_APERTUREF_NUMBER)
					m_pExifInfo->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_flags & EXIF_APERTUREF_NUMBER) && m_pExifInfo->ApertureFNumber == 0)
				{
                    m_pExifInfo->ApertureFNumber = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0)*0.5);
                }
                break;

			case TAG_BRIGHTNESS:
				if ( m_flags & EXIF_BRIGHTNESS)
					m_pExifInfo->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. 
                */
				if ( m_flags & EXIF_FOCAL_LENGTH)
					m_pExifInfo->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.
                */
				if ( m_flags & EXIF_DISTANCE)
					m_pExifInfo->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) 
                */
				if ( m_flags & EXIF_EXPOSURE_TIME)
					m_pExifInfo->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_flags & EXIF_EXPOSURE_TIME) && m_pExifInfo->ExposureTime == 0)
				{
                    m_pExifInfo->ExposureTime = (float) (1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0)));
                }
                break;

            case TAG_FLASH:
				if ( m_flags & EXIF_FLASH_USED)
				{
					if ((int)ConvertAnyFormat(ValuePtr, Format) & 7)
					{
						m_pExifInfo->FlashUsed = 1;
					}
					else
					{
						m_pExifInfo->FlashUsed = 0;
					}
				}
                break;

            case TAG_ORIENTATION:
				if ( m_flags & EXIF_ORIENTATION)
				{
					m_pExifInfo->Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
					if (m_pExifInfo->Orientation < 1 || m_pExifInfo->Orientation > 8)
					{
#ifdef GetErrorCode 
						strcpy(m_szLastError,"Undefined rotation value");
#endif
						m_pExifInfo->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 (m_ExifImageWidth < a) 
					m_ExifImageWidth = a;
                break;

            case TAG_FOCALPLANEXRES:
				if ( m_flags & EXIF_FOCALPLANE_XRES)
					m_pExifInfo->FocalplaneXRes = (float)ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_FOCALPLANEYRES:
				if ( m_flags & EXIF_FOCALPLANE_YRES)
					m_pExifInfo->FocalplaneYRes = (float)ConvertAnyFormat(ValuePtr, Format);
                break;

			case TAG_RESOLUTIONUNIT:
				if ( m_flags & EXIF_RESOLUTION_UNITS)
				{
					switch((int)ConvertAnyFormat(ValuePtr, Format))
					{
					case 1: m_pExifInfo->ResolutionUnit = 1.0f; break; /* 1 inch */
					case 2:	m_pExifInfo->ResolutionUnit = 1.0f; break;
					case 3: m_pExifInfo->ResolutionUnit = 0.3937007874f;    break;  /* 1 centimeter*/
					case 4: m_pExifInfo->ResolutionUnit = 0.03937007874f;   break;  /* 1 millimeter*/
					case 5: m_pExifInfo->ResolutionUnit = 0.00003937007874f;  /* 1 micrometer*/
					}
				}
                break;

            case TAG_FOCALPLANEUNITS:
				if ( m_flags & EXIF_FOCALPLANE_UNITS)
				{
					switch((int)ConvertAnyFormat(ValuePtr, Format))
					{
						case 1: m_pExifInfo->FocalplaneUnits = 1.0f; break; /* 1 inch */
						case 2:	m_pExifInfo->FocalplaneUnits = 1.0f; break;
						case 3: m_pExifInfo->FocalplaneUnits = 0.3937007874f;    break;  /* 1 centimeter*/
						case 4: m_pExifInfo->FocalplaneUnits = 0.03937007874f;   break;  /* 1 millimeter*/
						case 5: m_pExifInfo->FocalplaneUnits = 0.00003937007874f;  /* 1 micrometer*/
					}
				}
                break;

                // Remaining cases contributed by: Volker C. Schoech <schoech(at)gmx(dot)de>

            case TAG_EXPOSURE_BIAS:
				if ( m_flags & EXIF_EXPOSURE_BIAS)
					m_pExifInfo->ExposureBias = (float) ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_WHITEBALANCE:
				if ( m_flags & EXIF_WHITE_BALANCE)
					m_pExifInfo->Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_METERING_MODE:
				if ( m_flags & EXIF_METERING_MODE)
					m_pExifInfo->MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_EXPOSURE_PROGRAM:
				if ( m_flags & EXIF_EXPOSURE_PROGRAM)
					m_pExifInfo->ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_ISO_EQUIVALENT:
				if ( m_flags & EXIF_ISO_EAUIVALENT)
				{
					m_pExifInfo->ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
					if ( m_pExifInfo->ISOequivalent < 50 ) 
						m_pExifInfo->ISOequivalent *= 200;
				}
                break;

            case TAG_COMPRESSION_LEVEL:
				if ( m_flags & EXIF_COMPRESSION_LEVEL)
					m_pExifInfo->CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_XRESOLUTION:
				if ( m_flags & EXIF_XRESOLUTION)
					m_pExifInfo->Xresolution = (float)ConvertAnyFormat(ValuePtr, Format);
                break;
            case TAG_YRESOLUTION:
				if ( m_flags & EXIF_YRESOLUTION)
					m_pExifInfo->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 )
			{
#ifdef GetErrorCode                
				strcpy(m_szLastError,"Illegal subdirectory link");
#endif
				return 0;
            }
            ProcessExifDir(SubdirStart, OffsetBase, ExifLength, 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 = Get32u(DirStart+2+12*NumDirEntries);
        if (Offset > 0)
		{
            SubdirStart = OffsetBase + Offset;
            if (SubdirStart < OffsetBase 
                || SubdirStart > OffsetBase+ExifLength)
			{
#ifdef GetErrorCode                
				strcpy(m_szLastError,"Illegal subdirectory link");
#endif
				return 0;
            }
            ProcessExifDir(SubdirStart, OffsetBase, ExifLength, LastExifRefdP);
        }
    }

    if (ThumbnailSize && ThumbnailOffset)
	{
        if (ThumbnailSize + ThumbnailOffset <= ExifLength)
		{
			if ( m_pExifInfo->pThumbnailPointer != NULL)
			{
				delete m_pExifInfo->pThumbnailPointer;
			}
			/* The thumbnail pointer appears to be valid.  Store it. */
            m_pExifInfo->pThumbnailPointer = OffsetBase + ThumbnailOffset;
			m_pExifInfo->ThumbnailOffset = ThumbnailOffset;
            m_pExifInfo->ThumbnailSize = ThumbnailSize;
        }
    }

	return 1;
}
Example #10
0
//--------------------------------------------------------------------------
// Process one of the nested EXIF directories.
//--------------------------------------------------------------------------
void ExifData::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength, unsigned NestingLevel)
{
    int de;
    int a;
    int NumDirEntries;
    unsigned ThumbnailOffset = 0;
    unsigned ThumbnailSize = 0;

    if ( NestingLevel > 4)
        throw FatalError("Maximum directory nesting exceeded (corrupt exif header)");

    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 {
                // Note: Files that had thumbnails trimmed with jhead 1.3 or earlier
                // might trigger this.
                throw FatalError("Illegally sized directory");
            }
        }
        if (DirEnd < LastExifRefd) LastExifRefd = DirEnd;
    }

    for (de=0; de<NumDirEntries; de++) {
        int Tag, Format, Components;
        unsigned char * ValuePtr;
        unsigned ByteCount;
        char * DirEntry;
        DirEntry = (char *)DIR_ENTRY_ADDR(DirStart, 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.
            throw FatalError("Illegal format code in EXIF dir");
        }

        if ((unsigned)Components > 0x10000) {
            throw FatalError("Illegal number of components for 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
                //printf("Offset %d bytes %d ExifLen %d\n",OffsetVal, ByteCount, ExifLength);

                throw FatalError("Illegal pointer offset value in EXIF");
            }
            ValuePtr = OffsetBase+OffsetVal;
        } else {
            // 4 bytes or less and value is in the dir entry itself
            ValuePtr = (unsigned char *)DirEntry+8;
        }

        if (LastExifRefd < ValuePtr+ByteCount) {
            // Keep track of last byte in the exif header that was actually referenced.
            // That way, we know where the discardable thumbnail data begins.
            LastExifRefd = ValuePtr+ByteCount;
        }

        // Extract useful components of tag
        switch(Tag) {

        case TAG_MAKE:
            ExifData::CameraMake = QString::fromLatin1((const char*)ValuePtr, 31);
            break;

        case TAG_MODEL:
            ExifData::CameraModel = QString::fromLatin1((const char*)ValuePtr, 39);
            break;

        case TAG_ORIENTATION:
            Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
            break;

        case TAG_DATETIME_ORIGINAL:
            DateTime = QString::fromLatin1((const char*)ValuePtr, 19);
            break;

        case TAG_USERCOMMENT:
            // Olympus has this 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
            if (memcmp(ValuePtr, "ASCII",5) == 0) {
                for (a=5; a<10; a++) {
                    int c;
                    c = (ValuePtr)[a];
                    if (c != '\0' && c != ' ') {
                        UserComment = QString::fromLatin1((const char*)(a+ValuePtr), 199);
                        break;
                    }
                }
            } else {
                UserComment = QString::fromLatin1((const 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)
            ExifData::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 (ExifData::ApertureFNumber == 0) {
                ExifData::ApertureFNumber
                    = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0)*0.5);
            }
            break;

        case TAG_FOCALLENGTH:
            // Nice digital cameras actually save the focal length as a function
            // of how far they are zoomed in.
            ExifData::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.
            ExifData::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)
            ExifData::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 (ExifData::ExposureTime == 0) {
                ExifData::ExposureTime
                    = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0)));
            }
            break;

        case TAG_FLASH:
            ExifData::FlashUsed = (int)ConvertAnyFormat(ValuePtr, Format);
            break;

        case TAG_EXIF_IMAGELENGTH:
            ExifImageLength = (int)ConvertAnyFormat(ValuePtr, Format);
            break;

        case TAG_EXIF_IMAGEWIDTH:
            ExifImageWidth = (int)ConvertAnyFormat(ValuePtr, Format);
            break;

        case TAG_FOCALPLANEXRES:
            FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format);
            break;

        case TAG_FOCALPLANEUNITS:
            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;  // milimeter
            case 5:
                FocalplaneUnits = .001;
                break;  // micrometer
            }
            break;

        // Remaining cases contributed by: Volker C. Schoech ([email protected])

        case TAG_EXPOSURE_BIAS:
            ExifData::ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format);
            break;

        case TAG_WHITEBALANCE:
            ExifData::Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
            break;

        case TAG_METERING_MODE:
            ExifData::MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
            break;

        case TAG_EXPOSURE_PROGRAM:
            ExifData::ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
            break;

        case TAG_ISO_EQUIVALENT:
            ExifData::ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
            if ( ExifData::ISOequivalent < 50 ) ExifData::ISOequivalent *= 200;
            break;

        case TAG_COMPRESSION_LEVEL:
            ExifData::CompressionLevel = (int)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) {
                throw FatalError("Illegal subdirectory link");
            }
            ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1);
            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 comitee!
        unsigned char * SubdirStart;
        unsigned Offset;

        if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength) {
            Offset = Get32u(DIR_ENTRY_ADDR(DirStart, NumDirEntries));
            // There is at least one jpeg from an HP camera having an Offset of almost MAXUINT.
            // Adding OffsetBase to it produces an overflow, so compare with ExifLength here.
            // See http://bugs.kde.org/show_bug.cgi?id=54542
            if (Offset && Offset < ExifLength) {
                SubdirStart = OffsetBase + Offset;
                if (SubdirStart > OffsetBase+ExifLength) {
                    if (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
                        kdDebug(7034) << "Thumbnail removed with Jhead 1.3 or earlier\n";
                    } else {
                        throw FatalError("Illegal subdirectory link 2");
                    }
                } else {
                    if (SubdirStart <= OffsetBase+ExifLength) {
                        ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1);
                    }
                }
            }
        } else {
            // The exif header ends before the last next directory pointer.
        }
    }

    if (ThumbnailSize && ThumbnailOffset) {
        if (ThumbnailSize + ThumbnailOffset < ExifLength) {
            // The thumbnail pointer appears to be valid.  Store it.
            Thumbnail.loadFromData(OffsetBase + ThumbnailOffset, ThumbnailSize, "JPEG");
        }
    }
}
Example #11
0
//--------------------------------------------------------------------------
// Process one of the nested EXIF directories.
//--------------------------------------------------------------------------
static void ProcessExifDir(char * DirStart, char * OffsetBase, unsigned ExifLength)
{
    int de;
    int a;
    int NumDirEntries;

    NumDirEntries = Get16u(DirStart);

    if ((DirStart+2+NumDirEntries*12) > (OffsetBase+ExifLength)){
        ErrExit("Illegally sized directory");
    }

    if (ShowTags){
        printf("Directory with %d entries\n",NumDirEntries);
    }

    for (de=0;de<NumDirEntries;de++){
        int Tag, Format, Components;
        char * ValuePtr;
        int ByteCount;
        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.
            ErrExit("Illegal format code in EXIF dir");
        }

        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
                printf("Offset %d bytes %d ExifLen %d\n",OffsetVal, ByteCount, ExifLength);

                ErrExit("Illegal pointer offset value in EXIF");
            }
            ValuePtr = OffsetBase+OffsetVal;
        }else{
            // 4 bytes or less and value is in the dir entry itself
            ValuePtr = DirEntry+8;
        }

        if (LastExifRefd < ValuePtr+ByteCount){
            // Keep track of last byte in the exif header that was actually referenced.
            // That way, we know where the discardable thumbnail data begins.
            LastExifRefd = ValuePtr+ByteCount;
        }

        if (ShowTags){
            // Show tag name
            for (a=0;;a++){
                if (TagTable[a].Tag == 0){
                    printf("  Unknown Tag %04x Value = ", Tag);
                    break;
                }
                if (TagTable[a].Tag == Tag){
                    printf("    %s = ",TagTable[a].Desc);
                    break;
                }
            }

            // Show tag value.
            switch(Format){

                case FMT_UNDEFINED:
                    // Undefined is typically an ascii string.

                case FMT_STRING:
                    // String arrays printed without function call (different from int arrays)
                    printf("\"");
                    for (a=0;a<ByteCount;a++){
                        if (isprint((ValuePtr)[a])){
                            putchar((ValuePtr)[a]);
                        }
                    }
                    printf("\"\n");
                    break;

                default:
                    // Handle arrays of numbers later (will there ever be?)
                    PrintFormatNumber(ValuePtr, Format);
            }
        }

        // Extract useful components of tag
        switch(Tag){

            case TAG_MAKE:
                strncpy(ImageInfo.CameraMake, ValuePtr, 31);
                break;

            case TAG_MODEL:
                strncpy(ImageInfo.CameraModel, ValuePtr, 39);
                break;

            case TAG_DATETIME_ORIGINAL:
                strncpy(ImageInfo.DateTime, ValuePtr, 19);
                break;

            case TAG_USERCOMMENT:
                // Olympus has this 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
                if (memcmp(ValuePtr, "ASCII",5) == 0){
                    for (a=5;a<10;a++){
                        int c;
                        c = (ValuePtr)[a];
                        if (c != '\0' && c != ' '){
                            strncpy(ImageInfo.Comments, a+ValuePtr, 199);
                            break;
                        }
                    }
                    
                }else{
                    strncpy(ImageInfo.Comments, 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)
                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 = (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.
                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:
                if (ConvertAnyFormat(ValuePtr, Format)){
                    ImageInfo.FlashUsed = 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_FOCALPLANEXRES:
                FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_FOCALPLANEUNITS:
                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;  // milimeter
                    case 5: FocalplaneUnits = .001; break;  // micrometer
                }
                break;

                // Remaining cases contributed by: Volker C. Schoech ([email protected])

            case TAG_EXPOSURE_BIAS:
                ImageInfo.ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_WHITEBALANCE:
                ImageInfo.Whitebalance = (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_ISO_EQUIVALENT:
                ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
                if ( ImageInfo.ISOequivalent < 80 ) ImageInfo.ISOequivalent *= 200;
                break;

            case TAG_COMPRESSION_LEVEL:
                ImageInfo.CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format);
                break;
        }

        if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET){
            char * SubdirStart;
            SubdirStart = OffsetBase + Get32u(ValuePtr);
            if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){
                ErrExit("Illegal subdirectory link");
            }
            ProcessExifDir(SubdirStart, OffsetBase, ExifLength);
            continue;
        }
    }
}