//------------------------------------------------ //--- 010 Editor v2.0 Binary Template // // File: JPG.bt // Authors: Mor FTP // E-mail: morftp AT hotmail DOT com // Version: 1.6.2 // Purpose: Template for JPG image files. // Category: Image // File Mask: *.jpg,*.jpeg // ID Bytes: FF D8 FF // History: // 1.6.2 2016-11-29 Bartosz Dziewonski: Search for end of file marker forwards rather than backwards. // Data after the marker may contain bytes that look just like the marker itself. // Also, use FindFirst() for better performance. // 1.6.1 2016-10-18 Bartosz Dziewonski: Don't fail when garbage bytes are present // between JPEG sections. // 1.6 2016-10-18 SweetScape: Handle when end of file marker is not found. // 1.5 2016-01-28 Pergamon: Added Sof3 support and set padded bytes color to silver. // 1.4.1 2016-06-14 Bartosz Dziewonski: Don't fail when parsing IFD where the offset of data for // final entry is before the structure offset. // 1.4 2016-01-28 SweetScape: Updated header for repository submission, added open attribute. // 1.3 2014-11-03 SweetScape: Fixed using FTell instead of Ftell. // 1.2 2012-10-04 dxp: Added JPEG-LS marker structure. // 1.1 2009-03-14 Kuang-che Wu: Fix parse fail if encounter unknown APP1, // fix uShort typo, // parse inlined EXIF data correctly, // recognize more sections and fields, especially EXIF tags, GPS tags, and CIFF tags // and many improvements. // 1.0 Mor FTP: Initial release. // // This is a detailed JPEG File analysis. // Features // 1. Huffmann and quantization tables. // 2. Exif (APP1) information including jpeg and other thubnail images // 3. SOS, SOF0, JIFF and APP0 sections // // Note : This code doesn't parse all known sections. The reson is the application sections // contain camera specific information and this information sometimes is not public or // related to the camera and not important for image display softwares. // // New Features: Parses MakerNote for casio qv-r62 // // references: // JPEG http://www.w3.org/Graphics/JPEG/itu-t81.pdf // JFIF http://www.w3.org/Graphics/JPEG/jfif3.pdf // EXIF http://www.exif.org/Exif2-2.PDF // CIFF http://xyrion.org/ciff/CIFFspecV1R04.pdf // exiftool http://www.sno.phy.queensu.ca/~phil/exiftool/ // JPEG-LS http://www.itu.int/rec/T-REC-T.87-199806-I/en //-------------------------------------- // set left to right for both endian LittleEndian(); BitfieldLeftToRight(); BigEndian(); BitfieldLeftToRight(); local quad JpegFileEnd = 0; local int colorId = 0; local int colorSelect = 0; local DWORD clr = 0; local DWORD jetMap[6*3] = { // blue, red green 0x0000cc,0x0000ff,0x0033ff,0x0066ff,0x0099ff,0x00ccff, 0x00ffff,0x33ffcc,0x66ff99,0x99ff66,0xccff33,0xffff00, 0xffcc00,0xff9900,0xff6600,0xff3300,0xff0000,0xcc0000 }; local char CameraMake[32]; local char CameraModel[40]; local string stack_IFD_dirtype = ""; enum IFD_dirtype { IFD_TYPE_EXIF = 1, IFD_TYPE_GEOTAG, IFD_TYPE_CASIO_QV_R62, }; // ------------------------------------------------------------ // helper functions void Stack_push(string &s, int x) { s += (char)x; } void Stack_pop(string &s) { s = SubStr(s, 0, Strlen(s) - 1); } int Stack_top(string &s) { return s[Strlen(s) - 1]; } string ReadStringN(int64 pos, int n) { local uchar s[n]; ReadBytes(s, pos, n); return s; } // ------------------------------------------------------------ void ChangeColor(byte bChangeColor) { if(bChangeColor == 1) {colorSelect++; colorId = 0;} clr = jetMap[(colorSelect%3)*6+(colorId%6)]; SetBackColor(clr); //Printf("clrIdx = [%d %d], RGB(%d,%d,%d)\n",colorSelect,colorId,(clr>>16),(clr>>8)&0x00FF,clr&0x0000FF); colorId++; } // ------------------------------------------------------------ // JPEG typedef enum tagID { M_SOF0 = 0xFFC0, // Start Of Frame N M_SOF1,// N indicates which compression process M_SOF2,// Only SOF0-SOF2 are now in common use M_SOF3, M_DHT, //Huffman Table M_SOF5, M_SOF6, M_SOF7, M_JPG, M_SOF9, M_SOF10, M_SOF11, M_DAC = 0xffcc, M_SOF13, M_SOF14, M_SOF15, M_RST0 = 0xffd0, M_RST1, M_RST2, M_RST3, M_RST4, M_RST5, M_RST6, M_RST7, M_SOI = 0xFFD8, // Start Of Image M_EOI,// End Of Image M_SOS,// Start Of Scan (begins compressed data) M_DQT, M_DNL, M_DRI, M_DHP, M_EXP, M_APP0 = 0xFFE0, // Jfif marker M_APP1,// Exif marker M_APP2, M_APP3, M_APP4, M_APP5, M_APP6, M_APP7, M_APP8, M_APP9, M_APP10, M_APP11, M_APP12, M_APP13, M_APP14, M_APP15, M_JPG0 = 0xfff0, M_JPG1, M_JPG2, M_JPG3, M_JPG4, M_JPG5, M_JPG6, M_JPGLS, M_JPG8, M_JPG9, M_JPG10, M_JPG11, M_JPG12, M_JPG13, M_JPG14, M_JPG15, M_COMM = 0xFFFE // Comment } M_ID ; // ------------------------------------------------------------ // EXIF tags typedef enum tagExifTag { /////////////////////////////////// Format Comp Description InteropIndex = 0x0001, InteropVersion = 0x0002, SubfileType = 0x00fe, OldSubfileType = 0x00ff, ImageWidth = 0x0100, ImageHeight = 0x0101, BitsPerSample = 0x0102, Compression = 0x0103, PhotometricInterpretation = 0x0106, Thresholding = 0x0107, CellWidth = 0x0108, CellLength = 0x0109, FillOrder = 0x010a, DocumentName = 0x010d, ImageDescription = 0x010e, Make = 0x010f, Model = 0x0110, StripOffsets = 0x0111, Orientation = 0x0112, SamplesPerPixel = 0x0115, RowsPerStrip = 0x0116, StripByteCounts = 0x0117, MinSampleValue = 0x0118, MaxSampleValue = 0x0119, XResolution = 0x011a, YResolution = 0x011b, PlanarConfiguration = 0x011c, PageName = 0x011d, XPosition = 0x011e, YPosition = 0x011f, FreeOffsets = 0x0120, FreeByteCounts = 0x0121, GrayResponseUnit = 0x0122, GrayResponseCurve = 0x0123, T4Options = 0x0124, T6Options = 0x0125, ResolutionUnit = 0x0128, PageNumber = 0x0129, ColorResponseUnit = 0x012c, TransferFunction = 0x012d, Software = 0x0131, ModifyDate = 0x0132, Artist = 0x013b, HostComputer = 0x013c, Predictor = 0x013d, WhitePoint = 0x013e, PrimaryChromaticities = 0x013f, ColorMap = 0x0140, HalftoneHints = 0x0141, TileWidth = 0x0142, TileLength = 0x0143, TileOffsets = 0x0144, TileByteCounts = 0x0145, BadFaxLines = 0x0146, CleanFaxData = 0x0147, ConsecutiveBadFaxLines = 0x0148, SubIFD = 0x014a, InkSet = 0x014c, InkNames = 0x014d, NumberofInks = 0x014e, DotRange = 0x0150, TargetPrinter = 0x0151, ExtraSamples = 0x0152, SampleFormat = 0x0153, SMinSampleValue = 0x0154, SMaxSampleValue = 0x0155, TransferRange = 0x0156, ClipPath = 0x0157, XClipPathUnits = 0x0158, YClipPathUnits = 0x0159, Indexed = 0x015a, JPEGTables = 0x015b, OPIProxy = 0x015f, GlobalParametersIFD = 0x0190, ProfileType = 0x0191, FaxProfile = 0x0192, CodingMethods = 0x0193, VersionYear = 0x0194, ModeNumber = 0x0195, Decode = 0x01b1, DefaultImageColor = 0x01b2, JPEGProc = 0x0200, ThumbnailOffset = 0x0201, ThumbnailLength = 0x0202, JPEGRestartInterval = 0x0203, JPEGLosslessPredictors = 0x0205, JPEGPointTransforms = 0x0206, JPEGQTables = 0x0207, JPEGDCTables = 0x0208, JPEGACTables = 0x0209, YCbCrCoefficients = 0x0211, YCbCrSubSampling = 0x0212, YCbCrPositioning = 0x0213, ReferenceBlackWhite = 0x0214, StripRowCounts = 0x022f, ApplicationNotes = 0x02bc, RelatedImageFileFormat = 0x1000, RelatedImageWidth = 0x1001, RelatedImageLength = 0x1002, ImageID = 0x800d, WangAnnotation = 0x80a4, Matteing = 0x80e3, DataType = 0x80e4, ImageDepth = 0x80e5, TileDepth = 0x80e6, Model2 = 0x827d, CFARepeatPatternDim = 0x828d, CFAPattern2 = 0x828e, BatteryLevel = 0x828f, Copyright = 0x8298, ExposureTime = 0x829a, FNumber = 0x829d, PixelScale = 0x830e, IPTC_NAA = 0x83bb, IntergraphPacketData = 0x8474, IntergraphFlagRegisters = 0x847f, IntergraphMatrix = 0x8480, ModelTiePoint = 0x8482, Site = 0x84e0, ColorSequence = 0x84e1, IT8Header = 0x84e2, RasterPadding = 0x84e3, BitsPerRunLength = 0x84e4, BitsPerExtendedRunLength = 0x84e5, ColorTable = 0x84e6, ImageColorIndicator = 0x84e7, BackgroundColorIndicator = 0x84e8, ImageColorValue = 0x84e9, BackgroundColorValue = 0x84ea, PixelIntensityRange = 0x84eb, TransparencyIndicator = 0x84ec, ColorCharacterization = 0x84ed, HCUsage = 0x84ee, IPTC_NAA2 = 0x8568, ModelTransform = 0x85d8, PhotoshopSettings = 0x8649, ExifOffset = 0x8769, ICC_Profile = 0x8773, ImageLayer = 0x87ac, GeoTiffDirectory = 0x87af, GeoTiffDoubleParams = 0x87b0, GeoTiffAsciiParams = 0x87b1, ExposureProgram = 0x8822, SpectralSensitivity = 0x8824, GPSInfo = 0x8825, ISO = 0x8827, OptoElectricConvFactor = 0x8828, Interlace = 0x8829, TimeZoneOffset = 0x882a, SelfTimerMode = 0x882b, FaxRecvParams = 0x885c, FaxSubAddress = 0x885d, FaxRecvTime = 0x885e, ExifVersion = 0x9000, DateTimeOriginal = 0x9003, CreateDate = 0x9004, ComponentsConfiguration = 0x9101, CompressedBitsPerPixel = 0x9102, ShutterSpeedValue = 0x9201, ApertureValue = 0x9202, BrightnessValue = 0x9203, ExposureCompensation = 0x9204, MaxApertureValue = 0x9205, SubjectDistance = 0x9206, MeteringMode = 0x9207, LightSource = 0x9208, Flash = 0x9209, FocalLength = 0x920a, FlashEnergy = 0x920b, SpatialFrequencyResponse = 0x920c, Noise = 0x920d, FocalPlaneXResolution = 0x920e, FocalPlaneYResolution = 0x920f, FocalPlaneResolutionUnit = 0x9210, ImageNumber = 0x9211, SecurityClassification = 0x9212, ImageHistory = 0x9213, SubjectLocation = 0x9214, ExposureIndex = 0x9215, TIFF_EPStandardID = 0x9216, SensingMethod = 0x9217, StoNits = 0x923f, MakerNote = 0x927c, UserComment = 0x9286, SubSecTime = 0x9290, SubSecTimeOriginal = 0x9291, SubSecTimeDigitized = 0x9292, ImageSourceData = 0x935c, XPTitle = 0x9c9b, XPComment = 0x9c9c, XPAuthor = 0x9c9d, XPKeywords = 0x9c9e, XPSubject = 0x9c9f, FlashpixVersion = 0xa000, ColorSpace = 0xa001, ExifImageWidth = 0xa002, ExifImageLength = 0xa003, RelatedSoundFile = 0xa004, InteropOffset = 0xa005, FlashEnergy2 = 0xa20b, SpatialFrequencyResponse2 = 0xa20c, Noise2 = 0xa20d, FocalPlaneXResolution2 = 0xa20e, FocalPlaneYResolution2 = 0xa20f, FocalPlaneResolutionUnit2 = 0xa210, ImageNumber2 = 0xa211, SecurityClassification2 = 0xa212, ImageHistory2 = 0xa213, SubjectLocation2 = 0xa214, ExposureIndex2 = 0xa215, TIFF_EPStandardID2 = 0xa216, SensingMethod2 = 0xa217, FileSource = 0xa300, SceneType = 0xa301, CFAPattern = 0xa302, CustomRendered = 0xa401, ExposureMode = 0xa402, WhiteBalance = 0xa403, DigitalZoomRatio = 0xa404, FocalLengthIn35mmFormat = 0xa405, SceneCaptureType = 0xa406, GainControl = 0xa407, Contrast = 0xa408, Saturation = 0xa409, Sharpness = 0xa40a, DeviceSettingDescription = 0xa40b, SubjectDistanceRange = 0xa40c, ImageUniqueID = 0xa420, GDALMetadata = 0xa480, GDALNoData = 0xa481, Gamma = 0xa500, FilmProductCode = 0xc350, ImageSourceEK = 0xc351, CaptureConditionsPAR = 0xc352, CameraOwner = 0xc353, SerialNumber = 0xc354, UserSelectGroupTitle = 0xc355, DealerIDNumber = 0xc356, CaptureDeviceFID = 0xc357, EnvelopeNumber = 0xc358, FrameNumber = 0xc359, FilmCategory = 0xc35a, FilmGencode = 0xc35b, ModelAndVersion = 0xc35c, FilmSize = 0xc35d, SBA_RGBShifts = 0xc35e, SBAInputImageColorspace = 0xc35f, SBAInputImageBitDepth = 0xc360, SBAExposureRecord = 0xc361, UserAdjSBA_RGBShifts = 0xc362, ImageRotationStatus = 0xc363, RollGuidElements = 0xc364, MetadataNumber = 0xc365, EditTagArray = 0xc366, Magnification = 0xc367, NativeXResolution = 0xc36c, NativeYResolution = 0xc36d, KodakEffectsIFD = 0xc36e, KodakBordersIFD = 0xc36f, NativeResolutionUnit = 0xc37a, SourceImageDirectory = 0xc418, SourceImageFileName = 0xc419, SourceImageVolumeName = 0xc41a, OceScanjobDesc = 0xc427, OceApplicationSelector = 0xc428, OceIDNumber = 0xc429, OceImageLogic = 0xc42a, Annotations = 0xc44f, PrintQuality = 0xc46c, ImagePrintStatus = 0xc46e, PrintIM = 0xc4a5, DNGVersion = 0xc612, DNGBackwardVersion = 0xc613, UniqueCameraModel = 0xc614, LocalizedCameraModel = 0xc615, CFAPlaneColor = 0xc616, CFALayout = 0xc617, LinearizationTable = 0xc618, BlackLevelRepeatDim = 0xc619, BlackLevel = 0xc61a, BlackLevelDeltaH = 0xc61b, BlackLevelDeltaV = 0xc61c, WhiteLevel = 0xc61d, DefaultScale = 0xc61e, DefaultCropOrigin = 0xc61f, DefaultCropSize = 0xc620, ColorMatrix1 = 0xc621, ColorMatrix2 = 0xc622, CameraCalibration1 = 0xc623, CameraCalibration2 = 0xc624, ReductionMatrix1 = 0xc625, ReductionMatrix2 = 0xc626, AnalogBalance = 0xc627, AsShotNeutral = 0xc628, AsShotWhiteXY = 0xc629, BaselineExposure = 0xc62a, BaselineNoise = 0xc62b, BaselineSharpness = 0xc62c, BayerGreenSplit = 0xc62d, LinearResponseLimit = 0xc62e, DNGCameraSerialNumber = 0xc62f, DNGLensInfo = 0xc630, ChromaBlurRadius = 0xc631, AntiAliasStrength = 0xc632, ShadowScale = 0xc633, DNGPrivateData = 0xc634, MakerNoteSafety = 0xc635, CalibrationIlluminant1 = 0xc65a, CalibrationIlluminant2 = 0xc65b, BestQualityScale = 0xc65c, AliasLayerMetadata = 0xc660, OwnerName = 0xfde8, SerialNumber2 = 0xfde9, Lens = 0xfdea, RawFile = 0xfe4c, Converter = 0xfe4d, WhiteBalance2 = 0xfe4e, Exposure = 0xfe51, Shadows = 0xfe52, Brightness = 0xfe53, Contrast2 = 0xfe54, Saturation2 = 0xfe55, Sharpness2 = 0xfe56, Smoothness = 0xfe57, MoireFilter = 0xfe58, } ExifTag; enum GeoTag { GPSVersionID, GPSLatitudeRef, GPSLatitude, GPSLongitudeRef, GPSLongitude, GPSAltitudeRef, GPSAltitude, GPSTimeStamp, GPSSatellites, GPSStatus, GPSMeasureMode, GPSDOP, GPSSpeedRef, GPSSpeed, GPSTrackRef, GPSTrack, GPSImgDirectionRef, GPSImgDirection, GPSMapDatum, GPSDestLatitudeRef, GPSDestLatitude, GPSDestLongitudeRef, GPSDestLongitude, GPSDestBearingRef, GPSDestBearing, GPSDestDistanceRef, GPSDestDistance, GPSProcessingMehotd, GPSAreaInformation, GPSDateStamp, GPSDifferential, }; // ------------------------------------------------------------ // Casio tag typedef enum tagCasioTag2 { PreviewThumbnailDimensions = 0x0002,//Numeric 2 values - x,y dimensions in pixels PreviewThumbnailSize = 0x0003,//Numeric Size in bytes PreviewThumbnailOffset = 0x0004,//Numeric Offset of Preview Thumbnail CSQualityMode = 0x0008,//Numeric Lookup 1 = Fine 2 = Super Fine CsImageSize = 0x0009,//Numeric Lookup 0 = 640 x 480 pixels 4 = 1600 x 1200 pixels 5 = 2048 x 1536 pixels 20 = 2288 x 1712 pixels 21 = 2592 x 1944 pixels 22 = 2304 x 1728 pixels 36 = 3008 x 2008 pixels CSFocusMode = 0x000D,//Numeric Lookup 0 = Normal 1 = Macro CsIsoSensitivity = 0x0014,//Numeric Lookup 3 = 50 4 = 64 6 = 100 9 = 200 CsWhiteBalance = 0x0019,//Numeric Lookup 0 = Auto 1 = Daylight 2 = Shade 3 = Tungsten 4 = Fluorescent 5 = Manual CsFocalLength = 0x001D,//Numeric Units are tenths of a millimetre CsSaturation = 0x001F,//Numeric Lookup 0 = -1 1 = Normal 2 = +1 CsContrast = 0x0020,//Numeric Lookup 0 = -1 1 = Normal 2 = +1 CsSharpness = 0x0021,//Numeric Lookup 0 = -1 1 = Normal 2 = +1 CsPrintImageMatchingInfo = 0x0E00,//PIM See Print Image Matching for specification CasioPreviewThumbnail = 0x2000,//Numeric Alternate thumbnail offset CsWhiteBalanceBias = 0x2011,//Numeric CsFlashMode = 0x2012,//Numeric Lookup 12 = Flash 0 = Manual 1 = Auto? 4 = Flash? CsObjectDistance = 0x2022,//Numeric Units are millimetres CsFlashDistance = 0x2034,//Numeric 0 = Off CsRecordMode = 0x3000,//Numeric Lookup 2 = Normal Mode CsSelfTimer = 0x3001,//Numeric Lookup 1 = Off? CsQuality = 0x3002,//Numeric Lookup 3 = Fine CsMeteringMode2 = 0x3003,//Numeric Lookup 1 = Fixation 6 = Multi-Area Auto Focus CsTimeZone = 0x3006,//String CsBestshotMode = 0x3007,//Numeric Lookup 0 = Off 1 = On? CsCCDISOSensitivity = 0x3014,//Numeric CsColourMode = 0x3015,//Numeric Lookup 0 = Off CsEnhancement = 0x3016,//Numeric Lookup 0 = Off CsFilter = 0x3017,//Numeric Lookup 0 = Off } CasioTag2; // ------------------------------------------------------------ // Canon CIFF typedef uint32 DC_UINT32; typedef int32 DC_SINT32; typedef float DC_FLOAT32; typedef struct tgCifDirEntry { uint16 storage_method : 2; // 00 in heap, 01 in entry uint16 data_type : 3; uint16 id_code : 11 ; if (storage_method == kStg_InHeapSpace) { DWORD sData; // Data Size (Bytes) DWORD oData; // Data Offset } else { switch (data_type << 11 | id_code) { case kTC_ImageFormat: DC_UINT32 fileFormat; DC_FLOAT32 targetCompressionRatio; break; default: byte data[8]; break; } } } CifDirEntry ; enum CIFFTagStg { kStg_InHeapSpace, kStg_InRecordEntry, kStg_reversed2, kStg_reversed3, }; enum CIFFTagDataType { kDT_BYTE = 0x0000, kDT_ASCII = 0x0800, kDT_WORD = 0x1000, kDT_DWORD = 0x1800, kDT_BYTE2 = 0x2000, kDT_HeapTypeProperty1 = 0x2800, kDT_HeapTypeProperty2 = 0x3000, }; enum CIFFTagType { kTC_Null = 0, kTC_Free, kTC_ExFree, kTC_Description = 0x0805,//kDT_ASCII | 0x0005, kTC_ModelName = 0x080a,//kDT_ASCII | 0x000a, kTC_FirmwareVersion = 0x080b,//kDT_ASCII | 0x000b, kTC_ComponentVersion = 0x080c,//kDT_ASCII | 0x000c, kTC_ROMOperationMode = 0x080d,//kDT_ASCII | 0x000d, kTC_OwnerName = 0x0810,//kDT_ASCII | 0x0010, kTC_ImageFileName = 0x0816,//kDT_ASCII | 0x0016, kTC_ThumbnailFileName = 0x0817,//kDT_ASCII | 0x0017, kTC_TargetImageType = 0x100a,//kDT_WORD | 0x000a, kTC_SR_ReleaseMethod = 0x1010,//kDT_WORD | 0x0010, kTC_SR_ReleaseTiming = 0x1011,//kDT_WORD | 0x0011, kTC_ReleaseSetting = 0x1016,//kDT_WORD | 0x0016, kTC_BodySensitivity = 0x101c,//kDT_WORD | 0x001c, kTC_ImageFormat = 0x1803,//kDT_DWORD | 0x0003, kTC_RecordID = 0x1804,//kDT_DWORD | 0x0004, kTC_SelfTimerTime = 0x1806,//kDT_DWORD | 0x0006, kTC_SR_TargetDistanceSetting = 0x1807,//kDT_DWORD | 0x0007, kTC_BodyID = 0x180b,//kDT_DWORD | 0x000b, kTC_CapturedTime = 0x180e,//kDT_DWORD | 0x000e, kTC_ImageSpec = 0x1810,//kDT_DWORD | 0x0010, kTC_SR_EF = 0x1813,//kDT_DWORD | 0x0013, kTC_MI_EV = 0x1814,//kDT_DWORD | 0x0014, kTC_SerialNumber = 0x1817,//kDT_DWORD | 0x0017, kTC_CameraObject = 0x2807,//0x0007 | kDT_HeapTypeProperty1, kTC_ShootingRecord = 0x3002,//0x0002 | kDT_HeapTypeProperty2, kTC_MeasuredInfo = 0x3003,//0x0003 | kDT_HeapTypeProperty2, kTC_CameraSpecification = 0x3004,//0x0004 | kDT_HeapTypeProperty2, }; string ReadCifDirEntry(CifDirEntry &e) { local string s; local uint16 tc = e.data_type << 11 | e.id_code; local CIFFTagType x = (CIFFTagType) tc; local CIFFTagStg stg = (CIFFTagStg)e.storage_method; local CIFFTagDataType dt = (CIFFTagDataType)(e.data_type << 11); if (EnumToString(x) != "") { SPrintf(s, "%s, %s", EnumToString(stg), EnumToString(x)); } else { SPrintf(s, "%s, %s, 0x%x", EnumToString(stg), EnumToString(dt), e.id_code); } return s; } typedef struct tgCDir { ChangeColor(0); //Printf("off %#Lx doff %#Lx dsz %#Lx\n",cifOffset , cDirOffset ,cDirSize); local quad myOffset = cDirOffset; local DWORD S = ReadInt(myOffset + cDirSize - 4); FSeek(cDirOffset + S); //Printf("S @ %#x = %#x FTell %#Lx",S,myOffset + cDirSize - 4,FTell()); WORD nDirEntry; //Printf(" nEntry %#x\n",nDirEntry); ChangeColor(0); CifDirEntry dirEntries[nDirEntry]; DWORD szValues; // = S local int i; for(i=0;i>1]; } str2Bytes; break; case kDT_DWORD: union { DWORD dwData[dirEntries[i].sData>>2]; DWORD flData[dirEntries[i].sData>>2]; } str4Bytes; break; case kDT_HeapTypeProperty1: case kDT_HeapTypeProperty2: cDirOffset = dirEntries[i].oData + myOffset; cDirSize = dirEntries[i].sData; struct CDIR subDir; break; default: struct { char uData[dirEntries[i].sData]; } strUnknown; break; } break; } } //else value is samaller than 8 byte so it is stored in sData and oData of CifDirEntry struct } } CDIR; // ------------------------------------------------------------ // JPEG APPx segments const local int dataFormatLength[13] = {0,1,1,2,4,8,1,1,2,4,8,4,8}; typedef enum tagDataFormat { uByte = 1, ascString, uShort, uLong, uRatio, sByte, undefined = 7, sShort, sLong = 9, sRatio, sFloat, dFloat, } DataFormat; typedef struct tgDIRENTRY { ChangeColor(0); switch (Stack_top(stack_IFD_dirtype)) { case IFD_TYPE_EXIF: ExifTag tagNumber; break; case IFD_TYPE_GEOTAG: GeoTag tagNumber; break; case IFD_TYPE_CASIO_QV_R62: CasioTag2 tagNumber; break; } DataFormat dataFormat; DWORD nComponent; local int j = 0; local int length = -1; if (1 <= dataFormat && dataFormat < 13) length = dataFormatLength[dataFormat] * nComponent; else { //Warning("unknown dataFormat = %x", dataFormat); } if (1 <= dataFormat && dataFormat < 13 && 0 <= length && length <= 4) { switch (tagNumber) { case ExposureProgram: enum { EP_Not_defined, EP_Manual, EP_Normal_program, EP_Aperture_priority, EP_Shutter_priority, EP_Creative_program, EP_Action_program, EP_Portrait_mode, EP_Landscape_mode, } ExposureProgram; break; case MeteringMode: enum { MM_unknown, MM_Average, MM_CenterWeightedAverage, MM_Spot, MM_MultiSpot, MM_Pattern, MM_Partial, MM_other = 255, } MeteringMode; break; case LightSource: enum { LS_unknown, LS_Daylight, LS_Fluorescent, LS_Tungsten, LS_Flash, LS_Fine_weather = 9, LS_Cloudy_weather, LS_Shade, LS_Daylight_fluorescent, LS_Day_white_fluorescent, LS_Cool_white_fluorescent, LS_White_fluorescent, LS_Standard_light_A, LS_Standard_light_B, LS_Standard_light_C, LS_D55, LS_D65, LS_D75, LS_D50, LS_ISO_studio_tungsten, LS_other_light_scoure = 255, } LightSource; break; case Flash: short unused : 9; short red_eye_mode : 1; short flash_function : 1; short flash_mode : 2; short flash_return : 2; short flash_fired : 1; break; case ExposureMode: enum { EM_Auto_exposure, EM_Manual_exposure, EM_Auto_bracket, } ExposureMode; break; case WhiteBalance: enum { WB_Auto_white_balance, WB_Manual_white_balance, } WhiteBalance; break; case SceneCaptureType: enum { SCT_Standard, SCT_Landscape, SCT_Portrait, SCT_Night_scene, } SceneCaptureType; break; case SubjectDistanceRange: enum { SDR_unknown, SDR_Macro, SDR_Close_view, SDR_Distant_view, } SubjectDistanceRange; break; default: switch (dataFormat) { case uByte: struct { uchar oneByteData[nComponent]; } strAscii; break; case ascString: struct StrAscii1 { char oneByteData[nComponent]; } strAscii ; break; case undefined: struct { uchar oneByteData[nComponent]; } strAscii; break; case uShort: for (j = 0; j < nComponent; j++) ushort usValue; break; case uLong: if (nComponent == 1) ulong ulValue; break; case sByte: struct { char sBValue[nComponent]; } strSByte; break; case sShort: struct { short sisValue[nComponent]; } strSShort; break; case sLong: if (nComponent == 1) ulong siLValue; break; case sFloat: if (nComponent == 1) float flValue; break; } break; } if (length != 4) uchar padding[4 - length]; } else { DWORD offsetData; } } DIRENTRY; string ReadDirEntry(DIRENTRY &entry) { local char no[50]; SPrintf(no,"Tag# = 0x%x (%s)",entry.tagNumber, EnumToString(entry.tagNumber)); return no; } typedef struct tgIFD { WORD nDirEntry; DIRENTRY dirEntry[nDirEntry]; DWORD nextIFDoffset; local int i = 0; local int pos = FTell(); for(i=0;i; break; case undefined: struct { uchar oneByteData[dirEntry[i].nComponent]; } strAscii; break; case uShort: struct { ushort usValue[dirEntry[i].nComponent]; } strUShort; break; case uLong: struct { ulong ulValue[dirEntry[i].nComponent]; } strULong; break; case uRatio: struct URatio { struct { DWORD num; DWORD den; } uRValue[dirEntry[i].nComponent]; } strURatio ; break; case sByte: struct { char sBValue[dirEntry[i].nComponent]; } strSByte; break; case sShort: struct { short sisValue[dirEntry[i].nComponent]; } strSShort; break; case sLong: struct { ulong siLValue[dirEntry[i].nComponent]; } strSLong; break; case sRatio: struct { struct { int num; int den; } siRValue[dirEntry[i].nComponent]; } strSRatio; break; case sFloat: struct { float flValue[dirEntry[i].nComponent]; } strsFloat; break; case dFloat: struct { double dFValue[dirEntry[i].nComponent]; } strdFloat; break; } } } for(i=0;i; switch (extension_code) { case 0x10: local quad JpegFileEnd2 = JpegFileEnd; JpegFileEnd = FTell() + szSection - 8; struct JPGFILE thumbnail; JpegFileEnd = JpegFileEnd2; break; case 0x11: ubyte xThumbnail; ubyte yThumbnail; struct { uchar r, g, b; } palette[256]; uchar pixel[szSection - 8]; break; case 0x13: ubyte xThumbnail; ubyte yThumbnail; struct { uchar r, g, b; } pixel[(ushort)xThumbnail * yThumbnail]; break; default: //Warning("Unknown JFXX"); char unknown[szSection - 8]; } } else if((ReadStringN(FTell(), 2) == "II" || ReadStringN(FTell(), 2) == "MM") && ReadStringN(FTell() + 6, 8) == "HEAPJPGM") { // Canon CIFF local quad cDirSize = 0; local quad cDirOffset = 0; local quad cifOffset = FTell(); //CIFF Header char ByteOrder[2]; if(!Strncmp(ByteOrder,"II",2)) LittleEndian(); DWORD HeaderLength; char type[4]; // "HEAP" char subtype[4]; // "JPGM" //Ciff Directory cDirOffset = HeaderLength + cifOffset; cDirSize = szSection - 2 - HeaderLength; CDIR APP0_Ciff; BigEndian(); FSeek(cifOffset + szSection - 2); } else { //Warning("Unknown APP0"); char unknown[szSection - 2]; } } APP0; typedef struct tgAPP1 { M_ID marker; WORD szSection; if (ReadStringN(FTell(), 5) == "Exif") { char EXIF[6]; local quad offset = FTell(); byte align[2]; if(align[0]=='I') { LittleEndian(); } WORD tagMark; // 0x002a DWORD offsetFirstIFD; if(offsetFirstIFD!=8) FSeek(offset + offsetFirstIFD); ChangeColor(0); Stack_push(stack_IFD_dirtype, IFD_TYPE_EXIF); IFD ifdMainImage; Stack_pop(stack_IFD_dirtype); if(ifdMainImage.nextIFDoffset) { FSeek(offset + ifdMainImage.nextIFDoffset); ChangeColor(0); Stack_push(stack_IFD_dirtype, IFD_TYPE_EXIF); IFD ifdThumbnailImage; Stack_pop(stack_IFD_dirtype); local int i = 0; local int thumbOffset = 0; local int thumbLength = 0; local int compression = 10; for(i;i 0) { struct { enum { DK_End, DK_Quality, DK_Comment, DK_Copyright, } tag; if (tag == DK_End) break; uint16 len; switch (tag) { case DK_End: break; case DK_Quality: uint32 value; break; case DK_Comment: uint32 count; char comment[len - 4]; break; case DK_Copyright: uint32 count; char comment[len - 4]; break; default: char unknown[len]; break; } } entry; if (entry.tag == DK_End) break; s -= sizeof(entry); } } else { //Warning("Unknown APP12"); char unknown[szSection - 2]; } } APP12; typedef struct tagAPP13 { M_ID marker; WORD szSection; if (ReadStringN(FTell(), 14) == "Photoshop 3.0") { // refer to ExifTool Photoshop.pm char photoshop30[14]; local int remainsize = szSection - 16; while (remainsize > 0) { struct { char type[4]; if (type == "8BIM") { } else if (type == "PHUT" || type == "DCSR" || type == "AgHg") { } else { char unknown[remainsize - 4]; break; } enum { PS_IPTCData = 0x0404, PS_JPEG_Quality = 0x0406, PS_PhotoshopBGRThumbnail = 0x0409, PS_CopyrightFlag = 0x040a, PS_URL = 0x040b, PS_PhotoshopThumbnail = 0x040c, PS_ICC_Profile = 0x040f, PS_GlobalAltitude = 0x0419, PS_EXIFInfo = 0x0422, PS_XMP = 0x0424, PS_IPTCDigest = 0x0425, PS_ClippingPathName = 0x0bb7, } tag; uchar namelen; if (namelen) char name[namelen]; if (namelen % 2 != 1) char padding; uint32 size; if (size) char data[size]; if (size % 2 != 0) char padding; } block; remainsize -= sizeof(block); } } else if (ReadStringN(FTell(), 9) == "Adobe_CM") { char adobe_cm[9]; uchar AdobeCMType; if (szSection != 12) char unknown[szSection - 12]; } else { //Warning("Unknown APP13"); char unknown[szSection - 2]; } } APP13; typedef struct tagAPP14 { M_ID marker; WORD szSection; if (ReadStringN(FTell(), 5) == "Adobe") { // http://partners.adobe.com/public/developer/en/ps/sdk/5116.DCT_Filter.pdf char adobe[5]; uint16 version; uint16 flag0; uint16 flag1; uchar color_transform_code; if (FTell() < szSection + startof(szSection)) char unknown[szSection + startof(szSection) - FTell()]; } else { //Warning("Unknown APP14"); char unknown[szSection - 2]; } } APP14; // ------------------------------------------------------------ // JPEG segments typedef struct tagSOS { M_ID marker; WORD szSection; ubyte nr_comp; ChangeColor(0); struct COMPSOS { ubyte AC:4; ubyte DC:4; } comp[nr_comp]; uchar Ss; uchar Se; uchar Ah : 4; uchar Al : 4; } SOS; typedef struct tagUNK { M_ID UnknownMarker; //Warning("Unknown Section 0x%08x %s", UnknownMarker, EnumToString(UnknownMarker)); WORD szSection; if (FTell() + szSection - 2 >= JpegFileEnd) { Warning("unknown section length pass the end of jpeg file"); ubyte unknown[JpegFileEnd - FTell()]; } else { ubyte unknown[szSection-2]; } } UNKNOWN; typedef struct tagDHT { M_ID marker; WORD szSection; local WORD huffsz = szSection - 2; while(huffsz > 0) { ChangeColor(0); struct Huffmann_Table { ubyte htInfo; ubyte length[16]; local int sumLen = 0; local int i = 0; for(i;i<16;i++) { sumLen += length[i]; } ubyte HTV[sumLen]; } huff_table; huffsz -= sizeof(huff_table); } } DHT; typedef struct tagDQT { M_ID marker; WORD szSection; local WORD qtsz = szSection - 2; while(qtsz > 0) { ChangeColor(0); struct QuanTable { uchar Pq : 4; uchar Tq : 4; if (Pq == 0) byte qTable[64]; else uint16 qTable[64]; } qtable; qtsz -= sizeof(qtable); } } DQT; typedef struct tagDRI { M_ID marker; WORD szSection; WORD Ri; } DRI; typedef struct tagDHP { M_ID marker; WORD szSection; uchar P; uint16 Y; uint16 X; uchar Nf; struct { uchar id; uchar h_factor : 4; uchar v_factor : 4; uchar Tq; } component_param[Nf]; } DHP; typedef struct tgSOFx { M_ID marker; WORD szSection; ubyte precision; WORD Y_image; WORD X_image; ubyte nr_comp; ChangeColor(0); struct COMPS { ubyte compId; ubyte Horz:4; ubyte Vert:4; ubyte compNr; } comp[nr_comp]; } SOFx; typedef struct tagCOMMENT { M_ID CommentMarker; WORD szSection; char comment[szSection-2]; local char comments[szSection-1] = {0}; local int i = 0; Memcpy(comments,comment,szSection-2); for(i=0;i; typedef struct tagJPGLS { M_ID marker; WORD szSection; uchar precision ; WORD Y_numlines; WORD X_numcols; uchar Nf ; uchar C_compID; uchar sub_sampling; uchar Tq ; if (11 < szSection) uchar uknown[szSection - 11]; } JPGLS; string ReadComment( COMMENT &com ) { return com.comment; } JpegFileEnd = FileSize(); // ------------------------------------------------------------ // JPEG file SetBackColor(jetMap[0]); typedef struct tgJPGFile { local int was_bigendian = IsBigEndian(); BigEndian(); local WORD NextMarker; local quad fpos2; local quad endpos; local byte bEOI = 0; while(FTell() < JpegFileEnd && !bEOI) { // skip optional 0xff before marker while (ReadUShort(FTell()) == 0xffff) FSkip(1); NextMarker = ReadUShort(FTell()); switch(NextMarker) { case M_SOI: M_ID SOIMarker; Printf("Start of Image Marker\n"); break; case M_SOS: SOS scanStart; Printf("Start of Scan Marker\n"); fpos2 = FindFirst(M_EOI, true, false, FINDMETHOD_NORMAL, 0.0, 1, FTell()); if( fpos2 < 0 ) { char unterminatedScanData[JpegFileEnd - FTell()]; Printf("Missing End of File marker\n"); } else { char scanData[fpos2 - FTell()]; ChangeColor(1); M_ID EOIMarker; Printf("End of File Image\n"); if(JpegFileEnd - FTell()) char unknownPadding[JpegFileEnd - FTell()] ; } bEOI = 1; break; case M_APP0: APP0 app0; break; case M_DHT: DHT dht; break; case M_DQT: DQT dqt; break; case M_DRI: DRI dri; break; case M_DHP: DHP dhp; break; case M_SOF0: SOFx sof0; break; case M_SOF1: SOFx sof1; break; case M_SOF2: SOFx sof2; break; case M_SOF3: SOFx sof3; break; case M_APP1: APP1 app1; break; case M_APP2: APP2 app2; break; case M_APP12: APP12 app12; break; case M_APP13: APP13 app13; break; case M_APP14: APP14 app14; break; case M_COMM: COMMENT comment; break; case M_JPGLS: JPGLS jpgls; break; default: if (ReadUByte(FTell()) == 0xff) { UNKNOWN unknownSection; } else { char garbage; } break; } ChangeColor(!bEOI); } if (!was_bigendian) LittleEndian(); } JPGFILE; JPGFILE jpgfile ;