|
shun-iwasawa |
fdbab5 |
/*-------------------------------------------------------------
|
|
shun-iwasawa |
fdbab5 |
tiio_jpg_exif.cpp
|
|
shun-iwasawa |
fdbab5 |
Based on source code of a public domain software "Exif Jpeg header manipulation
|
|
shun-iwasawa |
fdbab5 |
tool (jhead)" by Matthias Wandel.
|
|
shun-iwasawa |
fdbab5 |
For now it is used only for obtaining resolution values.
|
|
shun-iwasawa |
fdbab5 |
http://www.sentex.net/~mwandel/jhead/
|
|
shun-iwasawa |
fdbab5 |
-------------------------------------------------------------*/
|
|
shun-iwasawa |
fdbab5 |
#include "tiio_jpg_exif.h"
|
|
shun-iwasawa |
fdbab5 |
#include <iostream></iostream>
|
|
shun-iwasawa |
fdbab5 |
#include <string.h></string.h>
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
// for debug
|
|
shun-iwasawa |
fdbab5 |
#define ShowTags 0
|
|
shun-iwasawa |
fdbab5 |
#define DumpExifMap 0
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
namespace {
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
typedef unsigned char uchar;
|
|
shun-iwasawa |
fdbab5 |
const int BytesPerFormat[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
|
|
shun-iwasawa |
fdbab5 |
//--------------------------------------------------------------------------
|
|
shun-iwasawa |
fdbab5 |
// Describes tag values
|
|
shun-iwasawa |
fdbab5 |
const int TAG_X_RESOLUTION = 0x011A;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_Y_RESOLUTION = 0x011B;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_RESOLUTION_UNIT = 0x0128;
|
|
shun-iwasawa |
fdbab5 |
#ifdef ReadAllTags
|
|
shun-iwasawa |
fdbab5 |
const int TAG_INTEROP_INDEX = 0x0001;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_INTEROP_VERSION = 0x0002;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_IMAGE_WIDTH = 0x0100;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_IMAGE_LENGTH = 0x0101;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_BITS_PER_SAMPLE = 0x0102;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_COMPRESSION = 0x0103;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_PHOTOMETRIC_INTERP = 0x0106;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_FILL_ORDER = 0x010A;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_DOCUMENT_NAME = 0x010D;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_IMAGE_DESCRIPTION = 0x010E;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_MAKE = 0x010F;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_MODEL = 0x0110;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_SRIP_OFFSET = 0x0111;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_ORIENTATION = 0x0112;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_SAMPLES_PER_PIXEL = 0x0115;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_ROWS_PER_STRIP = 0x0116;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_STRIP_BYTE_COUNTS = 0x0117;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_PLANAR_CONFIGURATION = 0x011C;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_TRANSFER_FUNCTION = 0x012D;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_SOFTWARE = 0x0131;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_DATETIME = 0x0132;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_ARTIST = 0x013B;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_WHITE_POINT = 0x013E;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_PRIMARY_CHROMATICITIES = 0x013F;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_TRANSFER_RANGE = 0x0156;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_JPEG_PROC = 0x0200;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_THUMBNAIL_OFFSET = 0x0201;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_THUMBNAIL_LENGTH = 0x0202;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_Y_CB_CR_COEFFICIENTS = 0x0211;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_Y_CB_CR_SUB_SAMPLING = 0x0212;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_Y_CB_CR_POSITIONING = 0x0213;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_REFERENCE_BLACK_WHITE = 0x0214;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_RELATED_IMAGE_WIDTH = 0x1001;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_RELATED_IMAGE_LENGTH = 0x1002;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_CFA_REPEAT_PATTERN_DIM = 0x828D;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_CFA_PATTERN1 = 0x828E;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_BATTERY_LEVEL = 0x828F;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_COPYRIGHT = 0x8298;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_EXPOSURETIME = 0x829A;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_FNUMBER = 0x829D;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_IPTC_NAA = 0x83BB;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_EXIF_OFFSET = 0x8769;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_INTER_COLOR_PROFILE = 0x8773;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_EXPOSURE_PROGRAM = 0x8822;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_SPECTRAL_SENSITIVITY = 0x8824;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_GPSINFO = 0x8825;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_ISO_EQUIVALENT = 0x8827;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_OECF = 0x8828;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_EXIF_VERSION = 0x9000;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_DATETIME_ORIGINAL = 0x9003;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_DATETIME_DIGITIZED = 0x9004;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_COMPONENTS_CONFIG = 0x9101;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_CPRS_BITS_PER_PIXEL = 0x9102;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_SHUTTERSPEED = 0x9201;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_APERTURE = 0x9202;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_BRIGHTNESS_VALUE = 0x9203;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_EXPOSURE_BIAS = 0x9204;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_MAXAPERTURE = 0x9205;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_SUBJECT_DISTANCE = 0x9206;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_METERING_MODE = 0x9207;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_LIGHT_SOURCE = 0x9208;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_FLASH = 0x9209;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_FOCALLENGTH = 0x920A;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_SUBJECTAREA = 0x9214;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_MAKER_NOTE = 0x927C;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_USERCOMMENT = 0x9286;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_SUBSEC_TIME = 0x9290;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_SUBSEC_TIME_ORIG = 0x9291;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_SUBSEC_TIME_DIG = 0x9292;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
const int TAG_WINXP_TITLE = 0x9c9b; // Windows XP - not part of exif standard.
|
|
shun-iwasawa |
fdbab5 |
const int TAG_WINXP_COMMENT =
|
|
shun-iwasawa |
fdbab5 |
0x9c9c; // Windows XP - not part of exif standard.
|
|
shun-iwasawa |
fdbab5 |
const int TAG_WINXP_AUTHOR = 0x9c9d; // Windows XP - not part of exif standard.
|
|
shun-iwasawa |
fdbab5 |
const int TAG_WINXP_KEYWORDS =
|
|
shun-iwasawa |
fdbab5 |
0x9c9e; // Windows XP - not part of exif standard.
|
|
shun-iwasawa |
fdbab5 |
const int TAG_WINXP_SUBJECT =
|
|
shun-iwasawa |
fdbab5 |
0x9c9f; // Windows XP - not part of exif standard.
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
const int TAG_FLASH_PIX_VERSION = 0xA000;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_COLOR_SPACE = 0xA001;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_PIXEL_X_DIMENSION = 0xA002;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_PIXEL_Y_DIMENSION = 0xA003;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_RELATED_AUDIO_FILE = 0xA004;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_INTEROP_OFFSET = 0xA005;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_FLASH_ENERGY = 0xA20B;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_SPATIAL_FREQ_RESP = 0xA20C;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_FOCAL_PLANE_XRES = 0xA20E;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_FOCAL_PLANE_YRES = 0xA20F;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_FOCAL_PLANE_UNITS = 0xA210;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_SUBJECT_LOCATION = 0xA214;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_EXPOSURE_INDEX = 0xA215;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_SENSING_METHOD = 0xA217;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_FILE_SOURCE = 0xA300;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_SCENE_TYPE = 0xA301;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_CFA_PATTERN = 0xA302;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_CUSTOM_RENDERED = 0xA401;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_EXPOSURE_MODE = 0xA402;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_WHITEBALANCE = 0xA403;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_DIGITALZOOMRATIO = 0xA404;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_FOCALLENGTH_35MM = 0xA405;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_SCENE_CAPTURE_TYPE = 0xA406;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_GAIN_CONTROL = 0xA407;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_CONTRAST = 0xA408;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_SATURATION = 0xA409;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_SHARPNESS = 0xA40A;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_DISTANCE_RANGE = 0xA40C;
|
|
shun-iwasawa |
fdbab5 |
const int TAG_IMAGE_UNIQUE_ID = 0xA420;
|
|
shun-iwasawa |
fdbab5 |
#endif
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
typedef struct {
|
|
shun-iwasawa |
fdbab5 |
unsigned short Tag;
|
|
Campbell Barton |
e4aac6 |
const char *Desc;
|
|
shun-iwasawa |
fdbab5 |
} TagTable_t;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
const TagTable_t TagTable[] = {
|
|
shun-iwasawa |
fdbab5 |
{TAG_X_RESOLUTION, "XResolution"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_Y_RESOLUTION, "YResolution"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_RESOLUTION_UNIT, "ResolutionUnit"},
|
|
shun-iwasawa |
fdbab5 |
#ifdef ReadAllTags
|
|
shun-iwasawa |
fdbab5 |
{TAG_INTEROP_INDEX, "InteropIndex"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_INTEROP_VERSION, "InteropVersion"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_IMAGE_WIDTH, "ImageWidth"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_IMAGE_LENGTH, "ImageLength"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_BITS_PER_SAMPLE, "BitsPerSample"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_COMPRESSION, "Compression"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_PHOTOMETRIC_INTERP, "PhotometricInterpretation"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_FILL_ORDER, "FillOrder"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_DOCUMENT_NAME, "DocumentName"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_IMAGE_DESCRIPTION, "ImageDescription"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_MAKE, "Make"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_MODEL, "Model"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_SRIP_OFFSET, "StripOffsets"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_ORIENTATION, "Orientation"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_SAMPLES_PER_PIXEL, "SamplesPerPixel"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_ROWS_PER_STRIP, "RowsPerStrip"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_STRIP_BYTE_COUNTS, "StripByteCounts"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_PLANAR_CONFIGURATION, "PlanarConfiguration"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_TRANSFER_FUNCTION, "TransferFunction"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_SOFTWARE, "Software"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_DATETIME, "DateTime"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_ARTIST, "Artist"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_WHITE_POINT, "WhitePoint"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_PRIMARY_CHROMATICITIES, "PrimaryChromaticities"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_TRANSFER_RANGE, "TransferRange"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_JPEG_PROC, "JPEGProc"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_THUMBNAIL_OFFSET, "ThumbnailOffset"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_THUMBNAIL_LENGTH, "ThumbnailLength"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_Y_CB_CR_COEFFICIENTS, "YCbCrCoefficients"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_Y_CB_CR_SUB_SAMPLING, "YCbCrSubSampling"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_Y_CB_CR_POSITIONING, "YCbCrPositioning"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_REFERENCE_BLACK_WHITE, "ReferenceBlackWhite"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_RELATED_IMAGE_WIDTH, "RelatedImageWidth"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_RELATED_IMAGE_LENGTH, "RelatedImageLength"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_CFA_REPEAT_PATTERN_DIM, "CFARepeatPatternDim"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_CFA_PATTERN1, "CFAPattern"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_BATTERY_LEVEL, "BatteryLevel"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_COPYRIGHT, "Copyright"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_EXPOSURETIME, "ExposureTime"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_FNUMBER, "FNumber"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_IPTC_NAA, "IPTC/NAA"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_EXIF_OFFSET, "ExifOffset"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_INTER_COLOR_PROFILE, "InterColorProfile"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_EXPOSURE_PROGRAM, "ExposureProgram"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_SPECTRAL_SENSITIVITY, "SpectralSensitivity"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_GPSINFO, "GPS Dir offset"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_ISO_EQUIVALENT, "ISOSpeedRatings"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_OECF, "OECF"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_EXIF_VERSION, "ExifVersion"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_DATETIME_ORIGINAL, "DateTimeOriginal"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_DATETIME_DIGITIZED, "DateTimeDigitized"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_COMPONENTS_CONFIG, "ComponentsConfiguration"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_CPRS_BITS_PER_PIXEL, "CompressedBitsPerPixel"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_SHUTTERSPEED, "ShutterSpeedValue"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_APERTURE, "ApertureValue"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_BRIGHTNESS_VALUE, "BrightnessValue"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_EXPOSURE_BIAS, "ExposureBiasValue"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_MAXAPERTURE, "MaxApertureValue"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_SUBJECT_DISTANCE, "SubjectDistance"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_METERING_MODE, "MeteringMode"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_LIGHT_SOURCE, "LightSource"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_FLASH, "Flash"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_FOCALLENGTH, "FocalLength"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_MAKER_NOTE, "MakerNote"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_USERCOMMENT, "UserComment"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_SUBSEC_TIME, "SubSecTime"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_SUBSEC_TIME_ORIG, "SubSecTimeOriginal"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_SUBSEC_TIME_DIG, "SubSecTimeDigitized"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_WINXP_TITLE, "Windows-XP Title"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_WINXP_COMMENT, "Windows-XP comment"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_WINXP_AUTHOR, "Windows-XP author"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_WINXP_KEYWORDS, "Windows-XP keywords"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_WINXP_SUBJECT, "Windows-XP subject"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_FLASH_PIX_VERSION, "FlashPixVersion"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_COLOR_SPACE, "ColorSpace"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_PIXEL_X_DIMENSION, "ExifImageWidth"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_PIXEL_Y_DIMENSION, "ExifImageLength"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_RELATED_AUDIO_FILE, "RelatedAudioFile"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_INTEROP_OFFSET, "InteroperabilityOffset"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_FLASH_ENERGY, "FlashEnergy"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_SPATIAL_FREQ_RESP, "SpatialFrequencyResponse"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_FOCAL_PLANE_XRES, "FocalPlaneXResolution"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_FOCAL_PLANE_YRES, "FocalPlaneYResolution"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_FOCAL_PLANE_UNITS, "FocalPlaneResolutionUnit"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_SUBJECT_LOCATION, "SubjectLocation"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_EXPOSURE_INDEX, "ExposureIndex"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_SENSING_METHOD, "SensingMethod"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_FILE_SOURCE, "FileSource"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_SCENE_TYPE, "SceneType"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_CFA_PATTERN, "CFA Pattern"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_CUSTOM_RENDERED, "CustomRendered"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_EXPOSURE_MODE, "ExposureMode"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_WHITEBALANCE, "WhiteBalance"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_DIGITALZOOMRATIO, "DigitalZoomRatio"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_FOCALLENGTH_35MM, "FocalLengthIn35mmFilm"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_SUBJECTAREA, "SubjectArea"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_SCENE_CAPTURE_TYPE, "SceneCaptureType"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_GAIN_CONTROL, "GainControl"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_CONTRAST, "Contrast"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_SATURATION, "Saturation"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_SHARPNESS, "Sharpness"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_DISTANCE_RANGE, "SubjectDistanceRange"},
|
|
shun-iwasawa |
fdbab5 |
{TAG_IMAGE_UNIQUE_ID, "ImageUniqueId"},
|
|
shun-iwasawa |
fdbab5 |
#endif
|
|
shun-iwasawa |
fdbab5 |
};
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
const int TAG_TABLE_SIZE = (sizeof(TagTable) / sizeof(TagTable_t));
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
const int TRUE = 1;
|
|
shun-iwasawa |
fdbab5 |
const int FALSE = 0;
|
|
Campbell Barton |
e4aac6 |
} // namespace
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
//--------------------------------------------------------------------------
|
|
shun-iwasawa |
fdbab5 |
// Convert a 16 bit unsigned value from file's native byte order
|
|
shun-iwasawa |
fdbab5 |
//--------------------------------------------------------------------------
|
|
shun-iwasawa |
fdbab5 |
int JpgExifReader::Get16u(void *Short) {
|
|
shun-iwasawa |
fdbab5 |
if (MotorolaOrder) {
|
|
shun-iwasawa |
fdbab5 |
return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
|
|
shun-iwasawa |
fdbab5 |
} else {
|
|
shun-iwasawa |
fdbab5 |
return (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0];
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
//--------------------------------------------------------------------------
|
|
shun-iwasawa |
fdbab5 |
// Convert a 32 bit signed value from file's native byte order
|
|
shun-iwasawa |
fdbab5 |
//--------------------------------------------------------------------------
|
|
shun-iwasawa |
fdbab5 |
int JpgExifReader::Get32s(void *Long) {
|
|
shun-iwasawa |
fdbab5 |
if (MotorolaOrder) {
|
|
shun-iwasawa |
fdbab5 |
return (((char *)Long)[0] << 24) | (((uchar *)Long)[1] << 16) |
|
|
shun-iwasawa |
fdbab5 |
(((uchar *)Long)[2] << 8) | (((uchar *)Long)[3] << 0);
|
|
shun-iwasawa |
fdbab5 |
} else {
|
|
shun-iwasawa |
fdbab5 |
return (((char *)Long)[3] << 24) | (((uchar *)Long)[2] << 16) |
|
|
shun-iwasawa |
fdbab5 |
(((uchar *)Long)[1] << 8) | (((uchar *)Long)[0] << 0);
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
//--------------------------------------------------------------------------
|
|
shun-iwasawa |
fdbab5 |
// Convert a 32 bit unsigned value from file's native byte order
|
|
shun-iwasawa |
fdbab5 |
//--------------------------------------------------------------------------
|
|
shun-iwasawa |
fdbab5 |
unsigned JpgExifReader::Get32u(void *Long) {
|
|
shun-iwasawa |
fdbab5 |
return (unsigned)Get32s(Long) & 0xffffffff;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
//--------------------------------------------------------------------------
|
|
shun-iwasawa |
fdbab5 |
// Display a number as one of its many formats
|
|
shun-iwasawa |
fdbab5 |
//--------------------------------------------------------------------------
|
|
shun-iwasawa |
fdbab5 |
void JpgExifReader::PrintFormatNumber(void *ValuePtr, int Format,
|
|
shun-iwasawa |
fdbab5 |
int ByteCount) {
|
|
shun-iwasawa |
fdbab5 |
int s, n;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
for (n = 0; n < 16; n++) {
|
|
shun-iwasawa |
fdbab5 |
switch (Format) {
|
|
shun-iwasawa |
fdbab5 |
case FMT_SBYTE:
|
|
shun-iwasawa |
fdbab5 |
case FMT_BYTE:
|
|
shun-iwasawa |
fdbab5 |
printf("%02x", *(uchar *)ValuePtr);
|
|
shun-iwasawa |
fdbab5 |
s = 1;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
case FMT_USHORT:
|
|
shun-iwasawa |
fdbab5 |
printf("%d", Get16u(ValuePtr));
|
|
shun-iwasawa |
fdbab5 |
s = 2;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
case FMT_ULONG:
|
|
shun-iwasawa |
fdbab5 |
case FMT_SLONG:
|
|
shun-iwasawa |
fdbab5 |
printf("%d", Get32s(ValuePtr));
|
|
shun-iwasawa |
fdbab5 |
s = 4;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
case FMT_SSHORT:
|
|
shun-iwasawa |
fdbab5 |
printf("%hd", (signed short)Get16u(ValuePtr));
|
|
shun-iwasawa |
fdbab5 |
s = 2;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
case FMT_URATIONAL:
|
|
shun-iwasawa |
fdbab5 |
printf("%u/%u", Get32s(ValuePtr), Get32s(4 + (char *)ValuePtr));
|
|
shun-iwasawa |
fdbab5 |
s = 8;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case FMT_SRATIONAL:
|
|
shun-iwasawa |
fdbab5 |
printf("%d/%d", Get32s(ValuePtr), Get32s(4 + (char *)ValuePtr));
|
|
shun-iwasawa |
fdbab5 |
s = 8;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case FMT_SINGLE:
|
|
shun-iwasawa |
fdbab5 |
printf("%f", (double)*(float *)ValuePtr);
|
|
shun-iwasawa |
fdbab5 |
s = 8;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
case FMT_DOUBLE:
|
|
shun-iwasawa |
fdbab5 |
printf("%f", *(double *)ValuePtr);
|
|
shun-iwasawa |
fdbab5 |
s = 8;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
default:
|
|
shun-iwasawa |
fdbab5 |
printf("Unknown format %d:", Format);
|
|
shun-iwasawa |
fdbab5 |
return;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
ByteCount -= s;
|
|
shun-iwasawa |
fdbab5 |
if (ByteCount <= 0) break;
|
|
shun-iwasawa |
fdbab5 |
printf(", ");
|
|
shun-iwasawa |
fdbab5 |
ValuePtr = (void *)((char *)ValuePtr + s);
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
if (n >= 16) printf("...");
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
//--------------------------------------------------------------------------
|
|
shun-iwasawa |
fdbab5 |
// Evaluate number, be it int, rational, or float from directory.
|
|
shun-iwasawa |
fdbab5 |
//--------------------------------------------------------------------------
|
|
shun-iwasawa |
fdbab5 |
double JpgExifReader::ConvertAnyFormat(void *ValuePtr, int Format) {
|
|
shun-iwasawa |
fdbab5 |
double Value;
|
|
shun-iwasawa |
fdbab5 |
Value = 0;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
switch (Format) {
|
|
shun-iwasawa |
fdbab5 |
case FMT_SBYTE:
|
|
shun-iwasawa |
fdbab5 |
Value = *(signed char *)ValuePtr;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
case FMT_BYTE:
|
|
shun-iwasawa |
fdbab5 |
Value = *(uchar *)ValuePtr;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case FMT_USHORT:
|
|
shun-iwasawa |
fdbab5 |
Value = Get16u(ValuePtr);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
case FMT_ULONG:
|
|
shun-iwasawa |
fdbab5 |
Value = Get32u(ValuePtr);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case FMT_URATIONAL:
|
|
shun-iwasawa |
fdbab5 |
case FMT_SRATIONAL: {
|
|
shun-iwasawa |
fdbab5 |
int Num, Den;
|
|
shun-iwasawa |
fdbab5 |
Num = Get32s(ValuePtr);
|
|
shun-iwasawa |
fdbab5 |
Den = Get32s(4 + (char *)ValuePtr);
|
|
shun-iwasawa |
fdbab5 |
if (Den == 0) {
|
|
shun-iwasawa |
fdbab5 |
Value = 0;
|
|
shun-iwasawa |
fdbab5 |
} else {
|
|
shun-iwasawa |
fdbab5 |
if (Format == FMT_SRATIONAL) {
|
|
shun-iwasawa |
fdbab5 |
Value = (double)Num / Den;
|
|
shun-iwasawa |
fdbab5 |
} else {
|
|
shun-iwasawa |
fdbab5 |
Value = (double)(unsigned)Num / (double)(unsigned)Den;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case FMT_SSHORT:
|
|
shun-iwasawa |
fdbab5 |
Value = (signed short)Get16u(ValuePtr);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
case FMT_SLONG:
|
|
shun-iwasawa |
fdbab5 |
Value = Get32s(ValuePtr);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
// Not sure if this is correct (never seen float used in Exif format)
|
|
shun-iwasawa |
fdbab5 |
case FMT_SINGLE:
|
|
shun-iwasawa |
fdbab5 |
Value = (double)*(float *)ValuePtr;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
case FMT_DOUBLE:
|
|
shun-iwasawa |
fdbab5 |
Value = *(double *)ValuePtr;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
default:
|
|
shun-iwasawa |
fdbab5 |
std::cout << "Illegal format code " << Format << " in Exif header"
|
|
shun-iwasawa |
fdbab5 |
<< std::endl;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
return Value;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
//--------------------------------------------------------------------------
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
void JpgExifReader::process_EXIF(unsigned char *ExifSection,
|
|
shun-iwasawa |
fdbab5 |
unsigned int length) {
|
|
shun-iwasawa |
fdbab5 |
unsigned int FirstOffset;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
#ifdef ReadAllTags
|
|
shun-iwasawa |
fdbab5 |
FocalplaneXRes = 0;
|
|
shun-iwasawa |
fdbab5 |
FocalplaneUnits = 0;
|
|
shun-iwasawa |
fdbab5 |
ExifImageWidth = 0;
|
|
shun-iwasawa |
fdbab5 |
NumOrientations = 0;
|
|
shun-iwasawa |
fdbab5 |
DirWithThumbnailPtrs = NULL;
|
|
shun-iwasawa |
fdbab5 |
#endif
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
if (ShowTags) printf("Exif header %u bytes long\n", length);
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
{ // Check the EXIF header component
|
|
shun-iwasawa |
fdbab5 |
static uchar ExifHeader[] = "Exif\0\0";
|
|
shun-iwasawa |
fdbab5 |
if (memcmp(ExifSection + 2, ExifHeader, 6)) {
|
|
shun-iwasawa |
fdbab5 |
std::cout << "Incorrect Exif header" << std::endl;
|
|
shun-iwasawa |
fdbab5 |
return;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
if (memcmp(ExifSection + 8, "II", 2) == 0) {
|
|
shun-iwasawa |
fdbab5 |
if (ShowTags) printf("Exif section in Intel order\n");
|
|
shun-iwasawa |
fdbab5 |
MotorolaOrder = 0;
|
|
shun-iwasawa |
fdbab5 |
} else {
|
|
shun-iwasawa |
fdbab5 |
if (memcmp(ExifSection + 8, "MM", 2) == 0) {
|
|
shun-iwasawa |
fdbab5 |
if (ShowTags) printf("Exif section in Motorola order\n");
|
|
shun-iwasawa |
fdbab5 |
MotorolaOrder = 1;
|
|
shun-iwasawa |
fdbab5 |
} else {
|
|
shun-iwasawa |
fdbab5 |
std::cout << "Invalid Exif alignment marker." << std::endl;
|
|
shun-iwasawa |
fdbab5 |
return;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
// Check the next value for correctness.
|
|
shun-iwasawa |
fdbab5 |
if (Get16u(ExifSection + 10) != 0x2a) {
|
|
shun-iwasawa |
fdbab5 |
std::cout << "Invalid Exif start (1)" << std::endl;
|
|
shun-iwasawa |
fdbab5 |
return;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
FirstOffset = Get32u(ExifSection + 12);
|
|
shun-iwasawa |
fdbab5 |
if (FirstOffset < 8 || FirstOffset > 16) {
|
|
shun-iwasawa |
fdbab5 |
if (FirstOffset < 16 || FirstOffset > length - 16) {
|
|
shun-iwasawa |
fdbab5 |
std::cout << "invalid offset for first Exif IFD value" << std::endl;
|
|
shun-iwasawa |
fdbab5 |
return;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
// Usually set to 8, but other values valid too.
|
|
shun-iwasawa |
fdbab5 |
std::cout << "Suspicious offset of first Exif IFD value" << std::endl;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
// First directory starts 16 bytes in. All offset are relative to 8 bytes in.
|
|
shun-iwasawa |
fdbab5 |
ProcessExifDir(ExifSection + 8 + FirstOffset, ExifSection + 8, length - 8, 0);
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
#ifdef ReadAllTags
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.ThumbnailAtEnd =
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.ThumbnailOffset >= ImageInfo.LargestExifOffset ? TRUE : FALSE;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
if (DumpExifMap) {
|
|
shun-iwasawa |
fdbab5 |
unsigned a, b;
|
|
shun-iwasawa |
fdbab5 |
printf("Map: %05d- End of exif\n", length - 8);
|
|
shun-iwasawa |
fdbab5 |
for (a = 0; a < length - 8; a += 10) {
|
|
shun-iwasawa |
fdbab5 |
printf("Map: %05d ", a);
|
|
shun-iwasawa |
fdbab5 |
for (b = 0; b < 10; b++) printf(" %02x", *(ExifSection + 8 + a + b));
|
|
shun-iwasawa |
fdbab5 |
printf("\n");
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
// Compute the CCD width, in millimeters.
|
|
shun-iwasawa |
fdbab5 |
if (FocalplaneXRes != 0 && ExifImageWidth != 0) {
|
|
shun-iwasawa |
fdbab5 |
// Note: With some cameras, its not possible to compute this correctly
|
|
shun-iwasawa |
fdbab5 |
// because
|
|
shun-iwasawa |
fdbab5 |
// they don't adjust the indicated focal plane resolution units when using
|
|
shun-iwasawa |
fdbab5 |
// less
|
|
shun-iwasawa |
fdbab5 |
// than maximum resolution, so the CCDWidth value comes out too small.
|
|
shun-iwasawa |
fdbab5 |
// Nothing
|
|
shun-iwasawa |
fdbab5 |
// that Jhad can do about it - its a camera problem.
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.CCDWidth =
|
|
shun-iwasawa |
fdbab5 |
(float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes);
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
if (ImageInfo.FocalLength && ImageInfo.FocalLength35mmEquiv == 0) {
|
|
shun-iwasawa |
fdbab5 |
// Compute 35 mm equivalent focal length based on sensor geometry if we
|
|
shun-iwasawa |
fdbab5 |
// haven't
|
|
shun-iwasawa |
fdbab5 |
// already got it explicitly from a tag.
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.FocalLength35mmEquiv =
|
|
shun-iwasawa |
fdbab5 |
(int)(ImageInfo.FocalLength / ImageInfo.CCDWidth * 36 + 0.5);
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
#endif
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
//--------------------------------------------------------------------------
|
|
shun-iwasawa |
fdbab5 |
// Process one of the nested EXIF directories.
|
|
shun-iwasawa |
fdbab5 |
//--------------------------------------------------------------------------
|
|
shun-iwasawa |
fdbab5 |
void JpgExifReader::ProcessExifDir(unsigned char *DirStart,
|
|
shun-iwasawa |
fdbab5 |
unsigned char *OffsetBase,
|
|
shun-iwasawa |
fdbab5 |
unsigned ExifLength, int NestingLevel) {
|
|
shun-iwasawa |
fdbab5 |
int de;
|
|
shun-iwasawa |
443318 |
#ifdef ReadAllTags
|
|
shun-iwasawa |
fdbab5 |
int a;
|
|
shun-iwasawa |
443318 |
#endif
|
|
shun-iwasawa |
fdbab5 |
int NumDirEntries;
|
|
shun-iwasawa |
fdbab5 |
unsigned ThumbnailOffset = 0;
|
|
shun-iwasawa |
fdbab5 |
unsigned ThumbnailSize = 0;
|
|
shun-iwasawa |
fdbab5 |
char IndentString[25];
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
if (NestingLevel > 4) {
|
|
shun-iwasawa |
fdbab5 |
std::cout << "Maximum Exif directory nesting exceeded (corrupt Exif header)"
|
|
shun-iwasawa |
fdbab5 |
<< std::endl;
|
|
shun-iwasawa |
fdbab5 |
return;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
memset(IndentString, ' ', 25);
|
|
shun-iwasawa |
fdbab5 |
IndentString[NestingLevel * 4] = '\0';
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
NumDirEntries = Get16u(DirStart);
|
|
shun-iwasawa |
fdbab5 |
#define DIR_ENTRY_ADDR(Start, Entry) (Start + 2 + 12 * (Entry))
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
{
|
|
shun-iwasawa |
fdbab5 |
unsigned char *DirEnd;
|
|
shun-iwasawa |
443318 |
DirEnd = DIR_ENTRY_ADDR(DirStart, static_cast<int64_t>(NumDirEntries));</int64_t>
|
|
shun-iwasawa |
fdbab5 |
if (DirEnd + 4 > (OffsetBase + ExifLength)) {
|
|
shun-iwasawa |
fdbab5 |
if (DirEnd + 2 == OffsetBase + ExifLength ||
|
|
shun-iwasawa |
fdbab5 |
DirEnd == OffsetBase + ExifLength) {
|
|
shun-iwasawa |
fdbab5 |
// Version 1.3 of jhead would truncate a bit too much.
|
|
shun-iwasawa |
fdbab5 |
// This also caught later on as well.
|
|
shun-iwasawa |
fdbab5 |
} else {
|
|
shun-iwasawa |
fdbab5 |
std::cout << "Illegally sized Exif subdirectory (" << NumDirEntries
|
|
shun-iwasawa |
fdbab5 |
<< "entries)" << std::endl;
|
|
shun-iwasawa |
fdbab5 |
return;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
if (DumpExifMap) {
|
|
shun-iwasawa |
fdbab5 |
printf("Map: %05u-%05u: Directory\n", (int)(DirStart - OffsetBase),
|
|
shun-iwasawa |
fdbab5 |
(int)(DirEnd + 4 - OffsetBase));
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
if (ShowTags) {
|
|
shun-iwasawa |
fdbab5 |
printf("(dir has %d entries)\n", NumDirEntries);
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
for (de = 0; de < NumDirEntries; de++) {
|
|
shun-iwasawa |
fdbab5 |
int Tag, Format, Components;
|
|
shun-iwasawa |
fdbab5 |
unsigned char *ValuePtr;
|
|
shun-iwasawa |
fdbab5 |
int ByteCount;
|
|
shun-iwasawa |
fdbab5 |
unsigned char *DirEntry;
|
|
shun-iwasawa |
443318 |
DirEntry = DIR_ENTRY_ADDR(DirStart, static_cast<int64_t>(de));</int64_t>
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
Tag = Get16u(DirEntry);
|
|
shun-iwasawa |
fdbab5 |
Format = Get16u(DirEntry + 2);
|
|
shun-iwasawa |
fdbab5 |
Components = Get32u(DirEntry + 4);
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
if ((Format - 1) >= NUM_FORMATS) {
|
|
shun-iwasawa |
fdbab5 |
// (-1) catches illegal zero case as unsigned underflows to positive
|
|
shun-iwasawa |
fdbab5 |
// large.
|
|
shun-iwasawa |
fdbab5 |
std::cout << "Illegal number format " << Format << " for tag " << Tag
|
|
shun-iwasawa |
fdbab5 |
<< " in Exif" << std::endl;
|
|
shun-iwasawa |
fdbab5 |
continue;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
if ((unsigned)Components > 0x10000) {
|
|
shun-iwasawa |
fdbab5 |
std::cout << "Too many components " << Components << " for tag " << Tag
|
|
shun-iwasawa |
fdbab5 |
<< " in Exif";
|
|
shun-iwasawa |
fdbab5 |
continue;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
ByteCount = Components * BytesPerFormat[Format];
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
if (ByteCount > 4) {
|
|
shun-iwasawa |
fdbab5 |
unsigned OffsetVal;
|
|
shun-iwasawa |
fdbab5 |
OffsetVal = Get32u(DirEntry + 8);
|
|
shun-iwasawa |
fdbab5 |
// If its bigger than 4 bytes, the dir entry contains an offset.
|
|
shun-iwasawa |
fdbab5 |
if (OffsetVal + ByteCount > ExifLength) {
|
|
shun-iwasawa |
fdbab5 |
// Bogus pointer offset and / or bytecount value
|
|
shun-iwasawa |
fdbab5 |
std::cout << "Illegal value pointer for tag " << Tag << " in Exif";
|
|
shun-iwasawa |
fdbab5 |
continue;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
ValuePtr = OffsetBase + OffsetVal;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
#ifdef ReadAllTags
|
|
shun-iwasawa |
fdbab5 |
if (OffsetVal > ImageInfo.LargestExifOffset) {
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.LargestExifOffset = OffsetVal;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
#endif
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
if (DumpExifMap) {
|
|
shun-iwasawa |
fdbab5 |
printf("Map: %05u-%05u: Data for tag %04x\n", OffsetVal,
|
|
shun-iwasawa |
fdbab5 |
OffsetVal + ByteCount, Tag);
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
} else {
|
|
shun-iwasawa |
fdbab5 |
// 4 bytes or less and value is in the dir entry itself
|
|
shun-iwasawa |
fdbab5 |
ValuePtr = DirEntry + 8;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
#ifdef ReadAllTags
|
|
shun-iwasawa |
fdbab5 |
if (Tag == TAG_MAKER_NOTE) {
|
|
shun-iwasawa |
fdbab5 |
if (ShowTags) {
|
|
shun-iwasawa |
fdbab5 |
printf("%s Maker note: ", IndentString);
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
// ProcessMakerNote(ValuePtr, ByteCount, OffsetBase, ExifLength);
|
|
shun-iwasawa |
fdbab5 |
continue;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
if (ShowTags) {
|
|
shun-iwasawa |
fdbab5 |
// Show tag name
|
|
shun-iwasawa |
fdbab5 |
for (a = 0;; a++) {
|
|
shun-iwasawa |
fdbab5 |
if (a >= TAG_TABLE_SIZE) {
|
|
shun-iwasawa |
fdbab5 |
printf("%s Unknown Tag %04x Value = ", IndentString, Tag);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
if (TagTable[a].Tag == Tag) {
|
|
shun-iwasawa |
fdbab5 |
printf("%s %s = ", IndentString, TagTable[a].Desc);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
// Show tag value.
|
|
shun-iwasawa |
fdbab5 |
switch (Format) {
|
|
shun-iwasawa |
fdbab5 |
case FMT_BYTE:
|
|
shun-iwasawa |
fdbab5 |
if (ByteCount > 1) {
|
|
shun-iwasawa |
fdbab5 |
printf("%.*ls\n", ByteCount / 2, (wchar_t *)ValuePtr);
|
|
shun-iwasawa |
fdbab5 |
} else {
|
|
shun-iwasawa |
fdbab5 |
PrintFormatNumber(ValuePtr, Format, ByteCount);
|
|
shun-iwasawa |
fdbab5 |
printf("\n");
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case FMT_UNDEFINED:
|
|
Campbell Barton |
e4aac6 |
// Undefined is typically an ascii string.
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case FMT_STRING:
|
|
shun-iwasawa |
fdbab5 |
// String arrays printed without function call (different from int
|
|
shun-iwasawa |
fdbab5 |
// arrays)
|
|
shun-iwasawa |
fdbab5 |
{
|
|
shun-iwasawa |
fdbab5 |
int NoPrint = 0;
|
|
shun-iwasawa |
fdbab5 |
printf("\"");
|
|
shun-iwasawa |
fdbab5 |
for (a = 0; a < ByteCount; a++) {
|
|
shun-iwasawa |
fdbab5 |
if (ValuePtr[a] >= 32) {
|
|
shun-iwasawa |
fdbab5 |
putchar(ValuePtr[a]);
|
|
shun-iwasawa |
fdbab5 |
NoPrint = 0;
|
|
shun-iwasawa |
fdbab5 |
} else {
|
|
shun-iwasawa |
fdbab5 |
// Avoiding indicating too many unprintable characters of
|
|
shun-iwasawa |
fdbab5 |
// proprietary
|
|
shun-iwasawa |
fdbab5 |
// bits of binary information this program may not know how to
|
|
shun-iwasawa |
fdbab5 |
// parse.
|
|
shun-iwasawa |
fdbab5 |
if (!NoPrint && a != ByteCount - 1) {
|
|
shun-iwasawa |
fdbab5 |
putchar('?');
|
|
shun-iwasawa |
fdbab5 |
NoPrint = 1;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
printf("\"\n");
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
default:
|
|
shun-iwasawa |
fdbab5 |
// Handle arrays of numbers later (will there ever be?)
|
|
shun-iwasawa |
fdbab5 |
PrintFormatNumber(ValuePtr, Format, ByteCount);
|
|
shun-iwasawa |
fdbab5 |
printf("\n");
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
#endif
|
|
shun-iwasawa |
fdbab5 |
// Extract useful components of tag
|
|
shun-iwasawa |
fdbab5 |
switch (Tag) {
|
|
shun-iwasawa |
fdbab5 |
#ifdef ReadAllTags
|
|
shun-iwasawa |
fdbab5 |
case TAG_MAKE:
|
|
shun-iwasawa |
fdbab5 |
strncpy(ImageInfo.CameraMake, (char *)ValuePtr,
|
|
shun-iwasawa |
fdbab5 |
ByteCount < 31 ? ByteCount : 31);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_MODEL:
|
|
shun-iwasawa |
fdbab5 |
strncpy(ImageInfo.CameraModel, (char *)ValuePtr,
|
|
shun-iwasawa |
fdbab5 |
ByteCount < 39 ? ByteCount : 39);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_DATETIME_ORIGINAL:
|
|
shun-iwasawa |
fdbab5 |
// If we get a DATETIME_ORIGINAL, we use that one.
|
|
shun-iwasawa |
fdbab5 |
strncpy(ImageInfo.DateTime, (char *)ValuePtr, 19);
|
|
Campbell Barton |
e4aac6 |
// Fallthru...
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_DATETIME_DIGITIZED:
|
|
shun-iwasawa |
fdbab5 |
case TAG_DATETIME:
|
|
shun-iwasawa |
fdbab5 |
if (!isdigit(static_cast<unsigned char="">(ImageInfo.DateTime[0]))) {</unsigned>
|
|
shun-iwasawa |
fdbab5 |
// If we don't already have a DATETIME_ORIGINAL, use whatever
|
|
shun-iwasawa |
fdbab5 |
// time fields we may have.
|
|
shun-iwasawa |
fdbab5 |
strncpy(ImageInfo.DateTime, (char *)ValuePtr, 19);
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
if (ImageInfo.numDateTimeTags >= MAX_DATE_COPIES) {
|
|
shun-iwasawa |
fdbab5 |
std::cout << "More than " << MAX_DATE_COPIES
|
|
shun-iwasawa |
fdbab5 |
<< " date fields in Exif. This is nuts" << std::endl;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.DateTimeOffsets[ImageInfo.numDateTimeTags++] =
|
|
shun-iwasawa |
fdbab5 |
(char *)ValuePtr - (char *)OffsetBase;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_WINXP_COMMENT:
|
|
shun-iwasawa |
fdbab5 |
if (ImageInfo.Comments[0]) { // We already have a jpeg comment.
|
|
shun-iwasawa |
fdbab5 |
// Already have a comment (probably windows comment), skip this one.
|
|
shun-iwasawa |
fdbab5 |
if (ShowTags)
|
|
luz paz |
6454c4 |
printf("Windows XP comment and other comment in header\n");
|
|
shun-iwasawa |
fdbab5 |
break; // Already have a windows comment, skip this one.
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
if (ByteCount > 1) {
|
|
shun-iwasawa |
fdbab5 |
if (ByteCount > MAX_COMMENT_SIZE) ByteCount = MAX_COMMENT_SIZE;
|
|
shun-iwasawa |
fdbab5 |
memcpy(ImageInfo.Comments, ValuePtr, ByteCount);
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.CommentWidthchars = ByteCount / 2;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_USERCOMMENT:
|
|
shun-iwasawa |
fdbab5 |
if (ImageInfo.Comments[0]) { // We already have a jpeg comment.
|
|
shun-iwasawa |
fdbab5 |
// Already have a comment (probably windows comment), skip this one.
|
|
shun-iwasawa |
fdbab5 |
if (ShowTags) printf("Multiple comments in exif header\n");
|
|
shun-iwasawa |
fdbab5 |
break; // Already have a windows comment, skip this one.
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
// Comment is often padded with trailing spaces. Remove these first.
|
|
shun-iwasawa |
fdbab5 |
for (a = ByteCount;;) {
|
|
shun-iwasawa |
fdbab5 |
a--;
|
|
shun-iwasawa |
fdbab5 |
if ((ValuePtr)[a] == ' ') {
|
|
shun-iwasawa |
fdbab5 |
(ValuePtr)[a] = '\0';
|
|
shun-iwasawa |
fdbab5 |
} else {
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
if (a == 0) break;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
// Copy the comment
|
|
shun-iwasawa |
fdbab5 |
{
|
|
Campbell Barton |
e4aac6 |
int msiz = ExifLength - (ValuePtr - OffsetBase);
|
|
shun-iwasawa |
fdbab5 |
if (msiz > ByteCount) msiz = ByteCount;
|
|
shun-iwasawa |
fdbab5 |
if (msiz > MAX_COMMENT_SIZE - 1) msiz = MAX_COMMENT_SIZE - 1;
|
|
shun-iwasawa |
fdbab5 |
if (msiz > 5 && memcmp(ValuePtr, "ASCII", 5) == 0) {
|
|
shun-iwasawa |
fdbab5 |
for (a = 5; a < 10 && a < msiz; a++) {
|
|
shun-iwasawa |
fdbab5 |
int c = (ValuePtr)[a];
|
|
shun-iwasawa |
fdbab5 |
if (c != '\0' && c != ' ') {
|
|
shun-iwasawa |
fdbab5 |
strncpy(ImageInfo.Comments, (char *)ValuePtr + a, msiz - a);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
} else {
|
|
shun-iwasawa |
fdbab5 |
strncpy(ImageInfo.Comments, (char *)ValuePtr, msiz);
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_FNUMBER:
|
|
shun-iwasawa |
fdbab5 |
// Simplest way of expressing aperture, so I trust it the most.
|
|
shun-iwasawa |
fdbab5 |
// (overwrite previously computd value if there is one)
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_APERTURE:
|
|
shun-iwasawa |
fdbab5 |
case TAG_MAXAPERTURE:
|
|
shun-iwasawa |
fdbab5 |
// More relevant info always comes earlier, so only use this field if we
|
|
shun-iwasawa |
fdbab5 |
// don't
|
|
shun-iwasawa |
fdbab5 |
// have appropriate aperture information yet.
|
|
shun-iwasawa |
fdbab5 |
if (ImageInfo.ApertureFNumber == 0) {
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.ApertureFNumber =
|
|
shun-iwasawa |
fdbab5 |
(float)exp(ConvertAnyFormat(ValuePtr, Format) * log(2) * 0.5);
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_FOCALLENGTH:
|
|
shun-iwasawa |
fdbab5 |
// Nice digital cameras actually save the focal length as a function
|
|
shun-iwasawa |
fdbab5 |
// of how farthey are zoomed in.
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.FocalLength = (float)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_SUBJECT_DISTANCE:
|
|
shun-iwasawa |
fdbab5 |
// Inidcates the distacne the autofocus camera is focused to.
|
|
shun-iwasawa |
fdbab5 |
// Tends to be less accurate as distance increases.
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.Distance = (float)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_EXPOSURETIME:
|
|
shun-iwasawa |
fdbab5 |
// Simplest way of expressing exposure time, so I trust it most.
|
|
shun-iwasawa |
fdbab5 |
// (overwrite previously computd value if there is one)
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_SHUTTERSPEED:
|
|
shun-iwasawa |
fdbab5 |
// More complicated way of expressing exposure time, so only use
|
|
shun-iwasawa |
fdbab5 |
// this value if we don't already have it from somewhere else.
|
|
shun-iwasawa |
fdbab5 |
if (ImageInfo.ExposureTime == 0) {
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.ExposureTime =
|
|
shun-iwasawa |
fdbab5 |
(float)(1 / exp(ConvertAnyFormat(ValuePtr, Format) * log(2)));
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_FLASH:
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.FlashUsed = (int)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_ORIENTATION:
|
|
shun-iwasawa |
fdbab5 |
if (NumOrientations >= 2) {
|
|
shun-iwasawa |
fdbab5 |
// Can have another orientation tag for the thumbnail, but if there's
|
|
shun-iwasawa |
fdbab5 |
// a third one, things are strange.
|
|
shun-iwasawa |
fdbab5 |
std::cout << "More than two orientation in Exif" << std::endl;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
OrientationPtr[NumOrientations] = ValuePtr;
|
|
shun-iwasawa |
fdbab5 |
OrientationNumFormat[NumOrientations] = Format;
|
|
shun-iwasawa |
fdbab5 |
if (NumOrientations == 0) {
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
if (ImageInfo.Orientation < 0 || ImageInfo.Orientation > 8) {
|
|
shun-iwasawa |
fdbab5 |
std::cout << "Undefined rotation value " << ImageInfo.Orientation
|
|
shun-iwasawa |
fdbab5 |
<< " in Exif" << std::endl;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
NumOrientations += 1;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_PIXEL_Y_DIMENSION:
|
|
shun-iwasawa |
fdbab5 |
case TAG_PIXEL_X_DIMENSION:
|
|
shun-iwasawa |
fdbab5 |
// Use largest of height and width to deal with images that have been
|
|
shun-iwasawa |
fdbab5 |
// rotated to portrait format.
|
|
shun-iwasawa |
fdbab5 |
a = (int)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
if (ExifImageWidth < a) ExifImageWidth = a;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_FOCAL_PLANE_XRES:
|
|
shun-iwasawa |
fdbab5 |
FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_FOCAL_PLANE_UNITS:
|
|
shun-iwasawa |
fdbab5 |
switch ((int)ConvertAnyFormat(ValuePtr, Format)) {
|
|
shun-iwasawa |
fdbab5 |
case 1:
|
|
shun-iwasawa |
fdbab5 |
FocalplaneUnits = 25.4;
|
|
shun-iwasawa |
fdbab5 |
break; // inch
|
|
shun-iwasawa |
fdbab5 |
case 2:
|
|
shun-iwasawa |
fdbab5 |
// According to the information I was using, 2 means meters.
|
|
shun-iwasawa |
fdbab5 |
// But looking at the Cannon powershot's files, inches is the only
|
|
shun-iwasawa |
fdbab5 |
// sensible value.
|
|
shun-iwasawa |
fdbab5 |
FocalplaneUnits = 25.4;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case 3:
|
|
shun-iwasawa |
fdbab5 |
FocalplaneUnits = 10;
|
|
shun-iwasawa |
fdbab5 |
break; // centimeter
|
|
shun-iwasawa |
fdbab5 |
case 4:
|
|
shun-iwasawa |
fdbab5 |
FocalplaneUnits = 1;
|
|
shun-iwasawa |
fdbab5 |
break; // millimeter
|
|
shun-iwasawa |
fdbab5 |
case 5:
|
|
shun-iwasawa |
fdbab5 |
FocalplaneUnits = .001;
|
|
shun-iwasawa |
fdbab5 |
break; // micrometer
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_EXPOSURE_BIAS:
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_WHITEBALANCE:
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_LIGHT_SOURCE:
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.LightSource = (int)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_METERING_MODE:
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_EXPOSURE_PROGRAM:
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_EXPOSURE_INDEX:
|
|
shun-iwasawa |
fdbab5 |
if (ImageInfo.ISOequivalent == 0) {
|
|
shun-iwasawa |
fdbab5 |
// Exposure index and ISO equivalent are often used interchangeably,
|
|
shun-iwasawa |
fdbab5 |
// so we will do the same in jhead.
|
|
shun-iwasawa |
fdbab5 |
// http://photography.about.com/library/glossary/bldef_ei.htm
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_EXPOSURE_MODE:
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.ExposureMode = (int)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_ISO_EQUIVALENT:
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_DIGITALZOOMRATIO:
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.DigitalZoomRatio = (float)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_THUMBNAIL_OFFSET:
|
|
shun-iwasawa |
fdbab5 |
ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
DirWithThumbnailPtrs = DirStart;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_THUMBNAIL_LENGTH:
|
|
shun-iwasawa |
fdbab5 |
ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.ThumbnailSizeOffset = ValuePtr - OffsetBase;
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_EXIF_OFFSET:
|
|
shun-iwasawa |
fdbab5 |
if (ShowTags) printf("%s Exif Dir:", IndentString);
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_INTEROP_OFFSET:
|
|
shun-iwasawa |
fdbab5 |
if (Tag == TAG_INTEROP_OFFSET && ShowTags)
|
|
shun-iwasawa |
fdbab5 |
printf("%s Interop Dir:", IndentString);
|
|
shun-iwasawa |
fdbab5 |
{
|
|
shun-iwasawa |
fdbab5 |
unsigned char *SubdirStart;
|
|
shun-iwasawa |
fdbab5 |
SubdirStart = OffsetBase + Get32u(ValuePtr);
|
|
shun-iwasawa |
fdbab5 |
if (SubdirStart < OffsetBase || SubdirStart > OffsetBase + ExifLength) {
|
|
shun-iwasawa |
fdbab5 |
std::cout << "Illegal Exif or interop ofset directory link"
|
|
shun-iwasawa |
fdbab5 |
<< std::endl;
|
|
shun-iwasawa |
fdbab5 |
} else {
|
|
shun-iwasawa |
fdbab5 |
ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel + 1);
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
continue;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_GPSINFO:
|
|
shun-iwasawa |
fdbab5 |
if (ShowTags) printf("%s GPS info dir:", IndentString);
|
|
shun-iwasawa |
fdbab5 |
{
|
|
shun-iwasawa |
fdbab5 |
unsigned char *SubdirStart;
|
|
shun-iwasawa |
fdbab5 |
SubdirStart = OffsetBase + Get32u(ValuePtr);
|
|
shun-iwasawa |
fdbab5 |
if (SubdirStart < OffsetBase || SubdirStart > OffsetBase + ExifLength) {
|
|
shun-iwasawa |
fdbab5 |
std::cout << "Illegal GPS directory link in Exif" << std::endl;
|
|
shun-iwasawa |
fdbab5 |
} else {
|
|
shun-iwasawa |
fdbab5 |
// ProcessGpsInfo(SubdirStart, OffsetBase, ExifLength);
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
continue;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_FOCALLENGTH_35MM:
|
|
shun-iwasawa |
fdbab5 |
// The focal length equivalent 35 mm is a 2.2 tag (defined as of April
|
|
shun-iwasawa |
fdbab5 |
// 2002)
|
|
shun-iwasawa |
fdbab5 |
// if its present, use it to compute equivalent focal length instead of
|
|
shun-iwasawa |
fdbab5 |
// computing it from sensor geometry and actual focal length.
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.FocalLength35mmEquiv =
|
|
shun-iwasawa |
fdbab5 |
(unsigned)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_DISTANCE_RANGE:
|
|
shun-iwasawa |
fdbab5 |
// Three possible standard values:
|
|
shun-iwasawa |
fdbab5 |
// 1 = macro, 2 = close, 3 = distant
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.DistanceRange = (int)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
#endif
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_X_RESOLUTION:
|
|
shun-iwasawa |
fdbab5 |
if (NestingLevel ==
|
|
shun-iwasawa |
fdbab5 |
0) { // Only use the values from the top level directory
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.xResolution = (float)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
// if yResolution has not been set, use the value of xResolution
|
|
shun-iwasawa |
fdbab5 |
if (ImageInfo.yResolution == 0.0)
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.yResolution = ImageInfo.xResolution;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_Y_RESOLUTION:
|
|
shun-iwasawa |
fdbab5 |
if (NestingLevel ==
|
|
shun-iwasawa |
fdbab5 |
0) { // Only use the values from the top level directory
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.yResolution = (float)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
// if xResolution has not been set, use the value of yResolution
|
|
shun-iwasawa |
fdbab5 |
if (ImageInfo.xResolution == 0.0)
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.xResolution = ImageInfo.yResolution;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
case TAG_RESOLUTION_UNIT:
|
|
shun-iwasawa |
fdbab5 |
if (NestingLevel ==
|
|
shun-iwasawa |
fdbab5 |
0) { // Only use the values from the top level directory
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.ResolutionUnit = (int)ConvertAnyFormat(ValuePtr, Format);
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
break;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
#ifdef ReadAllTags
|
|
shun-iwasawa |
fdbab5 |
{
|
|
shun-iwasawa |
fdbab5 |
// In addition to linking to subdirectories via exif tags,
|
|
shun-iwasawa |
fdbab5 |
// there's also a potential link to another directory at the end of each
|
|
shun-iwasawa |
fdbab5 |
// directory. this has got to be the result of a committee!
|
|
shun-iwasawa |
fdbab5 |
unsigned char *SubdirStart;
|
|
shun-iwasawa |
fdbab5 |
unsigned Offset;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <=
|
|
shun-iwasawa |
fdbab5 |
OffsetBase + ExifLength) {
|
|
shun-iwasawa |
fdbab5 |
Offset = Get32u(DirStart + 2 + 12 * NumDirEntries);
|
|
shun-iwasawa |
fdbab5 |
if (Offset) {
|
|
shun-iwasawa |
fdbab5 |
SubdirStart = OffsetBase + Offset;
|
|
shun-iwasawa |
fdbab5 |
if (SubdirStart > OffsetBase + ExifLength || SubdirStart < OffsetBase) {
|
|
shun-iwasawa |
fdbab5 |
if (SubdirStart > OffsetBase &&
|
|
shun-iwasawa |
fdbab5 |
SubdirStart < OffsetBase + ExifLength + 20) {
|
|
shun-iwasawa |
fdbab5 |
// Jhead 1.3 or earlier would crop the whole directory!
|
|
shun-iwasawa |
fdbab5 |
// As Jhead produces this form of format incorrectness,
|
|
shun-iwasawa |
fdbab5 |
// I'll just let it pass silently
|
|
shun-iwasawa |
fdbab5 |
if (ShowTags)
|
|
shun-iwasawa |
fdbab5 |
printf("Thumbnail removed with Jhead 1.3 or earlier\n");
|
|
shun-iwasawa |
fdbab5 |
} else {
|
|
shun-iwasawa |
fdbab5 |
std::cout << "Illegal subdirectory link in Exif header"
|
|
shun-iwasawa |
fdbab5 |
<< std::endl;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
} else {
|
|
shun-iwasawa |
fdbab5 |
if (SubdirStart <= OffsetBase + ExifLength) {
|
|
shun-iwasawa |
fdbab5 |
if (ShowTags) printf("%s Continued directory ", IndentString);
|
|
shun-iwasawa |
fdbab5 |
ProcessExifDir(SubdirStart, OffsetBase, ExifLength,
|
|
shun-iwasawa |
fdbab5 |
NestingLevel + 1);
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
if (Offset > ImageInfo.LargestExifOffset) {
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.LargestExifOffset = Offset;
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
} else {
|
|
shun-iwasawa |
fdbab5 |
// The exif header ends before the last next directory pointer.
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
if (ThumbnailOffset) {
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.ThumbnailAtEnd = FALSE;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
if (DumpExifMap) {
|
|
shun-iwasawa |
fdbab5 |
printf("Map: %05d-%05d: Thumbnail\n", ThumbnailOffset,
|
|
shun-iwasawa |
fdbab5 |
ThumbnailOffset + ThumbnailSize);
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
if (ThumbnailOffset <= ExifLength) {
|
|
shun-iwasawa |
fdbab5 |
if (ThumbnailSize > ExifLength - ThumbnailOffset) {
|
|
shun-iwasawa |
fdbab5 |
// If thumbnail extends past exif header, only save the part that
|
|
shun-iwasawa |
fdbab5 |
// actually exists. Canon's EOS viewer utility will do this - the
|
|
shun-iwasawa |
fdbab5 |
// thumbnail extracts ok with this hack.
|
|
shun-iwasawa |
fdbab5 |
ThumbnailSize = ExifLength - ThumbnailOffset;
|
|
shun-iwasawa |
fdbab5 |
if (ShowTags) printf("Thumbnail incorrectly placed in header\n");
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
// The thumbnail pointer appears to be valid. Store it.
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.ThumbnailOffset = ThumbnailOffset;
|
|
shun-iwasawa |
fdbab5 |
ImageInfo.ThumbnailSize = ThumbnailSize;
|
|
shun-iwasawa |
fdbab5 |
|
|
shun-iwasawa |
fdbab5 |
if (ShowTags) {
|
|
shun-iwasawa |
fdbab5 |
printf("Thumbnail size: %u bytes\n", ThumbnailSize);
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
}
|
|
shun-iwasawa |
fdbab5 |
#endif
|
|
shun-iwasawa |
fdbab5 |
}
|