12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273 |
- #------------------------------------------------------------------------------
- # File: CanonVRD.pm
- #
- # Description: Read/write Canon VRD and DR4 information
- #
- # Revisions: 2006/10/30 - P. Harvey Created
- # 2007/10/23 - PH Added new VRD 3.0 tags
- # 2008/08/29 - PH Added new VRD 3.4 tags
- # 2008/12/02 - PH Added new VRD 3.5 tags
- # 2010/06/18 - PH Support variable-length CustomPictureStyle data
- # 2010/09/14 - PH Added r/w support for XMP in VRD
- # 2015/05/16 - PH Added DR4 support (DPP 4.1.50.0)
- #
- # References: 1) Bogdan private communication (Canon DPP v3.4.1.1)
- # 2) Gert Kello private communiation (DPP 3.8)
- #------------------------------------------------------------------------------
- package Image::ExifTool::CanonVRD;
- use strict;
- use vars qw($VERSION);
- use Image::ExifTool qw(:DataAccess :Utils);
- use Image::ExifTool::Canon;
- $VERSION = '1.28';
- sub ProcessCanonVRD($$;$);
- sub WriteCanonVRD($$;$);
- sub ProcessEditData($$$);
- sub ProcessIHL($$$);
- sub ProcessIHLExif($$$);
- sub ProcessDR4($$;$);
- sub SortDR4($$);
- # map for adding directories to VRD
- my %vrdMap = (
- XMP => 'CanonVRD',
- CanonVRD => 'VRD',
- );
- my %noYes = (
- PrintConvColumns => 2,
- PrintConv => { 0 => 'No', 1 => 'Yes' },
- );
- # DR4 format codes
- my %vrdFormat = (
- 1 => 'int32u',
- 2 => 'string',
- 8 => 'int32u',
- 9 => 'int32s',
- 13 => 'double',
- 33 => 'int32u', # (array)
- 38 => 'double', # (array)
- # 254 => 'undef', ?
- 255 => 'undef',
- );
- # empty VRD header/footer for creating VRD from scratch
- my $blankHeader = "CANON OPTIONAL DATA\0\0\x01\0\0\0\0\0\0";
- my $blankFooter = "CANON OPTIONAL DATA\0" . ("\0" x 42) . "\xff\xd9";
- # main tag table blocks in CanonVRD trailer (ref PH)
- %Image::ExifTool::CanonVRD::Main = (
- WRITE_PROC => \&WriteCanonVRD,
- PROCESS_PROC => \&ProcessCanonVRD,
- NOTES => q{
- Canon Digital Photo Professional writes VRD (Recipe Data) information as a
- trailer record to JPEG, TIFF, CRW and CR2 images, or as stand-alone VRD or
- DR4 files. The tags listed below represent information found in these
- records. The complete VRD/DR4 data record may be accessed as a block using
- the Extra 'CanonVRD' or 'CanonDR4' tag, but this tag is not extracted or
- copied unless specified explicitly.
- },
- 0xffff00f4 => {
- Name => 'EditData',
- SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::Edit' },
- },
- 0xffff00f5 => {
- Name => 'IHLData',
- SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::IHL' },
- },
- 0xffff00f6 => {
- Name => 'XMP',
- Flags => [ 'Binary', 'Protected' ],
- Writable => 'undef', # allow writing/deleting as a block
- SubDirectory => {
- DirName => 'XMP',
- TagTable => 'Image::ExifTool::XMP::Main',
- },
- },
- 0xffff00f7 => {
- Name => 'Edit4Data',
- SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::Edit4' },
- },
- );
- # the VRD edit information is divided into sections
- %Image::ExifTool::CanonVRD::Edit = (
- WRITE_PROC => \&ProcessEditData,
- PROCESS_PROC => \&ProcessEditData,
- VARS => { ID_LABEL => 'Index' }, # change TagID label in documentation
- NOTES => 'Canon VRD edit information.',
- 0 => {
- Name => 'VRD1',
- Size => 0x272, # size of version 1.0 edit information in bytes
- SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::Ver1' },
- },
- 1 => {
- Name => 'VRDStampTool',
- Size => 0, # size is variable, and obtained from int32u at directory start
- SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::StampTool' },
- },
- 2 => {
- Name => 'VRD2',
- Size => undef, # size is the remaining edit data
- SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::Ver2' },
- },
- );
- # Canon DPP version 4 edit information
- %Image::ExifTool::CanonVRD::Edit4 = (
- WRITE_PROC => \&ProcessEditData,
- PROCESS_PROC => \&ProcessEditData,
- VARS => { ID_LABEL => 'Index' }, # change TagID label in documentation
- NOTES => 'Canon DPP version 4 edit information.',
- 0 => {
- Name => 'DR4',
- Size => undef, # size is the remaining edit data
- SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::DR4' },
- },
- );
- # "IHL Created Optional Item Data" tags (not yet writable)
- %Image::ExifTool::CanonVRD::IHL = (
- PROCESS_PROC => \&ProcessIHL,
- TAG_PREFIX => 'VRD_IHL',
- GROUPS => { 2 => 'Image' },
- 1 => [
- # this contains edited TIFF-format data, with an original IFD at 0x0008
- # and an edited IFD with offset given in the TIFF header.
- {
- Name => 'IHL_EXIF',
- Condition => '$self->Options("ExtractEmbedded")',
- SubDirectory => {
- TagTable => 'Image::ExifTool::Exif::Main',
- ProcessProc => \&ProcessIHLExif,
- },
- },{
- Name => 'IHL_EXIF',
- Notes => q{
- extracted as a block if the Unknown option is used, or processed as the
- first sub-document with the ExtractEmbedded option
- },
- Binary => 1,
- Unknown => 1,
- },
- ],
- # 2 - written by DPP 3.0.2.6, and it looks something like edit data,
- # but I haven't decoded it yet - PH
- 3 => {
- # (same size as the PreviewImage with DPP 3.0.2.6)
- Name => 'ThumbnailImage',
- Groups => { 2 => 'Preview' },
- Binary => 1,
- },
- 4 => {
- Name => 'PreviewImage',
- Groups => { 2 => 'Preview' },
- Binary => 1,
- },
- 5 => {
- Name => 'RawCodecVersion',
- ValueConv => '$val =~ s/\0.*//s; $val', # truncate string at null
- },
- 6 => {
- Name => 'CRCDevelParams',
- Binary => 1,
- Unknown => 1,
- },
- );
- # VRD version 1 tags (ref PH)
- %Image::ExifTool::CanonVRD::Ver1 = (
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
- WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
- CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
- WRITABLE => 1,
- FIRST_ENTRY => 0,
- GROUPS => { 2 => 'Image' },
- DATAMEMBER => [ 0x002 ], # necessary for writing
- #
- # RAW image adjustment
- #
- 0x002 => {
- Name => 'VRDVersion',
- Format => 'int16u',
- Writable => 0,
- DataMember => 'VRDVersion',
- RawConv => '$$self{VRDVersion} = $val',
- PrintConv => '$val =~ s/^(\d)(\d*)(\d)$/$1.$2.$3/; $val',
- },
- 0x006 => {
- Name => 'WBAdjRGGBLevels',
- Format => 'int16u[4]',
- },
- 0x018 => {
- Name => 'WhiteBalanceAdj',
- Format => 'int16u',
- PrintConvColumns => 2,
- PrintConv => {
- 0 => 'Auto',
- 1 => 'Daylight',
- 2 => 'Cloudy',
- 3 => 'Tungsten',
- 4 => 'Fluorescent',
- 5 => 'Flash',
- 8 => 'Shade',
- 9 => 'Kelvin',
- 30 => 'Manual (Click)',
- 31 => 'Shot Settings',
- },
- },
- 0x01a => {
- Name => 'WBAdjColorTemp',
- Format => 'int16u',
- },
- # 0x01c similar to 0x006
- 0x024 => {
- Name => 'WBFineTuneActive',
- Format => 'int16u',
- %noYes,
- },
- 0x028 => {
- Name => 'WBFineTuneSaturation',
- Format => 'int16u',
- },
- 0x02c => {
- Name => 'WBFineTuneTone',
- Format => 'int16u',
- },
- 0x02e => {
- Name => 'RawColorAdj',
- Format => 'int16u',
- PrintConv => {
- 0 => 'Shot Settings',
- 1 => 'Faithful',
- 2 => 'Custom',
- },
- },
- 0x030 => {
- Name => 'RawCustomSaturation',
- Format => 'int32s',
- },
- 0x034 => {
- Name => 'RawCustomTone',
- Format => 'int32s',
- },
- 0x038 => {
- Name => 'RawBrightnessAdj',
- Format => 'int32s',
- ValueConv => '$val / 6000',
- ValueConvInv => 'int($val * 6000 + ($val < 0 ? -0.5 : 0.5))',
- PrintConv => 'sprintf("%.2f",$val)',
- PrintConvInv => '$val',
- },
- 0x03c => {
- Name => 'ToneCurveProperty',
- Format => 'int16u',
- PrintConvColumns => 2,
- PrintConv => {
- 0 => 'Shot Settings',
- 1 => 'Linear',
- 2 => 'Custom 1',
- 3 => 'Custom 2',
- 4 => 'Custom 3',
- 5 => 'Custom 4',
- 6 => 'Custom 5',
- },
- },
- # 0x040 usually "10 9 2"
- 0x07a => {
- Name => 'DynamicRangeMin',
- Format => 'int16u',
- },
- 0x07c => {
- Name => 'DynamicRangeMax',
- Format => 'int16u',
- },
- # 0x0c6 usually "10 9 2"
- #
- # RGB image adjustment
- #
- 0x110 => {
- Name => 'ToneCurveActive',
- Format => 'int16u',
- %noYes,
- },
- 0x113 => {
- Name => 'ToneCurveMode',
- PrintConv => { 0 => 'RGB', 1 => 'Luminance' },
- },
- 0x114 => {
- Name => 'BrightnessAdj',
- Format => 'int8s',
- },
- 0x115 => {
- Name => 'ContrastAdj',
- Format => 'int8s',
- },
- 0x116 => {
- Name => 'SaturationAdj',
- Format => 'int16s',
- },
- 0x11e => {
- Name => 'ColorToneAdj',
- Notes => 'in degrees, so -1 is the same as 359',
- Format => 'int32s',
- },
- 0x126 => {
- Name => 'LuminanceCurvePoints',
- Format => 'int16u[21]',
- PrintConv => 'Image::ExifTool::CanonVRD::ToneCurvePrint($val)',
- PrintConvInv => 'Image::ExifTool::CanonVRD::ToneCurvePrintInv($val)',
- },
- 0x150 => {
- Name => 'LuminanceCurveLimits',
- Notes => '4 numbers: input and output highlight and shadow points',
- Format => 'int16u[4]',
- },
- 0x159 => {
- Name => 'ToneCurveInterpolation',
- PrintConv => { 0 => 'Curve', 1 => 'Straight' },
- },
- 0x160 => {
- Name => 'RedCurvePoints',
- Format => 'int16u[21]',
- PrintConv => 'Image::ExifTool::CanonVRD::ToneCurvePrint($val)',
- PrintConvInv => 'Image::ExifTool::CanonVRD::ToneCurvePrintInv($val)',
- },
- # 0x193 same as 0x159
- 0x19a => {
- Name => 'GreenCurvePoints',
- Format => 'int16u[21]',
- PrintConv => 'Image::ExifTool::CanonVRD::ToneCurvePrint($val)',
- PrintConvInv => 'Image::ExifTool::CanonVRD::ToneCurvePrintInv($val)',
- },
- # 0x1cd same as 0x159
- 0x1d4 => {
- Name => 'BlueCurvePoints',
- Format => 'int16u[21]',
- PrintConv => 'Image::ExifTool::CanonVRD::ToneCurvePrint($val)',
- PrintConvInv => 'Image::ExifTool::CanonVRD::ToneCurvePrintInv($val)',
- },
- 0x18a => {
- Name => 'RedCurveLimits',
- Format => 'int16u[4]',
- },
- 0x1c4 => {
- Name => 'GreenCurveLimits',
- Format => 'int16u[4]',
- },
- 0x1fe => {
- Name => 'BlueCurveLimits',
- Format => 'int16u[4]',
- },
- # 0x207 same as 0x159
- 0x20e => {
- Name => 'RGBCurvePoints',
- Format => 'int16u[21]',
- PrintConv => 'Image::ExifTool::CanonVRD::ToneCurvePrint($val)',
- PrintConvInv => 'Image::ExifTool::CanonVRD::ToneCurvePrintInv($val)',
- },
- 0x238 => {
- Name => 'RGBCurveLimits',
- Format => 'int16u[4]',
- },
- # 0x241 same as 0x159
- 0x244 => {
- Name => 'CropActive',
- Format => 'int16u',
- %noYes,
- },
- 0x246 => {
- Name => 'CropLeft',
- Notes => 'crop coordinates in original unrotated image',
- Format => 'int16u',
- },
- 0x248 => {
- Name => 'CropTop',
- Format => 'int16u',
- },
- 0x24a => {
- Name => 'CropWidth',
- Format => 'int16u',
- },
- 0x24c => {
- Name => 'CropHeight',
- Format => 'int16u',
- },
- 0x25a => {
- Name => 'SharpnessAdj',
- Format => 'int16u',
- },
- 0x260 => {
- Name => 'CropAspectRatio',
- Format => 'int16u',
- PrintConv => {
- 0 => 'Free',
- 1 => '3:2',
- 2 => '2:3',
- 3 => '4:3',
- 4 => '3:4',
- 5 => 'A-size Landscape',
- 6 => 'A-size Portrait',
- 7 => 'Letter-size Landscape',
- 8 => 'Letter-size Portrait',
- 9 => '4:5',
- 10 => '5:4',
- 11 => '1:1',
- 12 => 'Circle',
- 65535 => 'Custom',
- },
- },
- 0x262 => {
- Name => 'ConstrainedCropWidth',
- Format => 'float',
- PrintConv => 'sprintf("%.7g",$val)',
- PrintConvInv => '$val',
- },
- 0x266 => {
- Name => 'ConstrainedCropHeight',
- Format => 'float',
- PrintConv => 'sprintf("%.7g",$val)',
- PrintConvInv => '$val',
- },
- 0x26a => {
- Name => 'CheckMark',
- Format => 'int16u',
- PrintConv => {
- 0 => 'Clear',
- 1 => 1,
- 2 => 2,
- 3 => 3,
- },
- },
- 0x26e => {
- Name => 'Rotation',
- Format => 'int16u',
- PrintConv => {
- 0 => 0,
- 1 => 90,
- 2 => 180,
- 3 => 270,
- },
- },
- 0x270 => {
- Name => 'WorkColorSpace',
- Format => 'int16u',
- PrintConv => {
- 0 => 'sRGB',
- 1 => 'Adobe RGB',
- 2 => 'Wide Gamut RGB',
- 3 => 'Apple RGB',
- 4 => 'ColorMatch RGB',
- },
- },
- # (VRD 1.0.0 edit data ends here -- 0x272 bytes)
- );
- # VRD Stamp Tool tags (ref PH)
- %Image::ExifTool::CanonVRD::StampTool = (
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
- GROUPS => { 2 => 'Image' },
- 0x00 => {
- Name => 'StampToolCount',
- Format => 'int32u',
- },
- );
- # VRD version 2 and 3 tags (ref PH)
- %Image::ExifTool::CanonVRD::Ver2 = (
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
- WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
- CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
- WRITABLE => 1,
- FIRST_ENTRY => 0,
- FORMAT => 'int16s',
- DATAMEMBER => [ 0x58, 0xdc, 0xdf, 0xe0 ], # (required for DataMember and var-format tags)
- IS_SUBDIR => [ 0xe0 ],
- GROUPS => { 2 => 'Image' },
- NOTES => 'Tags added in DPP version 2.0 and later.',
- 0x02 => {
- Name => 'PictureStyle',
- PrintConvColumns => 2,
- PrintConv => {
- 0 => 'Standard',
- 1 => 'Portrait',
- 2 => 'Landscape',
- 3 => 'Neutral',
- 4 => 'Faithful',
- 5 => 'Monochrome',
- 6 => 'Unknown?', # PH (maybe in-camera custom picture style?)
- 7 => 'Custom',
- },
- },
- 0x03 => { Name => 'IsCustomPictureStyle', %noYes },
- # 0x08: 3
- # 0x09: 4095
- # 0x0a: 0
- # 0x0b: 4095
- # 0x0c: 0
- 0x0d => 'StandardRawColorTone',
- 0x0e => 'StandardRawSaturation',
- 0x0f => 'StandardRawContrast',
- 0x10 => { Name => 'StandardRawLinear', %noYes },
- 0x11 => 'StandardRawSharpness',
- 0x12 => 'StandardRawHighlightPoint',
- 0x13 => 'StandardRawShadowPoint',
- 0x14 => 'StandardOutputHighlightPoint', #2
- 0x15 => 'StandardOutputShadowPoint', #2
- 0x16 => 'PortraitRawColorTone',
- 0x17 => 'PortraitRawSaturation',
- 0x18 => 'PortraitRawContrast',
- 0x19 => { Name => 'PortraitRawLinear', %noYes },
- 0x1a => 'PortraitRawSharpness',
- 0x1b => 'PortraitRawHighlightPoint',
- 0x1c => 'PortraitRawShadowPoint',
- 0x1d => 'PortraitOutputHighlightPoint',
- 0x1e => 'PortraitOutputShadowPoint',
- 0x1f => 'LandscapeRawColorTone',
- 0x20 => 'LandscapeRawSaturation',
- 0x21 => 'LandscapeRawContrast',
- 0x22 => { Name => 'LandscapeRawLinear', %noYes },
- 0x23 => 'LandscapeRawSharpness',
- 0x24 => 'LandscapeRawHighlightPoint',
- 0x25 => 'LandscapeRawShadowPoint',
- 0x26 => 'LandscapeOutputHighlightPoint',
- 0x27 => 'LandscapeOutputShadowPoint',
- 0x28 => 'NeutralRawColorTone',
- 0x29 => 'NeutralRawSaturation',
- 0x2a => 'NeutralRawContrast',
- 0x2b => { Name => 'NeutralRawLinear', %noYes },
- 0x2c => 'NeutralRawSharpness',
- 0x2d => 'NeutralRawHighlightPoint',
- 0x2e => 'NeutralRawShadowPoint',
- 0x2f => 'NeutralOutputHighlightPoint',
- 0x30 => 'NeutralOutputShadowPoint',
- 0x31 => 'FaithfulRawColorTone',
- 0x32 => 'FaithfulRawSaturation',
- 0x33 => 'FaithfulRawContrast',
- 0x34 => { Name => 'FaithfulRawLinear', %noYes },
- 0x35 => 'FaithfulRawSharpness',
- 0x36 => 'FaithfulRawHighlightPoint',
- 0x37 => 'FaithfulRawShadowPoint',
- 0x38 => 'FaithfulOutputHighlightPoint',
- 0x39 => 'FaithfulOutputShadowPoint',
- 0x3a => {
- Name => 'MonochromeFilterEffect',
- PrintConv => {
- -2 => 'None',
- -1 => 'Yellow',
- 0 => 'Orange',
- 1 => 'Red',
- 2 => 'Green',
- },
- },
- 0x3b => {
- Name => 'MonochromeToningEffect',
- PrintConv => {
- -2 => 'None',
- -1 => 'Sepia',
- 0 => 'Blue',
- 1 => 'Purple',
- 2 => 'Green',
- },
- },
- 0x3c => 'MonochromeContrast',
- 0x3d => { Name => 'MonochromeLinear', %noYes },
- 0x3e => 'MonochromeSharpness',
- 0x3f => 'MonochromeRawHighlightPoint',
- 0x40 => 'MonochromeRawShadowPoint',
- 0x41 => 'MonochromeOutputHighlightPoint',
- 0x42 => 'MonochromeOutputShadowPoint',
- 0x45 => { Name => 'UnknownContrast', Unknown => 1 },
- 0x46 => { Name => 'UnknownLinear', %noYes, Unknown => 1 },
- 0x47 => { Name => 'UnknownSharpness', Unknown => 1 },
- 0x48 => { Name => 'UnknownRawHighlightPoint', Unknown => 1 },
- 0x49 => { Name => 'UnknownRawShadowPoint', Unknown => 1 },
- 0x4a => { Name => 'UnknownOutputHighlightPoint',Unknown => 1 },
- 0x4b => { Name => 'UnknownOutputShadowPoint', Unknown => 1 },
- 0x4c => 'CustomColorTone',
- 0x4d => 'CustomSaturation',
- 0x4e => 'CustomContrast',
- 0x4f => { Name => 'CustomLinear', %noYes },
- 0x50 => 'CustomSharpness',
- 0x51 => 'CustomRawHighlightPoint',
- 0x52 => 'CustomRawShadowPoint',
- 0x53 => 'CustomOutputHighlightPoint',
- 0x54 => 'CustomOutputShadowPoint',
- 0x58 => {
- Name => 'CustomPictureStyleData',
- Format => 'var_int16u',
- Binary => 1,
- Notes => 'variable-length data structure',
- Writable => 0,
- RawConv => 'length($val) == 2 ? undef : $val', # ignore if no data
- },
- # (VRD 2.0.0 edit data ends here: 178 bytes, index 0x59)
- 0x5e => [{
- Name => 'ChrominanceNoiseReduction',
- Condition => '$$self{VRDVersion} < 330',
- Notes => 'VRDVersion prior to 3.3.0',
- PrintConv => {
- 0 => 'Off',
- 58 => 'Low',
- 100 => 'High',
- },
- },{ #1
- Name => 'ChrominanceNoiseReduction',
- Notes => 'VRDVersion 3.3.0 or later',
- PrintHex => 1,
- PrintConvColumns => 4,
- PrintConv => {
- 0x00 => 0,
- 0x10 => 1,
- 0x21 => 2,
- 0x32 => 3,
- 0x42 => 4,
- 0x53 => 5,
- 0x64 => 6,
- 0x74 => 7,
- 0x85 => 8,
- 0x96 => 9,
- 0xa6 => 10,
- 0xa7 => 11,
- 0xa8 => 12,
- 0xa9 => 13,
- 0xaa => 14,
- 0xab => 15,
- 0xac => 16,
- 0xad => 17,
- 0xae => 18,
- 0xaf => 19,
- 0xb0 => 20,
- },
- }],
- 0x5f => [{
- Name => 'LuminanceNoiseReduction',
- Condition => '$$self{VRDVersion} < 330',
- Notes => 'VRDVersion prior to 3.3.0',
- PrintConv => {
- 0 => 'Off',
- 65 => 'Low',
- 100 => 'High',
- },
- },{ #1
- Name => 'LuminanceNoiseReduction',
- Notes => 'VRDVersion 3.3.0 or later',
- PrintHex => 1,
- PrintConvColumns => 4,
- PrintConv => {
- 0x00 => 0,
- 0x41 => 1,
- 0x64 => 2,
- 0x6e => 3,
- 0x78 => 4,
- 0x82 => 5,
- 0x8c => 6,
- 0x96 => 7,
- 0xa0 => 8,
- 0xaa => 9,
- 0xb4 => 10,
- 0xb5 => 11,
- 0xb6 => 12,
- 0xb7 => 13,
- 0xb8 => 14,
- 0xb9 => 15,
- 0xba => 16,
- 0xbb => 17,
- 0xbc => 18,
- 0xbd => 19,
- 0xbe => 20,
- },
- }],
- 0x60 => [{
- Name => 'ChrominanceNR_TIFF_JPEG',
- Condition => '$$self{VRDVersion} < 330',
- Notes => 'VRDVersion prior to 3.3.0',
- PrintConv => {
- 0 => 'Off',
- 33 => 'Low',
- 100 => 'High',
- },
- },{ #1
- Name => 'ChrominanceNR_TIFF_JPEG',
- Notes => 'VRDVersion 3.3.0 or later',
- PrintHex => 1,
- PrintConvColumns => 4,
- PrintConv => {
- 0x00 => 0,
- 0x10 => 1,
- 0x21 => 2,
- 0x32 => 3,
- 0x42 => 4,
- 0x53 => 5,
- 0x64 => 6,
- 0x74 => 7,
- 0x85 => 8,
- 0x96 => 9,
- 0xa6 => 10,
- 0xa7 => 11,
- 0xa8 => 12,
- 0xa9 => 13,
- 0xaa => 14,
- 0xab => 15,
- 0xac => 16,
- 0xad => 17,
- 0xae => 18,
- 0xaf => 19,
- 0xb0 => 20,
- },
- }],
- # 0x61: 1
- # (VRD 3.0.0 edit data ends here: 196 bytes, index 0x62)
- 0x62 => { Name => 'ChromaticAberrationOn', %noYes },
- 0x63 => { Name => 'DistortionCorrectionOn', %noYes },
- 0x64 => { Name => 'PeripheralIlluminationOn', %noYes },
- 0x65 => { Name => 'ColorBlur', %noYes },
- 0x66 => {
- Name => 'ChromaticAberration',
- ValueConv => '$val / 0x400',
- ValueConvInv => 'int($val * 0x400 + 0.5)',
- PrintConv => 'sprintf("%.0f%%", $val * 100)',
- PrintConvInv => 'ToFloat($val) / 100',
- },
- 0x67 => {
- Name => 'DistortionCorrection',
- ValueConv => '$val / 0x400',
- ValueConvInv => 'int($val * 0x400 + 0.5)',
- PrintConv => 'sprintf("%.0f%%", $val * 100)',
- PrintConvInv => 'ToFloat($val) / 100',
- },
- 0x68 => {
- Name => 'PeripheralIllumination',
- ValueConv => '$val / 0x400',
- ValueConvInv => 'int($val * 0x400 + 0.5)',
- PrintConv => 'sprintf("%.0f%%", $val * 100)',
- PrintConvInv => 'ToFloat($val) / 100',
- },
- 0x69 => {
- Name => 'AberrationCorrectionDistance',
- Notes => '100% = infinity',
- RawConv => '$val == 0x7fff ? undef : $val',
- ValueConv => '1 - $val / 0x400',
- ValueConvInv => 'int((1 - $val) * 0x400 + 0.5)',
- PrintConv => 'sprintf("%.0f%%", $val * 100)',
- PrintConvInv => 'ToFloat($val) / 100',
- },
- 0x6a => 'ChromaticAberrationRed',
- 0x6b => 'ChromaticAberrationBlue',
- 0x6d => { #1
- Name => 'LuminanceNR_TIFF_JPEG',
- Notes => 'val = raw / 10',
- ValueConv => '$val / 10',
- ValueConvInv => 'int($val * 10 + 0.5)',
- },
- # (VRD 3.4.0 edit data ends here: 220 bytes, index 0x6e)
- 0x6e => { Name => 'AutoLightingOptimizerOn', %noYes },
- 0x6f => {
- Name => 'AutoLightingOptimizer',
- PrintConv => {
- 100 => 'Low',
- 200 => 'Standard',
- 300 => 'Strong',
- 0x7fff => 'n/a', #1
- },
- },
- # 0x71: 200
- # 0x73: 100
- # (VRD 3.5.0 edit data ends here: 232 bytes, index 0x74)
- 0x75 => {
- Name => 'StandardRawHighlight',
- ValueConv => '$val / 10',
- ValueConvInv => '$val * 10',
- },
- 0x76 => {
- Name => 'PortraitRawHighlight',
- ValueConv => '$val / 10',
- ValueConvInv => '$val * 10',
- },
- 0x77 => {
- Name => 'LandscapeRawHighlight',
- ValueConv => '$val / 10',
- ValueConvInv => '$val * 10',
- },
- 0x78 => {
- Name => 'NeutralRawHighlight',
- ValueConv => '$val / 10',
- ValueConvInv => '$val * 10',
- },
- 0x79 => {
- Name => 'FaithfulRawHighlight',
- ValueConv => '$val / 10',
- ValueConvInv => '$val * 10',
- },
- 0x7a => {
- Name => 'MonochromeRawHighlight',
- ValueConv => '$val / 10',
- ValueConvInv => '$val * 10',
- },
- 0x7b => {
- Name => 'UnknownRawHighlight',
- Unknown => 1,
- ValueConv => '$val / 10',
- ValueConvInv => '$val * 10',
- },
- 0x7c => {
- Name => 'CustomRawHighlight',
- ValueConv => '$val / 10',
- ValueConvInv => '$val * 10',
- },
- 0x7e => {
- Name => 'StandardRawShadow',
- ValueConv => '$val / 10',
- ValueConvInv => '$val * 10',
- },
- 0x7f => {
- Name => 'PortraitRawShadow',
- ValueConv => '$val / 10',
- ValueConvInv => '$val * 10',
- },
- 0x80 => {
- Name => 'LandscapeRawShadow',
- ValueConv => '$val / 10',
- ValueConvInv => '$val * 10',
- },
- 0x81 => {
- Name => 'NeutralRawShadow',
- ValueConv => '$val / 10',
- ValueConvInv => '$val * 10',
- },
- 0x82 => {
- Name => 'FaithfulRawShadow',
- ValueConv => '$val / 10',
- ValueConvInv => '$val * 10',
- },
- 0x83 => {
- Name => 'MonochromeRawShadow',
- ValueConv => '$val / 10',
- ValueConvInv => '$val * 10',
- },
- 0x84 => {
- Name => 'UnknownRawShadow',
- Unknown => 1,
- ValueConv => '$val / 10',
- ValueConvInv => '$val * 10',
- },
- 0x85 => {
- Name => 'CustomRawShadow',
- ValueConv => '$val / 10',
- ValueConvInv => '$val * 10',
- },
- 0x8b => { #2
- Name => 'AngleAdj',
- Format => 'int32s',
- ValueConv => '$val / 100',
- ValueConvInv => '$val * 100',
- },
- 0x8e => {
- Name => 'CheckMark2',
- Format => 'int16u',
- PrintConvColumns => 2,
- PrintConv => {
- 0 => 'Clear',
- 1 => 1,
- 2 => 2,
- 3 => 3,
- 4 => 4,
- 5 => 5,
- },
- },
- # (VRD 3.8.0 edit data ends here: 286 bytes, index 0x8f)
- 0x90 => {
- Name => 'UnsharpMask',
- PrintConv => { 0 => 'Off', 1 => 'On' },
- },
- 0x92 => 'StandardUnsharpMaskStrength',
- 0x94 => 'StandardUnsharpMaskFineness',
- 0x96 => 'StandardUnsharpMaskThreshold',
- 0x98 => 'PortraitUnsharpMaskStrength',
- 0x9a => 'PortraitUnsharpMaskFineness',
- 0x9c => 'PortraitUnsharpMaskThreshold',
- 0x9e => 'LandscapeUnsharpMaskStrength',
- 0xa0 => 'LandscapeUnsharpMaskFineness',
- 0xa2 => 'LandscapeUnsharpMaskThreshold',
- 0xa4 => 'NeutraUnsharpMaskStrength',
- 0xa6 => 'NeutralUnsharpMaskFineness',
- 0xa8 => 'NeutralUnsharpMaskThreshold',
- 0xaa => 'FaithfulUnsharpMaskStrength',
- 0xac => 'FaithfulUnsharpMaskFineness',
- 0xae => 'FaithfulUnsharpMaskThreshold',
- 0xb0 => 'MonochromeUnsharpMaskStrength',
- 0xb2 => 'MonochromeUnsharpMaskFineness',
- 0xb4 => 'MonochromeUnsharpMaskThreshold',
- 0xb6 => 'CustomUnsharpMaskStrength',
- 0xb8 => 'CustomUnsharpMaskFineness',
- 0xba => 'CustomUnsharpMaskThreshold',
- 0xbc => 'CustomDefaultUnsharpStrength',
- 0xbe => 'CustomDefaultUnsharpFineness',
- 0xc0 => 'CustomDefaultUnsharpThreshold',
- # (VRD 3.9.1 edit data ends here: 392 bytes, index 0xc4)
- # 0xc9: 3 - some RawSharpness
- # 0xca: 4095 - some RawHighlightPoint
- # 0xcb: 0 - some RawShadowPoint
- # 0xcc: 4095 - some OutputHighlightPoint
- # 0xcd: 0 - some OutputShadowPoint
- # 0xd1: 3 - some UnsharpMaskStrength
- # 0xd3: 7 - some UnsharpMaskFineness
- # 0xd5: 3,4 - some UnsharpMaskThreshold
- 0xd6 => { Name => 'CropCircleActive', %noYes },
- 0xd7 => 'CropCircleX',
- 0xd8 => 'CropCircleY',
- 0xd9 => 'CropCircleRadius',
- # 0xda: 0, 1
- # 0xdb: 100
- 0xdc => {
- Name => 'DLOOn',
- DataMember => 'DLOOn',
- RawConv => '$$self{DLOOn} = $val',
- %noYes,
- },
- 0xdd => 'DLOSetting',
- # (VRD 3.11.0 edit data ends here: 444 bytes, index 0xde)
- 0xde => {
- Name => 'DLOShootingDistance',
- Notes => '100% = infinity',
- RawConv => '$val == 0x7fff ? undef : $val',
- ValueConv => '1 - $val / 0x400',
- ValueConvInv => 'int((1 - $val) * 0x400 + 0.5)',
- PrintConv => 'sprintf("%.0f%%", $val * 100)',
- PrintConvInv => 'ToFloat($val) / 100',
- },
- 0xdf => {
- Name => 'DLODataLength',
- DataMember => 'DLODataLength',
- Format => 'int32u',
- Writable => 0,
- RawConv => '$$self{DLODataLength} = $val',
- },
- 0xe0 => { # (yes, this overlaps DLODataLength)
- Name => 'DLOInfo',
- # - have seen DLODataLengths of 65536,64869 when DLO is Off, so must test DLOOn flag
- Condition => '$$self{DLOOn}',
- SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::DLOInfo' },
- Hook => '$varSize += $$self{DLODataLength} + 0x16',
- },
- 0xe1 => 'CameraRawColorTone',
- # (VRD 3.11.2 edit data ends here: 452 bytes, index 0xe2, unless DLO is on)
- 0xe2 => 'CameraRawSaturation',
- 0xe3 => 'CameraRawContrast',
- 0xe4 => { Name => 'CameraRawLinear', %noYes },
- 0xe5 => 'CameraRawSharpness',
- 0xe6 => 'CameraRawHighlightPoint',
- 0xe7 => 'CameraRawShadowPoint',
- 0xe8 => 'CameraRawOutputHighlightPoint',
- 0xe9 => 'CameraRawOutputShadowPoint',
- );
- # DLO tags (ref PH)
- %Image::ExifTool::CanonVRD::DLOInfo = (
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
- WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
- CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
- WRITABLE => 1,
- FIRST_ENTRY => 1,
- FORMAT => 'int16s',
- GROUPS => { 2 => 'Image' },
- NOTES => 'Tags added when DLO (Digital Lens Optimizer) is on.',
- # 0x01 - seen 3112,3140
- 0x04 => 'DLOSettingApplied',
- 0x05 => {
- Name => 'DLOVersion', #(NC)
- Format => 'string[10]',
- },
- 0x0a => {
- Name => 'DLOData',
- LargeTag => 1, # large tag, so avoid storing unnecessarily
- Notes => 'variable-length Digital Lens Optimizer data, stored in JPEG-like format',
- Format => 'undef[$$self{DLODataLength}]',
- Writable => 0,
- Binary => 1,
- },
- );
- # VRD version 4 tags (ref PH)
- %Image::ExifTool::CanonVRD::DR4 = (
- PROCESS_PROC => \&ProcessDR4,
- WRITE_PROC => \&ProcessDR4,
- WRITABLE => 1,
- GROUPS => { 2 => 'Image' },
- VARS => { HEX_ID => 1, SORT_PROC => \&SortDR4 },
- NOTES => q{
- Tags written by Canon DPP version 4 in CanonVRD trailers and DR4 files. Each
- tag has three associated flag words which are stored with the directory
- entry, some of which are extracted as a separate tag, indicated in the table
- below by a decimal appended to the tag ID (.0, .1 or .2).
- },
- header => {
- Name => 'DR4Header',
- SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::DR4Header' },
- },
- 0x10002 => 'Rotation', # left/right rotation 90,180,270
- 0x10003 => 'AngleAdj', # crop angle
- # 0x10018 - fmt=8: 0
- # 0x10020 - fmt=2: ''
- 0x10021 => 'CustomPictureStyle', # (string)
- 0x10101 => {
- Name => 'CheckMark',
- PrintConv => {
- 0 => 'Clear',
- 1 => 1,
- 2 => 2,
- 3 => 3,
- 4 => 4,
- 5 => 5,
- },
- },
- 0x10200 => {
- Name => 'WorkColorSpace',
- PrintConv => {
- 1 => 'sRGB',
- 2 => 'Adobe RGB',
- 3 => 'Wide Gamut RGB',
- 4 => 'Apple RGB',
- 5 => 'ColorMatch RGB',
- },
- },
- # 0x10201 - fmt=9: 0
- # 0x10f20 - fmt=9: 350
- 0x20001 => 'RawBrightnessAdj',
- 0x20101 => {
- Name => 'WhiteBalanceAdj',
- PrintConvColumns => 2,
- PrintConv => {
- -1 => 'Manual (Click)',
- 0 => 'Auto',
- 1 => 'Daylight',
- 2 => 'Cloudy',
- 3 => 'Tungsten',
- 4 => 'Fluorescent',
- 5 => 'Flash',
- 8 => 'Shade',
- 9 => 'Kelvin',
- 255 => 'Shot Settings',
- },
- },
- 0x20102 => 'WBAdjColorTemp',
- 0x20105 => 'WBAdjMagentaGreen',
- 0x20106 => 'WBAdjBlueAmber',
- 0x20125 => {
- Name => 'WBAdjRGGBLevels',
- PrintConv => '$val =~ s/^\d+ //; $val', # remove first integer (14: what is this for?)
- PrintConvInv => '"14 $val"',
- },
- 0x20200 => { Name => 'GammaLinear', %noYes },
- 0x20301 => {
- Name => 'PictureStyle',
- PrintHex => 1,
- PrintConv => {
- 0x81 => 'Standard',
- 0x82 => 'Portrait',
- 0x83 => 'Landscape',
- 0x84 => 'Neutral',
- 0x85 => 'Faithful',
- 0x86 => 'Monochrome',
- 0x87 => 'Auto',
- 0x88 => 'Fine Detail',
- 0xf0 => 'Shot Settings',
- 0xff => 'Custom',
- },
- },
- # 0x20302 - Gamma curve data
- 0x20303 => 'ContrastAdj',
- 0x20304 => 'ColorToneAdj',
- 0x20305 => 'ColorSaturationAdj',
- 0x20306 => {
- Name => 'MonochromeToningEffect',
- PrintConv => {
- 0 => 'None',
- 1 => 'Sepia',
- 2 => 'Blue',
- 3 => 'Purple',
- 4 => 'Green',
- },
- },
- 0x20307 => {
- Name => 'MonochromeFilterEffect',
- PrintConv => {
- 0 => 'None',
- 1 => 'Yellow',
- 2 => 'Orange',
- 3 => 'Red',
- 4 => 'Green',
- },
- },
- 0x20308 => 'UnsharpMaskStrength',
- 0x20309 => 'UnsharpMaskFineness',
- 0x2030a => 'UnsharpMaskThreshold',
- 0x2030b => 'ShadowAdj',
- 0x2030c => 'HighlightAdj',
- 0x20310 => {
- Name => 'SharpnessAdj',
- PrintConv => {
- 0 => 'Sharpness',
- 1 => 'Unsharp Mask',
- },
- },
- '0x20310.0' => { Name => 'SharpnessAdjOn', %noYes },
- 0x20311 => 'SharpnessStrength',
- 0x20400 => {
- Name => 'ToneCurve',
- SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::ToneCurve' },
- },
- '0x20400.1' => { Name => 'ToneCurveOriginal', %noYes },
- # 0x20401 - fmt=33 (312 bytes)
- 0x20410 => 'ToneCurveBrightness',
- 0x20411 => 'ToneCurveContrast',
- 0x20500 => {
- Name => 'AutoLightingOptimizer',
- PrintConv => {
- 0 => 'Low',
- 1 => 'Standard',
- 2 => 'Strong',
- },
- },
- '0x20500.0' => {
- Name => 'AutoLightingOptimizerOn',
- Notes => 'ignored if gamma is linear',
- %noYes,
- },
- # 0x20501 - fmt=13: 0
- # 0x20502 - fmt=13: 0
- 0x20600 => 'LuminanceNoiseReduction',
- 0x20601 => 'ChrominanceNoiseReduction',
- # 0x20650 - fmt=9: 0 (JPG images)
- 0x20701 => {
- Name => 'ShootingDistance',
- Notes => '100% = infinity',
- ValueConv => '$val / 10',
- ValueConvInv => '$val * 10',
- PrintConv => 'sprintf("%.0f%%", $val * 100)',
- PrintConvInv => 'ToFloat($val) / 100',
- },
- 0x20702 => {
- Name => 'PeripheralIllumination',
- PrintConv => 'sprintf "%g", $val',
- PrintConvInv => '$val',
- },
- '0x20702.0' => { Name => 'PeripheralIlluminationOn', %noYes },
- 0x20703 => {
- Name => 'ChromaticAberration',
- PrintConv => 'sprintf "%g", $val',
- PrintConvInv => '$val',
- },
- '0x20703.0' => { Name => 'ChromaticAberrationOn', %noYes },
- 0x20704 => { Name => 'ColorBlurOn', %noYes },
- 0x20705 => {
- Name => 'DistortionCorrection',
- PrintConv => 'sprintf "%g", $val',
- PrintConvInv => '$val',
- },
- '0x20705.0' => { Name => 'DistortionCorrectionOn', %noYes },
- 0x20706 => 'DLOSetting',
- '0x20706.0' => { Name => 'DLOOn', %noYes },
- 0x20707 => {
- Name => 'ChromaticAberrationRed',
- PrintConv => 'sprintf "%g", $val',
- PrintConvInv => '$val',
- },
- 0x20708 => {
- Name => 'ChromaticAberrationBlue',
- PrintConv => 'sprintf "%g", $val',
- PrintConvInv => '$val',
- },
- 0x20709 => {
- Name => 'DistortionEffect',
- PrintConv => {
- 0 => 'Shot Settings',
- 1 => 'Emphasize Linearity',
- 2 => 'Emphasize Distance',
- 3 => 'Emphasize Periphery',
- 4 => 'Emphasize Center',
- },
- },
- # 0x20800 - fmt=1: 0
- # 0x20801 - fmt=1: 0
- 0x20900 => 'ColorHue',
- 0x20901 => 'SaturationAdj',
- 0x20910 => 'RedHSL',
- 0x20911 => 'OrangeHSL',
- 0x20912 => 'GreenHSL',
- 0x20913 => 'AquaHSL',
- 0x20914 => 'BlueHSL',
- 0x20915 => 'BlueHSL',
- 0x20916 => 'PurpleHSL',
- 0x20917 => 'MagentaHSL',
- 0x20a00 => {
- Name => 'GammaInfo',
- SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::GammaInfo' },
- },
- # 0x20a01 - Auto picture style settings
- # 0x20a02 - Standard picture style settings
- # 0x20a03 - Portrait picture style settings
- # 0x20a04 - Landscape picture style settings
- # 0x20a05 - Neutral picture style settings
- # 0x20a06 - Faithful picture style settings
- # 0x20a07 - Monochrome picture style settings
- # 0x20a08 - (unknown picture style settings)
- # 0x20a09 - Custom picture style settings
- # 0x20a20 - Fine Detail picture style settings
- 0x30101 => {
- Name => 'CropAspectRatio',
- PrintConv => {
- 0 => 'Free',
- 1 => 'Custom',
- 2 => '1:1',
- 3 => '3:2',
- 4 => '2:3',
- 5 => '4:3',
- 6 => '3:4',
- 7 => '5:4',
- 8 => '4:5',
- 9 => '16:9',
- 10 => '9:16',
- },
- },
- 0x30102 => 'CropAspectRatioCustom',
- # 0x30103 - fmt=33: "0 0 8"
- 0xf0100 => {
- Name => 'CropInfo',
- SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::CropInfo' },
- },
- 0xf0500 => {
- Name => 'CustomPictureStyleData',
- Binary => 1,
- },
- 0xf0510 => {
- Name => 'StampInfo',
- SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::StampInfo' },
- },
- 0xf0511 => {
- Name => 'DustInfo',
- SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::DustInfo' },
- },
- 0xf0512 => 'LensFocalLength',
- # 0xf0521 - DLO data
- # 0xf0520 - DLO data
- # 0xf0530 - created when dust delete data applied (4 bytes, all zero)
- # 0xf0600 - fmt=253 (2308 bytes, JPG images)
- # 0xf0601 - fmt=253 (2308 bytes, JPG images)
- # 0x1ff52c - values: 129,130,132 (related to custom picture style somehow)
- # to do:
- # - find 8-15mm CR2 sample and decode linear distortion effect fine-tune
- );
- # Version 4 header information (ref PH)
- %Image::ExifTool::CanonVRD::DR4Header = (
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
- WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
- CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
- WRITABLE => 1,
- FIRST_ENTRY => 0,
- FORMAT => 'int32u',
- GROUPS => { 2 => 'Image' },
- # 0 - value: 'IIII' (presumably byte order)
- # 1 - value: 0x00040004 (currently use this for magic number)
- # 2 - value: 6
- 3 => {
- Name => 'DR4CameraModel',
- Writable => 'int32u',
- PrintHex => 1,
- SeparateTable => 'Canon CameraModelID',
- PrintConv => \%Image::ExifTool::Canon::canonModelID,
- },
- # 4 - value: 3
- # 5 - value: 4
- # 6 - value: 5
- # 7 - DR4 directory entry count
- );
- # Version 4 RGB tone curve information (ref PH)
- %Image::ExifTool::CanonVRD::ToneCurve = (
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
- WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
- CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
- WRITABLE => 1,
- FIRST_ENTRY => 0,
- FORMAT => 'int32u',
- GROUPS => { 2 => 'Image' },
- 0x00 => {
- Name => 'ToneCurveColorSpace',
- PrintConv => {
- 0 => 'RGB',
- 1 => 'Luminance',
- },
- },
- 0x01 => {
- Name => 'ToneCurveShape',
- PrintConv => {
- 0 => 'Curve',
- 1 => 'Straight',
- },
- },
- 0x03 => { Name => 'ToneCurveInputRange', Format => 'int32u[2]', Notes => '255 max' },
- 0x05 => { Name => 'ToneCurveOutputRange', Format => 'int32u[2]', Notes => '255 max' },
- 0x07 => {
- Name => 'RGBCurvePoints',
- Format => 'int32u[21]',
- PrintConv => 'Image::ExifTool::CanonVRD::ToneCurvePrint($val)',
- PrintConvInv => 'Image::ExifTool::CanonVRD::ToneCurvePrintInv($val)',
- },
- 0x0a => 'ToneCurveX',
- 0x0b => 'ToneCurveY',
- 0x2d => {
- Name => 'RedCurvePoints',
- Format => 'int32u[21]',
- PrintConv => 'Image::ExifTool::CanonVRD::ToneCurvePrint($val)',
- PrintConvInv => 'Image::ExifTool::CanonVRD::ToneCurvePrintInv($val)',
- },
- 0x53 => {
- Name => 'GreenCurvePoints',
- Format => 'int32u[21]',
- PrintConv => 'Image::ExifTool::CanonVRD::ToneCurvePrint($val)',
- PrintConvInv => 'Image::ExifTool::CanonVRD::ToneCurvePrintInv($val)',
- },
- 0x79 => {
- Name => 'BlueCurvePoints',
- Format => 'int32u[21]',
- PrintConv => 'Image::ExifTool::CanonVRD::ToneCurvePrint($val)',
- PrintConvInv => 'Image::ExifTool::CanonVRD::ToneCurvePrintInv($val)',
- },
- );
- # Version 4 gamma curve information (ref PH)
- %Image::ExifTool::CanonVRD::GammaInfo = (
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
- WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
- CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
- WRITABLE => 1,
- FIRST_ENTRY => 0,
- FORMAT => 'double',
- GROUPS => { 2 => 'Image' },
- 0x02 => 'GammaContrast',
- 0x03 => 'GammaColorTone',
- 0x04 => 'GammaSaturation',
- 0x05 => 'GammaUnsharpMaskStrength',
- 0x06 => 'GammaUnsharpMaskFineness',
- 0x07 => 'GammaUnsharpMaskThreshold',
- 0x08 => 'GammaSharpnessStrength',
- 0x09 => 'GammaShadow',
- 0x0a => 'GammaHighlight',
- # 0x0b-0x10 are the same as first 6 doubles of tag DR4_0x20302
- # 0x0b - value: 14
- 0x0c => {
- Name => 'GammaBlackPoint',
- ValueConv => q{
- return 0 if $val <= 0;
- $val = log($val / 4.6875) / log(2) + 1;
- return abs($val) > 1e-10 ? $val : 0;
- },
- ValueConvInv => '$val ? exp(($val - 1) * log(2)) * 4.6876 : 0',
- PrintConv => 'sprintf("%+.3f", $val)',
- PrintConvInv => '$val',
- },
- 0x0d => {
- Name => 'GammaWhitePoint',
- ValueConv => q{
- return $val if $val <= 0;
- $val = log($val / 4.6875) / log(2) - 11.77109325169954;
- return abs($val) > 1e-10 ? $val : 0;
- },
- ValueConvInv => '$val ? exp(($val + 11.77109325169954) * log(2)) * 4.6875 : 0',
- PrintConv => 'sprintf("%+.3f", $val)',
- PrintConvInv => '$val',
- },
- 0x0e => {
- Name => 'GammaMidPoint',
- ValueConv => q{
- return $val if $val <= 0;
- $val = log($val / 4.6875) / log(2) - 8;
- return abs($val) > 1e-10 ? $val : 0;
- },
- ValueConvInv => '$val ? exp(($val + 8) * log(2)) * 4.6876 : 0',
- PrintConv => 'sprintf("%+.3f", $val)',
- PrintConvInv => '$val',
- },
- 0x0f => { Name => 'GammaCurveOutputRange', Format => 'double[2]', Notes => '16383 max' },
- );
- # Version 4 crop information (ref PH)
- %Image::ExifTool::CanonVRD::CropInfo = (
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
- WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
- CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
- WRITABLE => 1,
- FIRST_ENTRY => 0,
- FORMAT => 'int32s',
- GROUPS => { 2 => 'Image' },
- 0 => { Name => 'CropActive', %noYes },
- 1 => 'CropRotatedOriginalWidth',
- 2 => 'CropRotatedOriginalHeight',
- 3 => 'CropX',
- 4 => 'CropY',
- 5 => 'CropWidth',
- 6 => 'CropHeight',
- 8 => {
- Name => 'CropRotation',
- Format => 'double',
- PrintConv => 'sprintf("%.7g",$val)',
- PrintConvInv => '$val',
- },
- 0x0a => 'CropOriginalWidth',
- 0x0b => 'CropOriginalHeight',
- # 0x0c double - value: 100
- );
- # DR4 Stamp Tool tags (ref PH)
- %Image::ExifTool::CanonVRD::StampInfo = (
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
- GROUPS => { 2 => 'Image' },
- FORMAT => 'int32u',
- FIRST_ENTRY => 0,
- 0x02 => 'StampToolCount',
- );
- # DR4 dust delete information (ref PH)
- %Image::ExifTool::CanonVRD::DustInfo = (
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
- GROUPS => { 2 => 'Image' },
- FORMAT => 'int32u',
- FIRST_ENTRY => 0,
- 0x02 => { Name => 'DustDeleteApplied', %noYes },
- );
- #------------------------------------------------------------------------------
- # sort DR4 tag ID's for the documentation
- sub SortDR4($$)
- {
- my ($a, $b) = @_;
- my ($aHex, $aDec, $bHex, $bDec);
- ($aHex, $aDec) = ($1, $2) if $a =~ /^(0x[0-9a-f]+)?\.?(\d*?)$/;
- ($bHex, $bDec) = ($1, $2) if $b =~ /^(0x[0-9a-f]+)?\.?(\d*?)$/;
- if ($aHex) {
- return 1 unless defined $bDec; # $b is 'header';
- return hex($aHex) <=> hex($bHex) || $aDec <=> $bDec if $bHex;
- return hex($aHex) <=> $bDec || 1;
- } elsif ($bHex) {
- return -1 unless defined $aDec;
- return $aDec <=> hex($bHex) || -1;
- } else {
- return 1 unless defined $bDec;
- return -1 unless defined $aDec;
- return $aDec <=> $bDec;
- }
- }
- #------------------------------------------------------------------------------
- # Tone curve print conversion
- sub ToneCurvePrint($)
- {
- my $val = shift;
- my @vals = split ' ', $val;
- return $val unless @vals == 21;
- my $n = shift @vals;
- return $val unless $n >= 2 and $n <= 10;
- $val = '';
- while ($n--) {
- $val and $val .= ' ';
- $val .= '(' . shift(@vals) . ',' . shift(@vals) . ')';
- }
- return $val;
- }
- #------------------------------------------------------------------------------
- # Inverse print conversion for tone curve
- sub ToneCurvePrintInv($)
- {
- my $val = shift;
- my @vals = ($val =~ /\((\d+),(\d+)\)/g);
- return undef unless @vals >= 4 and @vals <= 20 and not @vals & 0x01;
- unshift @vals, scalar(@vals) / 2;
- while (@vals < 21) { push @vals, 0 }
- return join(' ',@vals);
- }
- #------------------------------------------------------------------------------
- # Read/Write VRD edit data
- # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
- # Returns: Reading: 1 on success; Writing: modified edit data, or undef if nothing changed
- sub ProcessEditData($$$)
- {
- my ($et, $dirInfo, $tagTablePtr) = @_;
- $et or return 1; # allow dummy access
- my $dataPt = $$dirInfo{DataPt};
- my $pos = $$dirInfo{DirStart};
- my $dataPos = $$dirInfo{DataPos};
- my $outfile = $$dirInfo{OutFile};
- my $dirLen = $$dirInfo{DirLen};
- my $verbose = $et->Options('Verbose');
- my $out = $et->Options('TextOut');
- my $oldChanged = $$et{CHANGED};
- $et->VerboseDir('VRD Edit Data', 0, $dirLen) unless $outfile;
- if ($outfile) {
- # make a copy for editing in place
- my $buff = substr($$dataPt, $pos, $dirLen);
- $dataPt = $$dirInfo{DataPt} = \$buff;
- $pos = $$dirInfo{DirStart} = 0;
- }
- my $dirEnd = $pos + $dirLen;
- # loop through all records in the edit data
- my ($recNum, $recLen, $err);
- for ($recNum=0;; ++$recNum, $pos+=$recLen) {
- if ($pos + 4 > $dirEnd) {
- last if $pos == $dirEnd; # all done if we arrived at end
- $recLen = 0; # just reset record size (will exit loop on test below)
- } else {
- $recLen = Get32u($dataPt, $pos);
- # (DR4 has a null terminator)
- last if $recLen == 0 and $pos + 4 == $dirEnd;
- }
- $pos += 4; # move to start of record
- if ($pos + $recLen > $dirEnd) {
- $et->Warn('Possibly corrupt CanonVRD Edit record');
- $err = 1;
- last;
- }
- my $saveRecLen = $recLen;
- if ($verbose > 1 and not $outfile) {
- printf $out "$$et{INDENT}CanonVRD Edit record ($recLen bytes at offset 0x%x)\n",
- $pos + $dataPos;
- if ($recNum and $verbose > 2) {
- my %parms = (
- Start => $pos,
- Addr => $pos + $dataPos,
- Out => $out,
- Prefix => $$et{INDENT},
- );
- $parms{MaxLen} = $verbose == 3 ? 96 : 2048 if $verbose < 5;
- HexDump($dataPt, $recLen, %parms);
- }
- }
- # our edit information is the 0th record, so don't process the others
- next if $recNum;
- # process VRD edit information
- my $subTablePtr = $tagTablePtr;
- my $index;
- my %subdirInfo = (
- DataPt => $dataPt,
- DataPos => $dataPos,
- DirStart => $pos,
- DirLen => $recLen,
- OutFile => $outfile,
- );
- my $subStart = 0;
- # loop through various sections of the VRD edit data
- for ($index=0; ; ++$index) {
- my $tagInfo = $$subTablePtr{$index} or last;
- my $subLen;
- my $maxLen = $recLen - $subStart;
- if ($$tagInfo{Size}) {
- $subLen = $$tagInfo{Size};
- } elsif (defined $$tagInfo{Size}) {
- # get size from int32u at $subStart
- last unless $subStart + 4 <= $recLen;
- $subLen = Get32u($dataPt, $subStart + $pos);
- $subStart += 4; # skip the length word
- } else {
- $subLen = $maxLen;
- }
- $subLen > $maxLen and $subLen = $maxLen;
- if ($subLen) {
- my $subTable = GetTagTable($$tagInfo{SubDirectory}{TagTable});
- my $subName = $$tagInfo{Name};
- $subdirInfo{DirStart} = $subStart + $pos;
- $subdirInfo{DirLen} = $subLen;
- $subdirInfo{DirName} = $subName;
- if ($outfile) {
- # rewrite this section of the VRD edit information
- $verbose and print $out " Rewriting Canon $subName\n";
- my $newVal = $et->WriteDirectory(\%subdirInfo, $subTable);
- if ($newVal) {
- my $sizeDiff = length($newVal) - $subLen;
- substr($$dataPt, $pos+$subStart, $subLen) = $newVal;
- if ($sizeDiff) {
- $subLen = length $newVal;
- $recLen += $sizeDiff;
- $dirEnd += $sizeDiff;
- $dirLen += $sizeDiff;
- }
- }
- } else {
- $et->VPrint(0, "$$et{INDENT}$subName (SubDirectory) -->\n");
- $et->VerboseDump($dataPt,
- Start => $pos + $subStart,
- Addr => $dataPos + $pos + $subStart,
- Len => $subLen,
- );
- # extract tags from this section of the VRD edit information
- $et->ProcessDirectory(\%subdirInfo, $subTable);
- }
- }
- # next section starts at the end of this one
- $subStart += $subLen;
- }
- if ($outfile and $saveRecLen ne $recLen) {
- # update record length if necessary
- Set32u($recLen, $dataPt, $pos - 4)
- }
- }
- if ($outfile) {
- return undef if $oldChanged == $$et{CHANGED};
- return substr($$dataPt, $$dirInfo{DirStart}, $dirLen);
- }
- return $err ? 0 : 1;
- }
- #------------------------------------------------------------------------------
- # Process VRD IHL data
- # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
- # Returns: 1 on success
- sub ProcessIHL($$$)
- {
- my ($et, $dirInfo, $tagTablePtr) = @_;
- my $dataPt = $$dirInfo{DataPt};
- my $dataPos = $$dirInfo{DataPos};
- my $pos = $$dirInfo{DirStart};
- my $dirLen = $$dirInfo{DirLen};
- my $dirEnd = $pos + $dirLen;
- $et->VerboseDir('VRD IHL', 0, $dirLen);
- SetByteOrder('II'); # (make up your mind, Canon!)
- while ($pos + 48 <= $dirEnd) {
- my $hdr = substr($$dataPt, $pos, 48);
- unless ($hdr =~ /^IHL Created Optional Item Data\0\0/) {
- $et->Warn('Possibly corrupted VRD IHL data');
- last;
- }
- my $tag = Get32u($dataPt, $pos + 36);
- my $size = Get32u($dataPt, $pos + 40); # size of data in IHL record
- my $next = Get32u($dataPt, $pos + 44); # size of complete IHL record
- if ($size > $next or $pos + 48 + $next > $dirEnd) {
- $et->Warn(sprintf('Bad size for VRD IHL tag 0x%.4x', $tag));
- last;
- }
- $pos += 48;
- $et->HandleTag($tagTablePtr, $tag, substr($$dataPt, $pos, $size),
- DataPt => $dataPt,
- DataPos => $dataPos,
- Start => $pos,
- Size => $size
- );
- $pos += $next;
- }
- return 1;
- }
- #------------------------------------------------------------------------------
- # Process VRD IHL EXIF data
- # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
- # Returns: 1 on success
- sub ProcessIHLExif($$$)
- {
- my ($et, $dirInfo, $tagTablePtr) = @_;
- $$et{DOC_NUM} = 1;
- # the IHL-edited maker notes may look messed up, but the offsets should be OK
- my $oldFix = $et->Options(FixBase => 0);
- my $rtnVal = $et->ProcessTIFF($dirInfo, $tagTablePtr);
- $et->Options(FixBase => $oldFix);
- delete $$et{DOC_NUM};
- return $rtnVal;
- }
- #------------------------------------------------------------------------------
- # Wrap DR4 data with the VRD header/footer and edit record
- # Inputs: 0) DR4 record
- # Returns: VRD[Edit[DR4]] data
- sub WrapDR4($)
- {
- my $val = shift;
- my $n = length $val;
- my $oldOrder = GetByteOrder();
- SetByteOrder('MM');
- $val = $blankHeader . "\xff\xff\0\xf7" . Set32u($n+8) . Set32u($n) .
- $val . "\0\0\0\0" . $blankFooter;
- # update the new VRD length in the header/footer
- Set32u($n + 16, \$val, 0x18); # (extra 16 bytes for the edit record wrapper)
- Set32u($n + 16, \$val, length($val) - 0x2c);
- SetByteOrder($oldOrder);
- return $val;
- }
- #------------------------------------------------------------------------------
- # Read/Write DPP version 4 edit data or DR4 file
- # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
- # Returns:
- # Reading from memory (not RAF and not IsWriting): 1 on success
- # Editing from memory (not RAF and IsWriting): modified edit data, or undef if nothing changed
- # Reading file (RAF and not OutFile): 1 if a valid DR4 file, 0 if not
- # Writing file (RAF and OutFile): 1 if valid DR4 file, 0 if not, -1 on write error
- # (serves me right for not having a consistent interface for the various modes of operation)
- sub ProcessDR4($$;$)
- {
- my ($et, $dirInfo, $tagTablePtr) = @_;
- $et or return 1; # allow dummy access
- my $dataPt = $$dirInfo{DataPt};
- my $raf = $$dirInfo{RAF};
- my $outfile = $$dirInfo{OutFile};
- my $isWriting = $outfile || $$dirInfo{IsWriting};
- my $dataPos = $$dirInfo{DataPos} || 0;
- my $verbose = $et->Options('Verbose');
- my $unknown = $et->Options('Unknown');
- my ($pos, $dirLen, $numEntries, $err, $newTags);
- # write CanonDR4 as a block if specified
- if ($isWriting) {
- my $nvHash;
- my $newVal = $et->GetNewValue('CanonDR4', \$nvHash);
- if ($newVal) {
- $et->VPrint(0, " Writing CanonDR4 as a block\n");
- $$et{DidCanonVRD} = 1; # set flag so we don't add this twice
- ++$$et{CHANGED};
- if ($outfile) {
- Write($$dirInfo{OutFile}, $newVal) or return -1;
- return 1;
- } else {
- return $newVal;
- }
- } elsif (not $dataPt and ($nvHash or $$et{DEL_GROUP}{CanonVRD})) {
- $et->Error("Can't delete all CanonDR4 information from a DR4 file");
- return 1;
- }
- }
- if ($dataPt) {
- $pos = $$dirInfo{DirStart} || 0;
- $dirLen = $$dirInfo{DirLen} || length($$dataPt) - $pos;
- } else {
- # load DR4 file into memory
- my $buff;
- $raf->Read($buff, 8) == 8 and $buff eq "IIII\x04\0\x04\0" or return 0;
- $et->SetFileType();
- $raf->Seek(0, 2) or return $err = 1;
- $dirLen = $raf->Tell();
- $raf->Seek(0, 0) or return $err = 1;
- $raf->Read($buff, $dirLen) == $dirLen or $err = 1;
- $err and $et->Warn('Error reading DR4 file'), return 1;
- $tagTablePtr = GetTagTable('Image::ExifTool::CanonVRD::DR4');
- $dataPt = \$buff;
- $pos = 0;
- }
- my $dirEnd = $pos + $dirLen;
- if (($$et{TAGS_FROM_FILE} and
- not $$et{EXCL_TAG_LOOKUP}{canondr4}) or $$et{REQ_TAG_LOOKUP}{canondr4})
- {
- # extract CanonDR4 block if copying tags, or if requested
- $et->FoundTag('CanonDR4', substr($$dataPt, $pos, $dirLen));
- }
- # version 4 header is 32 bytes (int32u[8])
- if ($dirLen < 32) {
- $err = 1;
- } else {
- SetByteOrder(substr($$dataPt, $pos, 2)) or $err = 1;
- # process the DR4 header
- my %hdrInfo = (
- DataPt => $dataPt,
- DirStart => $pos,
- DirLen => 32,
- DirName => 'DR4Header',
- );
- my $hdrTable = GetTagTable('Image::ExifTool::CanonVRD::DR4Header');
- if ($outfile) {
- my $hdr = $et->WriteDirectory(\%hdrInfo, $hdrTable);
- substr($$dataPt, $pos, 32) = $hdr if $hdr and length $hdr == 32;
- } else {
- $et->VerboseDir('DR4Header', undef, 32);
- $et->ProcessDirectory(\%hdrInfo, $hdrTable);
- }
- # number of entries in the DR4 directory
- $numEntries = Get32u($dataPt, $pos + 28);
- $err = 1 if $dirLen < 36 + 28 * $numEntries;
- }
- $err and $et->Warn('Invalid DR4 directory'), return $outfile ? undef : 0;
- if ($outfile) {
- $newTags = $et->GetNewTagInfoHash($tagTablePtr);
- } else {
- $et->VerboseDir('DR4', $numEntries, $dirLen);
- }
- my $index;
- for ($index=0; $index<$numEntries; ++$index) {
- my ($val, @flg, $i);
- my $entry = $pos + 36 + 28 * $index;
- last if $entry + 28 > $dirEnd;
- my $tag = Get32u($dataPt, $entry);
- my $fmt = Get32u($dataPt, $entry + 4);
- $flg[0] = Get32u($dataPt, $entry + 8);
- $flg[1] = Get32u($dataPt, $entry + 12);
- $flg[2] = Get32u($dataPt, $entry + 16);
- my $off = Get32u($dataPt, $entry + 20) + $pos;
- my $len = Get32u($dataPt, $entry + 24);
- next if $off + $len >= $dirEnd;
- my $format = $vrdFormat{$fmt};
- if (not $format) {
- $val = unpack 'H*', substr($$dataPt, $off, $len);
- $format = 'undef';
- } elsif ($format eq 'double' and $len eq 8) {
- # avoid teeny weeny values
- $val = ReadValue($dataPt, $off, $format, undef, $len);
- $val = 0 if abs($val) < 1e-100;
- }
- if ($outfile) {
- # write (binary data) subdirectory if it exists
- my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
- if ($tagInfo and $$tagInfo{SubDirectory}) {
- my %subdirInfo = (
- DataPt => $dataPt,
- DirStart => $off,
- DirLen => $len,
- DirName => $$tagInfo{Name},
- );
- my $subTablePtr = GetTagTable($$tagInfo{SubDirectory}{TagTable});
- my $saveChanged = $$et{CHANGED};
- my $dat = $et->WriteDirectory(\%subdirInfo, $subTablePtr);
- if (defined $dat and length($dat) == $len) {
- substr($$dataPt, $off, $len) = $dat;
- } else {
- $$et{CHANGED} = $saveChanged; # didn't change anything after all
- }
- } else {
- # loop through main tag and flags (don't yet consider flag 2)
- for ($i=-1; $i<2; ++$i) {
- $tagInfo = $$newTags{$i>=0 ? sprintf('0x%x.%d',$tag,$i) : $tag};
- next unless $tagInfo;
- if ($i >= 0) {
- $off = $entry + 8 + 4 * $i;
- $format = 'int32u';
- $len = 4;
- undef $val;
- }
- $val = ReadValue($dataPt, $off, $format, undef, $len) unless defined $val;
- my $nvHash;
- my $newVal = $et->GetNewValue($tagInfo, \$nvHash);
- if ($et->IsOverwriting($nvHash, $val) and defined $newVal) {
- my $count = int($len / Image::ExifTool::FormatSize($format));
- my $rtnVal = WriteValue($newVal, $format, $count, $dataPt, $off);
- if (defined $rtnVal) {
- $et->VerboseValue("- CanonVRD:$$tagInfo{Name}", $val);
- $et->VerboseValue("+ CanonVRD:$$tagInfo{Name}", $newVal);
- ++$$et{CHANGED};
- }
- }
- }
- }
- next;
- }
- $et->HandleTag($tagTablePtr, $tag, $val,
- DataPt => $dataPt,
- DataPos => $dataPos,
- Start => $off,
- Size => $len,
- Index => $index,
- Format => $format,
- # $flg[0] is on/off flag
- # $flg[1] "is default" flag?
- # $flg[2] changed to 0 when some unsharp mask settings were changed
- Extra => ", fmt=$fmt flags=" . join(',', @flg),
- );
- foreach $i (0..2) {
- my $flagID = sprintf('0x%x.%d', $tag, $i);
- $et->HandleTag($tagTablePtr, $flagID, $flg[$i]) if $$tagTablePtr{$flagID};
- }
- }
- return 1 unless $isWriting;
- return substr($$dataPt, $pos, $dirLen) unless $raf;
- return 1 if Write($outfile, substr($$dataPt, $pos, $dirLen));
- return -1;
- }
- #------------------------------------------------------------------------------
- # Read/write Canon VRD file
- # Inputs: 0) ExifTool object reference, 1) dirInfo reference
- # Returns: 1 if this was a Canon VRD file, 0 otherwise, -1 on write error
- sub ProcessVRD($$)
- {
- my ($et, $dirInfo) = @_;
- my $raf = $$dirInfo{RAF};
- my $buff;
- my $num = $raf->Read($buff, 0x1c);
- # initialize write directories if necessary
- $et->InitWriteDirs(\%vrdMap, 'XMP') if $$dirInfo{OutFile};
- if (not $num and $$dirInfo{OutFile}) {
- # create new VRD file from scratch
- my $newVal = $et->GetNewValue('CanonVRD');
- if ($newVal) {
- $et->VPrint(0, " Writing CanonVRD as a block\n");
- Write($$dirInfo{OutFile}, $newVal) or return -1;
- $$et{DidCanonVRD} = 1;
- ++$$et{CHANGED};
- } else {
- # allow VRD to be created from individual tags
- if ($$et{ADD_DIRS}{CanonVRD}) {
- my $newVal = '';
- if (ProcessCanonVRD($et, { OutFile => \$newVal }) > 0) {
- Write($$dirInfo{OutFile}, $newVal) or return -1;
- ++$$et{CHANGED};
- return 1;
- }
- }
- $et->Error('No CanonVRD information to write');
- }
- } else {
- $num == 0x1c or return 0;
- $buff =~ /^CANON OPTIONAL DATA\0/ or return 0;
- $et->SetFileType();
- $$dirInfo{DirName} = 'CanonVRD'; # set directory name for verbose output
- my $result = ProcessCanonVRD($et, $dirInfo);
- return $result if $result < 0;
- $result or $et->Warn('Format error in VRD file');
- }
- return 1;
- }
- #------------------------------------------------------------------------------
- # Write VRD data record as a block
- # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
- # Returns: VRD data block (may be empty if no VRD data)
- # Notes: Increments ExifTool CHANGED flag if changed
- sub WriteCanonVRD($$;$)
- {
- my ($et, $dirInfo, $tagTablePtr) = @_;
- $et or return 1; # allow dummy access
- my $nvHash = $et->GetNewValueHash($Image::ExifTool::Extra{CanonVRD});
- my $val = $et->GetNewValue($nvHash);
- $val = '' unless defined $val;
- return undef unless $et->IsOverwriting($nvHash, $val);
- ++$$et{CHANGED};
- return $val;
- }
- #------------------------------------------------------------------------------
- # Read/write CanonVRD information (from VRD file or VRD trailer)
- # Inputs: 0) ExifTool object reference, 1) dirInfo reference
- # Returns: 1 on success, 0 not valid VRD, or -1 error writing
- # - updates DataPos to point to start of CanonVRD information
- # - updates DirLen to existing trailer length
- sub ProcessCanonVRD($$;$)
- {
- my ($et, $dirInfo, $tagTablePtr) = @_;
- my $raf = $$dirInfo{RAF};
- my $offset = $$dirInfo{Offset} || 0;
- my $outfile = $$dirInfo{OutFile};
- my $dataPt = $$dirInfo{DataPt};
- my $verbose = $et->Options('Verbose');
- my $out = $et->Options('TextOut');
- my ($buff, $created, $err, $blockLen, $blockType, %didDir, $fromFile);
- #
- # The CanonVRD trailer has a 0x1c-byte header and a 0x40-byte footer,
- # each beginning with "CANON OPTIONAL DATA\0" and containing an int32u
- # giving the size of the contained data (at byte 0x18 and 0x14 respectively)
- #
- if ($raf) {
- $fromFile = 1;
- } else {
- unless ($dataPt) {
- return 1 unless $outfile;
- # create blank VRD data from scratch
- my $blank = $blankHeader . $blankFooter;
- $dataPt = \$blank;
- $verbose and print $out " Creating CanonVRD trailer\n";
- $created = 1;
- }
- $raf = new File::RandomAccess($dataPt);
- }
- # read and validate the footer
- $raf->Seek(-0x40-$offset, 2) or return 0;
- $raf->Read($buff, 0x40) == 0x40 or return 0;
- $buff =~ /^CANON OPTIONAL DATA\0(.{4})/s or return 0;
- my $dirLen = unpack('N', $1) + 0x5c; # size including header+footer
- # read and validate the header
- unless ($dirLen < 0x80000000 and
- $raf->Seek(-$dirLen, 1) and
- $raf->Read($buff, 0x1c) == 0x1c and
- $buff =~ /^CANON OPTIONAL DATA\0/ and
- $raf->Seek(-0x1c, 1))
- {
- $et->Warn('Bad CanonVRD trailer');
- return 0;
- }
- # set variables returned in dirInfo hash
- $$dirInfo{DataPos} = $raf->Tell();
- $$dirInfo{DirLen} = $dirLen;
- if ($outfile and ref $outfile eq 'SCALAR' and not length $$outfile) {
- # write directly to outfile to avoid duplicating data in memory
- $$outfile = $$dataPt unless $fromFile;
- # TRICKY! -- copy to outfile memory buffer and edit in place
- # (so we must disable all Write() calls for this case)
- $dataPt = $outfile;
- }
- if ($fromFile) {
- $dataPt = \$buff unless $dataPt;
- # read VRD data into memory if necessary
- unless ($raf->Read($$dataPt, $dirLen) == $dirLen) {
- $$dataPt = '' if $outfile and $outfile eq $dataPt;
- $et->Warn('Error reading CanonVRD data');
- return 0;
- }
- }
- # exit quickly if writing and no CanonVRD tags are being edited
- if ($outfile and not exists $$et{EDIT_DIRS}{CanonVRD}) {
- print $out "$$et{INDENT} [nothing changed]\n" if $verbose;
- return 1 if $outfile eq $dataPt;
- return Write($outfile, $$dataPt) ? 1 : -1;
- }
- my $vrdType = 'VRD';
- if ($outfile) {
- $verbose and not $created and print $out " Rewriting CanonVRD trailer\n";
- # delete CanonVRD information if specified
- my $doDel = $$et{DEL_GROUP}{CanonVRD};
- unless ($doDel) {
- $doDel = 1 if $$et{DEL_GROUP}{Trailer} and $$et{FILE_TYPE} ne 'VRD';
- unless ($doDel) {
- # also delete if writing as a block (will get added back again later)
- if ($$et{NEW_VALUE}{$Image::ExifTool::Extra{CanonVRD}}) {
- # delete if this isn't version 4
- $doDel = 1 unless $$dataPt =~ /^.{28}\xff\xff\0\xf7/s;
- }
- if ($$et{NEW_VALUE}{$Image::ExifTool::Extra{CanonDR4}} and not $doDel) {
- # delete if this is version 4
- $doDel = 1 if $$dataPt =~ /^.{28}\xff\xff\0\xf7/s;
- }
- }
- }
- if ($doDel) {
- if ($$et{FILE_TYPE} eq 'VRD') {
- my $newVal = $et->GetNewValue('CanonVRD');
- if ($newVal) {
- $verbose and print $out " Writing CanonVRD as a block\n";
- if ($outfile eq $dataPt) {
- $$outfile = $newVal;
- } else {
- Write($outfile, $newVal) or return -1;
- }
- $$et{DidCanonVRD} = 1;
- ++$$et{CHANGED};
- } else {
- $et->Error("Can't delete all CanonVRD information from a VRD file");
- }
- } else {
- $verbose and print $out " Deleting CanonVRD trailer\n";
- $$outfile = '' if $outfile eq $dataPt;
- ++$$et{CHANGED};
- }
- return 1;
- }
- # write now and return if CanonVRD was set as a block
- my $val = $et->GetNewValue('CanonVRD');
- unless ($val) {
- $val = $et->GetNewValue('CanonDR4');
- $vrdType = 'DR4' if $val;
- }
- if ($val) {
- $verbose and print $out " Writing Canon$vrdType as a block\n";
- # must wrap DR4 data with the VRD header/footer and edit record
- $val = WrapDR4($val) if $vrdType eq 'DR4';
- if ($outfile eq $dataPt) {
- $$outfile = $val;
- } else {
- Write($outfile, $val) or return -1;
- }
- $$et{DidCanonVRD} = 1;
- ++$$et{CHANGED};
- return 1;
- }
- } elsif ($verbose or $$et{HTML_DUMP}) {
- $et->DumpTrailer($dirInfo) if $$dirInfo{RAF};
- }
- $tagTablePtr = GetTagTable('Image::ExifTool::CanonVRD::Main');
- # validate VRD trailer and get position and length of edit record
- SetByteOrder('MM'); # VRD header/footer is big-endian
- my $pos = 0x1c; # start at end of header
- # loop through the VRD blocks
- for (;;) {
- my $end = $dirLen - 0x40; # end of last VRD block (and start of footer)
- if ($pos + 8 > $end) {
- last if $pos == $end;
- $blockLen = $end; # mark as invalid
- } else {
- $blockType = Get32u($dataPt, $pos);
- $blockLen = Get32u($dataPt, $pos + 4);
- }
- $vrdType = 'DR4' if $blockType eq 0xffff00f7;
- $pos += 8; # move to start of block
- if ($pos + $blockLen > $end) {
- $et->Warn('Possibly corrupt CanonVRD block');
- last;
- }
- if ($verbose > 1 and not $outfile) {
- printf $out " CanonVRD block 0x%.8x ($blockLen bytes at offset 0x%x)\n",
- $blockType, $pos + $$dirInfo{DataPos};
- if ($verbose > 2) {
- my %parms = (
- Start => $pos,
- Addr => $pos + $$dirInfo{DataPos},
- Out => $out,
- Prefix => $$et{INDENT},
- );
- $parms{MaxLen} = $verbose == 3 ? 96 : 2048 if $verbose < 5;
- HexDump($dataPt, $blockLen, %parms);
- }
- }
- my $tagInfo = $$tagTablePtr{$blockType};
- unless ($tagInfo) {
- unless ($et->Options('Unknown')) {
- $pos += $blockLen; # step to next block
- next;
- }
- my $name = sprintf('CanonVRD_0x%.8x', $blockType);
- my $desc = $name;
- $desc =~ tr/_/ /;
- $tagInfo = {
- Name => $name,
- Description => $desc,
- Binary => 1,
- };
- AddTagToTable($tagTablePtr, $blockType, $tagInfo);
- }
- if ($$tagInfo{SubDirectory}) {
- my $subTablePtr = GetTagTable($$tagInfo{SubDirectory}{TagTable});
- my %subdirInfo = (
- DataPt => $dataPt,
- DataLen => length $$dataPt,
- DataPos => $$dirInfo{DataPos},
- DirStart => $pos,
- DirLen => $blockLen,
- DirName => $$tagInfo{Name},
- Parent => 'CanonVRD',
- OutFile => $outfile,
- );
- if ($outfile) {
- # set flag indicating we did this directory
- $didDir{$$tagInfo{Name}} = 1;
- my ($dat, $diff);
- if ($$et{NEW_VALUE}{$tagInfo}) {
- # write as a block
- $et->VPrint(0, "Writing $$tagInfo{Name} as a block\n");
- $dat = $et->GetNewValue($tagInfo);
- $dat = '' unless defined $dat;
- ++$$et{CHANGED};
- } else {
- $dat = $et->WriteDirectory(\%subdirInfo, $subTablePtr);
- }
- # update data with new directory
- if (defined $dat) {
- if (length $dat or $$et{FILE_TYPE} !~ /^(CRW|VRD)$/) {
- # replace with new block (updating the block length word)
- substr($$dataPt, $pos-4, $blockLen+4) = Set32u(length $dat) . $dat;
- } else {
- # remove block totally (CRW/VRD files only)
- substr($$dataPt, $pos-8, $blockLen+8) = '';
- }
- # make necessary adjustments if block changes length
- if (($diff = length($$dataPt) - $dirLen) != 0) {
- $pos += $diff;
- $dirLen += $diff;
- # update the new VRD length in the header/footer
- Set32u($dirLen - 0x5c, $dataPt, 0x18);
- Set32u($dirLen - 0x5c, $dataPt, $dirLen - 0x2c);
- }
- }
- } else {
- # extract as a block if requested
- $et->ProcessDirectory(\%subdirInfo, $subTablePtr);
- }
- } else {
- $et->HandleTag($tagTablePtr, $blockType, substr($$dataPt, $pos, $blockLen));
- }
- $pos += $blockLen; # step to next block
- }
- if ($outfile) {
- # create XMP block if necessary (CRW/VRD files only)
- if ($$et{ADD_DIRS}{CanonVRD} and not $didDir{XMP}) {
- my $subTablePtr = GetTagTable('Image::ExifTool::XMP::Main');
- my $dat = $et->WriteDirectory({ Parent => 'CanonVRD' }, $subTablePtr);
- if ($dat) {
- my $blockLen = length $dat;
- substr($$dataPt, -0x40, 0) = Set32u(0xffff00f6) . Set32u(length $dat) . $dat;
- $dirLen = length $$dataPt;
- # update the new VRD length in the header/footer
- Set32u($dirLen - 0x5c, $dataPt, 0x18);
- Set32u($dirLen - 0x5c, $dataPt, $dirLen - 0x2c);
- }
- }
- # write CanonVRD trailer unless it is empty
- if (length $$dataPt) {
- Write($outfile, $$dataPt) or $err = 1 unless $outfile eq $dataPt;
- } else {
- $verbose and print $out " Deleting CanonVRD trailer\n";
- }
- } elsif ($vrdType eq 'VRD' and (($$et{TAGS_FROM_FILE} and
- not $$et{EXCL_TAG_LOOKUP}{canonvrd}) or $$et{REQ_TAG_LOOKUP}{canonvrd}))
- {
- # extract CanonVRD block if copying tags, or if requested (and not DR4 info)
- $et->FoundTag('CanonVRD', $buff);
- }
- undef $buff;
- return $err ? -1 : 1;
- }
- 1; # end
- __END__
- =head1 NAME
- Image::ExifTool::CanonVRD - Read/write Canon VRD and DR4 information
- =head1 SYNOPSIS
- This module is used by Image::ExifTool
- =head1 DESCRIPTION
- This module contains definitions required by Image::ExifTool to read and
- write VRD and DR4 Recipe Data information as written by the Canon Digital
- Photo Professional software. This information is written to VRD and DR4
- files, and as a trailer in JPEG, CRW, CR2 and TIFF images.
- =head1 AUTHOR
- Copyright 2003-2016, Phil Harvey (phil at owl.phy.queensu.ca)
- This library is free software; you can redistribute it and/or modify it
- under the same terms as Perl itself.
- =head1 ACKNOWLEDGEMENTS
- Thanks to Bogdan and Gert Kello for decoding some tags.
- =head1 SEE ALSO
- L<Image::ExifTool::TagNames/CanonVRD Tags>,
- L<Image::ExifTool(3pm)|Image::ExifTool>
- =cut
|