FujiFilm.pm 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221
  1. #------------------------------------------------------------------------------
  2. # File: FujiFilm.pm
  3. #
  4. # Description: Read/write FujiFilm maker notes and RAF images
  5. #
  6. # Revisions: 11/25/2003 - P. Harvey Created
  7. # 11/14/2007 - PH Added abilty to write RAF images
  8. #
  9. # References: 1) http://park2.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html
  10. # 2) http://homepage3.nifty.com/kamisaka/makernote/makernote_fuji.htm (2007/09/11)
  11. # 3) Michael Meissner private communication
  12. # 4) Paul Samuelson private communication (S5)
  13. # 5) http://www.cybercom.net/~dcoffin/dcraw/
  14. # 6) http://forums.dpreview.com/forums/readflat.asp?forum=1012&thread=31350384
  15. # and http://forum.photome.de/viewtopic.php?f=2&t=353&p=742#p740
  16. # 7) Kai Lappalainen private communication
  17. # 8) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,5223.0.html
  18. # 9) Iliah Borg private communication (LibRaw)
  19. # JD) Jens Duttke private communication
  20. #------------------------------------------------------------------------------
  21. package Image::ExifTool::FujiFilm;
  22. use strict;
  23. use vars qw($VERSION);
  24. use Image::ExifTool qw(:DataAccess :Utils);
  25. use Image::ExifTool::Exif;
  26. $VERSION = '1.53';
  27. sub ProcessFujiDir($$$);
  28. sub ProcessFaceRec($$$);
  29. # the following RAF version numbers have been tested for writing:
  30. my %testedRAF = (
  31. '0100' => 'E550, E900, F770, S5600, S6000fd, S6500fd, HS10/HS11, HS30, S200EXR, X100, XF1, X-Pro1, X-S1, XQ2 Ver1.00',
  32. '0101' => 'X-E1, X20 Ver1.01',
  33. '0102' => 'S100FS, X10 Ver1.02',
  34. '0103' => 'IS Pro Ver1.03',
  35. '0104' => 'S5Pro Ver1.04',
  36. '0106' => 'S5Pro Ver1.06',
  37. '0111' => 'S5Pro Ver1.11',
  38. '0114' => 'S9600 Ver1.00',
  39. '0159' => 'S2Pro Ver1.00',
  40. '0200' => 'X10 Ver2.00',
  41. '0212' => 'S3Pro Ver2.12',
  42. '0216' => 'S3Pro Ver2.16', # (NC)
  43. '0218' => 'S3Pro Ver2.18',
  44. '0264' => 'F700 Ver2.00',
  45. '0266' => 'S9500 Ver1.01',
  46. '0269' => 'S9500 Ver1.02',
  47. '0271' => 'S3Pro Ver2.71', # UV/IR model?
  48. '0300' => 'X-E2',
  49. '0712' => 'S5000 Ver3.00',
  50. '0716' => 'S5000 Ver3.00', # (yes, 2 RAF versions with the same Software version)
  51. );
  52. my %faceCategories = (
  53. Format => 'int8u',
  54. PrintConv => { BITMASK => {
  55. 1 => 'Partner',
  56. 2 => 'Family',
  57. 3 => 'Friend',
  58. }},
  59. );
  60. # FujiFilm MakerNotes tags
  61. %Image::ExifTool::FujiFilm::Main = (
  62. WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
  63. CHECK_PROC => \&Image::ExifTool::Exif::CheckExif,
  64. WRITABLE => 1,
  65. GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
  66. 0x0 => {
  67. Name => 'Version',
  68. Writable => 'undef',
  69. },
  70. 0x0010 => { #PH (how does this compare to actual serial number?)
  71. Name => 'InternalSerialNumber',
  72. Writable => 'string',
  73. Notes => q{
  74. this number is unique, and contains the date of manufacture, but doesn't
  75. necessarily correspond to the camera body number -- this needs to be checked
  76. },
  77. # eg) "FPX20017035 592D31313034060427796060110384"
  78. # "FPX 20495643 592D313335310701318AD010110047" (F40fd)
  79. # yymmdd
  80. PrintConv => q{
  81. return $val unless $val=~/^(.*)(\d{2})(\d{2})(\d{2})(.{12})$/;
  82. my $yr = $2 + ($2 < 70 ? 2000 : 1900);
  83. return "$1 $yr:$3:$4 $5";
  84. },
  85. PrintConvInv => '$_=$val; s/ (19|20)(\d{2}):(\d{2}):(\d{2}) /$2$3$4/; $_',
  86. },
  87. 0x1000 => {
  88. Name => 'Quality',
  89. Writable => 'string',
  90. },
  91. 0x1001 => {
  92. Name => 'Sharpness',
  93. Flags => 'PrintHex',
  94. Writable => 'int16u',
  95. PrintConv => {
  96. 0x01 => 'Soft',
  97. 0x02 => 'Soft2',
  98. 0x03 => 'Normal',
  99. 0x04 => 'Hard',
  100. 0x05 => 'Hard2',
  101. 0x82 => 'Medium Soft', #2
  102. 0x84 => 'Medium Hard', #2
  103. 0x8000 => 'Film Simulation', #2
  104. 0xffff => 'n/a', #2
  105. },
  106. },
  107. 0x1002 => {
  108. Name => 'WhiteBalance',
  109. Flags => 'PrintHex',
  110. Writable => 'int16u',
  111. PrintConv => {
  112. 0x0 => 'Auto',
  113. 0x100 => 'Daylight',
  114. 0x200 => 'Cloudy',
  115. 0x300 => 'Daylight Fluorescent',
  116. 0x301 => 'Day White Fluorescent',
  117. 0x302 => 'White Fluorescent',
  118. 0x303 => 'Warm White Fluorescent', #2/PH (S5)
  119. 0x304 => 'Living Room Warm White Fluorescent', #2/PH (S5)
  120. 0x400 => 'Incandescent',
  121. 0x500 => 'Flash', #4
  122. 0x600 => 'Underwater', #forum6109
  123. 0xf00 => 'Custom',
  124. 0xf01 => 'Custom2', #2
  125. 0xf02 => 'Custom3', #2
  126. 0xf03 => 'Custom4', #2
  127. 0xf04 => 'Custom5', #2
  128. # 0xfe0 => 'Gray Point?', #2
  129. 0xff0 => 'Kelvin', #4
  130. },
  131. },
  132. 0x1003 => {
  133. Name => 'Saturation',
  134. Flags => 'PrintHex',
  135. Writable => 'int16u',
  136. PrintConv => {
  137. 0x0 => 'Normal', # # ("Color 0", ref 8)
  138. 0x080 => 'Medium High', #2 ("Color +1", ref 8)
  139. 0x100 => 'High', # ("Color +2", ref 8)
  140. 0x180 => 'Medium Low', #2 ("Color -1", ref 8)
  141. 0x200 => 'Low',
  142. 0x300 => 'None (B&W)', #2
  143. 0x301 => 'B&W Red Filter', #PH/8
  144. 0x302 => 'B&W Yellow Filter', #PH (X100)
  145. 0x303 => 'B&W Green Filter', #PH/8
  146. 0x310 => 'B&W Sepia', #PH (X100)
  147. 0x400 => 'Low 2', #8 ("Color -2")
  148. 0x8000 => 'Film Simulation', #2
  149. },
  150. },
  151. 0x1004 => {
  152. Name => 'Contrast',
  153. Flags => 'PrintHex',
  154. Writable => 'int16u',
  155. PrintConv => {
  156. 0x0 => 'Normal',
  157. 0x080 => 'Medium High', #2
  158. 0x100 => 'High',
  159. 0x180 => 'Medium Low', #2
  160. 0x200 => 'Low',
  161. 0x8000 => 'Film Simulation', #2
  162. },
  163. },
  164. 0x1005 => { #4
  165. Name => 'ColorTemperature',
  166. Writable => 'int16u',
  167. },
  168. 0x1006 => { #JD
  169. Name => 'Contrast',
  170. Flags => 'PrintHex',
  171. Writable => 'int16u',
  172. PrintConv => {
  173. 0x0 => 'Normal',
  174. 0x100 => 'High',
  175. 0x300 => 'Low',
  176. },
  177. },
  178. 0x100a => { #2
  179. Name => 'WhiteBalanceFineTune',
  180. Writable => 'int32s',
  181. Count => 2,
  182. PrintConv => 'sprintf("Red %+d, Blue %+d", split(" ", $val))',
  183. PrintConvInv => 'my @v=($val=~/-?\d+/g);"@v"',
  184. },
  185. 0x100b => { #2
  186. Name => 'NoiseReduction',
  187. Flags => 'PrintHex',
  188. Writable => 'int16u',
  189. PrintConv => {
  190. 0x40 => 'Low',
  191. 0x80 => 'Normal',
  192. 0x100 => 'n/a', #PH (NC) (all X100 samples)
  193. },
  194. },
  195. 0x100e => { #PH (X100)
  196. Name => 'HighISONoiseReduction',
  197. Flags => 'PrintHex',
  198. Writable => 'int16u',
  199. PrintConv => {
  200. 0x000 => 'Normal', # ("NR 0, ref 8)
  201. 0x100 => 'Strong', # ("NR+2, ref 8)
  202. 0x180 => 'Medium Strong', #8 ("NR+1")
  203. 0x200 => 'Weak', # ("NR-2, ref 8)
  204. 0x280 => 'Medium Weak', #8 ("NR-1")
  205. },
  206. },
  207. 0x1010 => {
  208. Name => 'FujiFlashMode',
  209. Writable => 'int16u',
  210. PrintConv => {
  211. 0 => 'Auto',
  212. 1 => 'On',
  213. 2 => 'Off',
  214. 3 => 'Red-eye reduction',
  215. 4 => 'External', #JD
  216. },
  217. },
  218. 0x1011 => {
  219. Name => 'FlashExposureComp', #JD
  220. Writable => 'rational64s',
  221. },
  222. 0x1020 => {
  223. Name => 'Macro',
  224. Writable => 'int16u',
  225. PrintConv => {
  226. 0 => 'Off',
  227. 1 => 'On',
  228. },
  229. },
  230. 0x1021 => {
  231. Name => 'FocusMode',
  232. Writable => 'int16u',
  233. PrintConv => {
  234. 0 => 'Auto',
  235. 1 => 'Manual',
  236. },
  237. },
  238. 0x1022 => { #8/forum6579
  239. Name => 'AFMode',
  240. Writable => 'int16u',
  241. Notes => '"No" for manual and some AF-multi focus modes',
  242. PrintConv => {
  243. 0 => 'No',
  244. 1 => 'Single Point',
  245. 256 => 'Zone',
  246. 512 => 'Wide/Tracking',
  247. },
  248. },
  249. 0x1023 => { #2
  250. Name => 'FocusPixel',
  251. Writable => 'int16u',
  252. Count => 2,
  253. },
  254. 0x1030 => {
  255. Name => 'SlowSync',
  256. Writable => 'int16u',
  257. PrintConv => {
  258. 0 => 'Off',
  259. 1 => 'On',
  260. },
  261. },
  262. 0x1031 => {
  263. Name => 'PictureMode',
  264. Flags => 'PrintHex',
  265. Writable => 'int16u',
  266. PrintConv => {
  267. 0x0 => 'Auto',
  268. 0x1 => 'Portrait',
  269. 0x2 => 'Landscape',
  270. 0x3 => 'Macro', #JD
  271. 0x4 => 'Sports',
  272. 0x5 => 'Night Scene',
  273. 0x6 => 'Program AE',
  274. 0x7 => 'Natural Light', #3
  275. 0x8 => 'Anti-blur', #3
  276. 0x9 => 'Beach & Snow', #JD
  277. 0xa => 'Sunset', #3
  278. 0xb => 'Museum', #3
  279. 0xc => 'Party', #3
  280. 0xd => 'Flower', #3
  281. 0xe => 'Text', #3
  282. 0xf => 'Natural Light & Flash', #3
  283. 0x10 => 'Beach', #3
  284. 0x11 => 'Snow', #3
  285. 0x12 => 'Fireworks', #3
  286. 0x13 => 'Underwater', #3
  287. 0x14 => 'Portrait with Skin Correction', #7
  288. 0x16 => 'Panorama', #PH (X100)
  289. 0x17 => 'Night (tripod)', #7
  290. 0x18 => 'Pro Low-light', #7
  291. 0x19 => 'Pro Focus', #7
  292. 0x1a => 'Portrait 2', #PH (NC, T500, maybe "Smile & Shoot"?)
  293. 0x1b => 'Dog Face Detection', #7
  294. 0x1c => 'Cat Face Detection', #7
  295. 0x40 => 'Advanced Filter',
  296. 0x100 => 'Aperture-priority AE',
  297. 0x200 => 'Shutter speed priority AE',
  298. 0x300 => 'Manual',
  299. },
  300. },
  301. 0x1032 => { #8
  302. Name => 'ExposureCount',
  303. Writable => 'int16u',
  304. Notes => 'number of exposures used for this image',
  305. },
  306. 0x1033 => { #6
  307. Name => 'EXRAuto',
  308. Writable => 'int16u',
  309. PrintConv => {
  310. 0 => 'Auto',
  311. 1 => 'Manual',
  312. },
  313. },
  314. 0x1034 => { #6
  315. Name => 'EXRMode',
  316. Writable => 'int16u',
  317. PrintHex => 1,
  318. PrintConv => {
  319. 0x100 => 'HR (High Resolution)',
  320. 0x200 => 'SN (Signal to Noise priority)',
  321. 0x300 => 'DR (Dynamic Range priority)',
  322. },
  323. },
  324. 0x1040 => { #8
  325. Name => 'ShadowTone',
  326. Writable => 'int32s',
  327. PrintConv => {
  328. -32 => 'Hard',
  329. -16 => 'Medium-hard',
  330. 0 => 'Normal',
  331. 16 => 'Medium-soft',
  332. 32 => 'Soft',
  333. },
  334. },
  335. 0x1041 => { #8
  336. Name => 'HighlightTone',
  337. Writable => 'int32s',
  338. PrintConv => {
  339. -32 => 'Hard',
  340. -16 => 'Medium-hard',
  341. 0 => 'Normal',
  342. 16 => 'Medium-soft',
  343. 32 => 'Soft',
  344. },
  345. },
  346. 0x1050 => { #forum6109
  347. Name => 'ShutterType',
  348. Writable => 'int16u',
  349. PrintConv => {
  350. 0 => 'Mechanical',
  351. 1 => 'Electronic',
  352. },
  353. },
  354. 0x1100 => {
  355. Name => 'AutoBracketing',
  356. Writable => 'int16u',
  357. PrintConv => {
  358. 0 => 'Off',
  359. 1 => 'On',
  360. 2 => 'No flash & flash', #3
  361. },
  362. },
  363. 0x1101 => {
  364. Name => 'SequenceNumber',
  365. Writable => 'int16u',
  366. },
  367. # (0x1150-0x1152 exist only for Pro Low-light and Pro Focus PictureModes)
  368. # 0x1150 - Pro Low-light - val=1; Pro Focus - val=2 (ref 7)
  369. # 0x1151 - Pro Low-light - val=4 (number of pictures taken?); Pro Focus - val=2,3 (ref 7)
  370. # 0x1152 - Pro Low-light - val=1,3,4 (stacked pictures used?); Pro Focus - val=1,2 (ref 7)
  371. 0x1201 => { #forum6109
  372. Name => 'AdvancedFilter',
  373. Writable => 'int32u',
  374. PrintHex => 1,
  375. PrintConv => {
  376. 0x10000 => 'Pop Color',
  377. 0x20000 => 'Hi Key',
  378. 0x30000 => 'Toy Camera',
  379. 0x40000 => 'Miniature',
  380. 0x50000 => 'Dynamic Tone',
  381. 0x60001 => 'Partial Color Red',
  382. 0x60002 => 'Partial Color Yellow',
  383. 0x60003 => 'Partial Color Green',
  384. 0x60004 => 'Partial Color Blue',
  385. 0x60005 => 'Partial Color Orange',
  386. 0x60006 => 'Partial Color Purple',
  387. 0x70000 => 'Soft Focus',
  388. 0x90000 => 'Low Key',
  389. },
  390. },
  391. 0x1210 => { #2
  392. Name => 'ColorMode',
  393. Writable => 'int16u',
  394. PrintHex => 1,
  395. PrintConv => {
  396. 0x00 => 'Standard',
  397. 0x10 => 'Chrome',
  398. 0x30 => 'B & W',
  399. },
  400. },
  401. 0x1300 => {
  402. Name => 'BlurWarning',
  403. Writable => 'int16u',
  404. PrintConv => {
  405. 0 => 'None',
  406. 1 => 'Blur Warning',
  407. },
  408. },
  409. 0x1301 => {
  410. Name => 'FocusWarning',
  411. Writable => 'int16u',
  412. PrintConv => {
  413. 0 => 'Good',
  414. 1 => 'Out of focus',
  415. },
  416. },
  417. 0x1302 => {
  418. Name => 'ExposureWarning',
  419. Writable => 'int16u',
  420. PrintConv => {
  421. 0 => 'Good',
  422. 1 => 'Bad exposure',
  423. },
  424. },
  425. 0x1304 => { #PH
  426. Name => 'GEImageSize',
  427. Condition => '$$self{Make} =~ /^GENERAL IMAGING/',
  428. Writable => 'string',
  429. Notes => 'GE models only',
  430. },
  431. 0x1400 => { #2
  432. Name => 'DynamicRange',
  433. Writable => 'int16u',
  434. PrintConv => {
  435. 1 => 'Standard',
  436. 3 => 'Wide',
  437. # the S5Pro has 100%(STD),130%,170%,230%(W1),300%,400%(W2) - PH
  438. },
  439. },
  440. 0x1401 => { #2 (this doesn't seem to work for the X100 - PH)
  441. Name => 'FilmMode',
  442. Writable => 'int16u',
  443. PrintHex => 1,
  444. PrintConv => {
  445. 0x000 => 'F0/Standard (Provia)',
  446. 0x100 => 'F1/Studio Portrait',
  447. 0x110 => 'F1a/Studio Portrait Enhanced Saturation',
  448. 0x120 => 'F1b/Studio Portrait Smooth Skin Tone (Astia)',
  449. 0x130 => 'F1c/Studio Portrait Increased Sharpness',
  450. 0x200 => 'F2/Fujichrome (Velvia)',
  451. 0x300 => 'F3/Studio Portrait Ex',
  452. 0x400 => 'F4/Velvia',
  453. 0x500 => 'Pro Neg. Std', #PH (X-Pro1)
  454. 0x501 => 'Pro Neg. Hi', #PH (X-Pro1)
  455. 0x600 => 'Classic Chrome', #forum6109
  456. },
  457. },
  458. 0x1402 => { #2
  459. Name => 'DynamicRangeSetting',
  460. Writable => 'int16u',
  461. PrintHex => 1,
  462. PrintConv => {
  463. 0x000 => 'Auto (100-400%)',
  464. 0x001 => 'Manual', #(ref http://forum.photome.de/viewtopic.php?f=2&t=353)
  465. 0x100 => 'Standard (100%)',
  466. 0x200 => 'Wide1 (230%)',
  467. 0x201 => 'Wide2 (400%)',
  468. 0x8000 => 'Film Simulation',
  469. },
  470. },
  471. 0x1403 => { #2 (only valid for manual DR, ref 6)
  472. Name => 'DevelopmentDynamicRange',
  473. Writable => 'int16u',
  474. },
  475. 0x1404 => { #2
  476. Name => 'MinFocalLength',
  477. Writable => 'rational64s',
  478. },
  479. 0x1405 => { #2
  480. Name => 'MaxFocalLength',
  481. Writable => 'rational64s',
  482. },
  483. 0x1406 => { #2
  484. Name => 'MaxApertureAtMinFocal',
  485. Writable => 'rational64s',
  486. },
  487. 0x1407 => { #2
  488. Name => 'MaxApertureAtMaxFocal',
  489. Writable => 'rational64s',
  490. },
  491. # 0x1408 - values: '0100', 'S100', 'VQ10'
  492. # 0x1409 - values: same as 0x1408
  493. # 0x140a - values: 0, 1, 3, 5, 7
  494. 0x140b => { #6
  495. Name => 'AutoDynamicRange',
  496. Writable => 'int16u',
  497. PrintConv => '"$val%"',
  498. PrintConvInv => '$val=~s/\s*\%$//; $val',
  499. },
  500. 0x1422 => { #8
  501. Name => 'ImageStabilization',
  502. Writable => 'int16u',
  503. Count => 3,
  504. PrintConv => [{
  505. 0 => 'None',
  506. 1 => 'Optical', #PH
  507. 2 => 'Sensor-shift', #PH
  508. 512 => 'Digital', #PH
  509. },{
  510. 0 => 'Off',
  511. 1 => 'On (mode 1, continuous)',
  512. 2 => 'On (mode 2, shooting only)',
  513. }],
  514. },
  515. 0x1431 => { #forum6109
  516. Name => 'Rating',
  517. Groups => { 2 => 'Image' },
  518. Writable => 'int32u',
  519. Priority => 0,
  520. },
  521. 0x1436 => { #8
  522. Name => 'ImageGeneration',
  523. Writable => 'int16u',
  524. PrintConv => {
  525. 0 => 'Original Image',
  526. 1 => 'Re-developed from RAW',
  527. },
  528. },
  529. 0x1438 => { #forum6579 (X-T1 firmware version 3)
  530. Name => 'ImageCount',
  531. Notes => 'may reset to 0 when new firmware is installed',
  532. Writable => 'int16u',
  533. ValueConv => '$val & 0x7fff',
  534. ValueConvInv => '$val | 0x8000',
  535. },
  536. 0x3820 => { #PH (HS20EXR MOV)
  537. Name => 'FrameRate',
  538. Writable => 'int16u',
  539. Groups => { 2 => 'Video' },
  540. },
  541. 0x3821 => { #PH (HS20EXR MOV)
  542. Name => 'FrameWidth',
  543. Writable => 'int16u',
  544. Groups => { 2 => 'Video' },
  545. },
  546. 0x3822 => { #PH (HS20EXR MOV)
  547. Name => 'FrameHeight',
  548. Writable => 'int16u',
  549. Groups => { 2 => 'Video' },
  550. },
  551. 0x4100 => { #PH
  552. Name => 'FacesDetected',
  553. Writable => 'int16u',
  554. },
  555. 0x4103 => { #PH
  556. Name => 'FacePositions',
  557. Writable => 'int16u',
  558. Count => -1,
  559. Notes => q{
  560. left, top, right and bottom coordinates in full-sized image for each face
  561. detected
  562. },
  563. },
  564. # 0x4101-0x4105 - exist only if face detection active
  565. # 0x4104 - also related to face detection (same number of entries as FacePositions)
  566. # 0x4200 - same as 0x4100?
  567. # 0x4203 - same as 0x4103
  568. # 0x4204 - same as 0x4104
  569. 0x4282 => { #PH
  570. Name => 'FaceRecInfo',
  571. SubDirectory => { TagTable => 'Image::ExifTool::FujiFilm::FaceRecInfo' },
  572. },
  573. 0x8000 => { #2
  574. Name => 'FileSource',
  575. Writable => 'string',
  576. },
  577. 0x8002 => { #2
  578. Name => 'OrderNumber',
  579. Writable => 'int32u',
  580. },
  581. 0x8003 => { #2
  582. Name => 'FrameNumber',
  583. Writable => 'int16u',
  584. },
  585. 0xb211 => { #PH
  586. Name => 'Parallax',
  587. # (value set in camera is -0.5 times this value in MPImage2... why?)
  588. Writable => 'rational64s',
  589. Notes => 'only found in MPImage2 of .MPO images',
  590. },
  591. # 0xb212 - also found in MPIMage2 images - PH
  592. );
  593. # Face recognition information from FinePix F550EXR (ref PH)
  594. %Image::ExifTool::FujiFilm::FaceRecInfo = (
  595. PROCESS_PROC => \&ProcessFaceRec,
  596. GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
  597. VARS => { NO_ID => 1 },
  598. NOTES => 'Face recognition information.',
  599. Face1Name => { },
  600. Face2Name => { },
  601. Face3Name => { },
  602. Face4Name => { },
  603. Face5Name => { },
  604. Face6Name => { },
  605. Face7Name => { },
  606. Face8Name => { },
  607. Face1Category => { %faceCategories },
  608. Face2Category => { %faceCategories },
  609. Face3Category => { %faceCategories },
  610. Face4Category => { %faceCategories },
  611. Face5Category => { %faceCategories },
  612. Face6Category => { %faceCategories },
  613. Face7Category => { %faceCategories },
  614. Face8Category => { %faceCategories },
  615. Face1Birthday => { },
  616. Face2Birthday => { },
  617. Face3Birthday => { },
  618. Face4Birthday => { },
  619. Face5Birthday => { },
  620. Face6Birthday => { },
  621. Face7Birthday => { },
  622. Face8Birthday => { },
  623. );
  624. # tags in RAF images (ref 5)
  625. %Image::ExifTool::FujiFilm::RAF = (
  626. PROCESS_PROC => \&ProcessFujiDir,
  627. GROUPS => { 0 => 'RAF', 1 => 'RAF', 2 => 'Image' },
  628. PRIORITY => 0, # so the first RAF directory takes precedence
  629. NOTES => q{
  630. FujiFilm RAF images contain meta information stored in a proprietary
  631. FujiFilm RAF format, as well as EXIF information stored inside an embedded
  632. JPEG preview image. The table below lists tags currently decoded from the
  633. RAF-format information.
  634. },
  635. 0x100 => {
  636. Name => 'RawImageFullSize',
  637. Format => 'int16u',
  638. Groups => { 1 => 'RAF2' }, # (so RAF2 shows up in family 1 list)
  639. Count => 2,
  640. Notes => 'including borders',
  641. ValueConv => 'my @v=reverse split(" ",$val);"@v"',
  642. PrintConv => '$val=~tr/ /x/; $val',
  643. },
  644. 0x121 => [
  645. {
  646. Name => 'RawImageSize',
  647. Condition => '$$self{Model} eq "FinePixS2Pro"',
  648. Format => 'int16u',
  649. Count => 2,
  650. ValueConv => q{
  651. my @v=split(" ",$val);
  652. $v[0]*=2, $v[1]/=2;
  653. return "@v";
  654. },
  655. PrintConv => '$val=~tr/ /x/; $val',
  656. },
  657. {
  658. Name => 'RawImageSize',
  659. Format => 'int16u',
  660. Count => 2,
  661. # values are height then width, adjusted for the layout
  662. ValueConv => q{
  663. my @v=reverse split(" ",$val);
  664. $$self{FujiLayout} and $v[0]/=2, $v[1]*=2;
  665. return "@v";
  666. },
  667. PrintConv => '$val=~tr/ /x/; $val',
  668. },
  669. ],
  670. 0x130 => {
  671. Name => 'FujiLayout',
  672. Format => 'int8u',
  673. RawConv => q{
  674. my ($v) = split ' ', $val;
  675. $$self{FujiLayout} = $v & 0x80 ? 1 : 0;
  676. return $val;
  677. },
  678. },
  679. 0x131 => { #5
  680. Name => 'XTransLayout',
  681. Description => 'X-Trans Layout',
  682. Format => 'int8u',
  683. Count => 36,
  684. PrintConv => '$val =~ tr/012 /RGB/d; join " ", $val =~ /....../g',
  685. },
  686. 0x2000 => { #9
  687. Name => 'WB_GRGBLevelsAuto',
  688. Format => 'int16u',
  689. Count => 4, # (ignore the duplicate values)
  690. },
  691. 0x2100 => { #9
  692. Name => 'WB_GRGBLevelsDaylight',
  693. Format => 'int16u',
  694. Count => 4,
  695. },
  696. 0x2200 => { #9
  697. Name => 'WB_GRGBLevelsCloudy',
  698. Format => 'int16u',
  699. Count => 4,
  700. },
  701. 0x2300 => { #9
  702. Name => 'WB_GRGBLevelsDaylightFluor',
  703. Format => 'int16u',
  704. Count => 4,
  705. },
  706. 0x2301 => { #9
  707. Name => 'WB_GRGBLevelsDayWhiteFluor',
  708. Format => 'int16u',
  709. Count => 4,
  710. },
  711. 0x2302 => { #9
  712. Name => 'WB_GRGBLevelsWhiteFluorescent',
  713. Format => 'int16u',
  714. Count => 4,
  715. },
  716. 0x2310 => { #9
  717. Name => 'WB_GRGBLevelsWarmWhiteFluor',
  718. Format => 'int16u',
  719. Count => 4,
  720. },
  721. 0x2311 => { #9
  722. Name => 'WB_GRGBLevelsLivingRoomWarmWhiteFluor',
  723. Format => 'int16u',
  724. Count => 4,
  725. },
  726. 0x2400 => { #9
  727. Name => 'WB_GRGBLevelsTungsten',
  728. Format => 'int16u',
  729. Count => 4,
  730. },
  731. # 0x2f00 => WB_GRGBLevelsCustom: int32u count, then count * (int16u GRGBGRGB), ref 9
  732. 0x2ff0 => {
  733. Name => 'WB_GRGBLevels',
  734. Format => 'int16u',
  735. Count => 4,
  736. },
  737. 0x9650 => { #Frank Markesteijn
  738. Name => 'RawExposureBias',
  739. Format => 'rational32s',
  740. },
  741. 0xc000 => {
  742. Name => 'RAFData',
  743. SubDirectory => {
  744. TagTable => 'Image::ExifTool::FujiFilm::RAFData',
  745. ByteOrder => 'Little-endian',
  746. }
  747. },
  748. );
  749. %Image::ExifTool::FujiFilm::RAFData = (
  750. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  751. GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
  752. DATAMEMBER => [ 0, 4, 8 ],
  753. FIRST_ENTRY => 0,
  754. # (FujiFilm image dimensions are REALLY confusing)
  755. # --> this needs some cleaning up
  756. 0 => {
  757. Name => 'RawImageWidth',
  758. Format => 'int32u',
  759. DataMember => 'FujiWidth',
  760. RawConv => '$val < 10000 ? $$self{FujiWidth} = $val : undef', #5
  761. ValueConv => '$$self{FujiLayout} ? ($val / 2) : $val',
  762. },
  763. 4 => [
  764. {
  765. Name => 'RawImageWidth',
  766. Condition => 'not $$self{FujiWidth}',
  767. Format => 'int32u',
  768. DataMember => 'FujiWidth',
  769. RawConv => '$val < 10000 ? $$self{FujiWidth} = $val : undef', #PH
  770. ValueConv => '$$self{FujiLayout} ? ($val / 2) : $val',
  771. },
  772. {
  773. Name => 'RawImageHeight',
  774. Format => 'int32u',
  775. DataMember => 'FujiHeight',
  776. RawConv => '$$self{FujiHeight} = $val',
  777. ValueConv => '$$self{FujiLayout} ? ($val * 2) : $val',
  778. },
  779. ],
  780. 8 => [
  781. {
  782. Name => 'RawImageWidth',
  783. Condition => 'not $$self{FujiWidth}',
  784. Format => 'int32u',
  785. DataMember => 'FujiWidth',
  786. RawConv => '$val < 10000 ? $$self{FujiWidth} = $val : undef', #PH
  787. ValueConv => '$$self{FujiLayout} ? ($val / 2) : $val',
  788. },
  789. {
  790. Name => 'RawImageHeight',
  791. Condition => 'not $$self{FujiHeight}',
  792. Format => 'int32u',
  793. DataMember => 'FujiHeight',
  794. RawConv => '$$self{FujiHeight} = $val',
  795. ValueConv => '$$self{FujiLayout} ? ($val * 2) : $val',
  796. },
  797. ],
  798. 12 => {
  799. Name => 'RawImageHeight',
  800. Condition => 'not $$self{FujiHeight}',
  801. Format => 'int32u',
  802. ValueConv => '$$self{FujiLayout} ? ($val * 2) : $val',
  803. },
  804. );
  805. # TIFF IFD-format information stored in FujiFilm RAF images (ref 5)
  806. %Image::ExifTool::FujiFilm::IFD = (
  807. PROCESS_PROC => \&Image::ExifTool::Exif::ProcessExif,
  808. GROUPS => { 0 => 'RAF', 1 => 'FujiIFD', 2 => 'Image' },
  809. NOTES => 'Tags found in the FujiIFD information of RAF images from some models.',
  810. 0xf000 => {
  811. Name => 'FujiIFD',
  812. Groups => { 1 => 'FujiIFD' },
  813. Flags => 'SubIFD',
  814. SubDirectory => {
  815. TagTable => 'Image::ExifTool::FujiFilm::IFD',
  816. DirName => 'FujiSubIFD',
  817. Start => '$val',
  818. },
  819. },
  820. 0xf001 => 'RawImageFullWidth',
  821. 0xf002 => 'RawImageFullHeight',
  822. 0xf003 => 'BitsPerSample',
  823. # 0xf004 - values: 4
  824. # 0xf005 - values: 1374, 1668
  825. # 0xf006 - some sort of flag indicating packed format?
  826. 0xf007 => {
  827. Name => 'StripOffsets',
  828. IsOffset => 1,
  829. OffsetPair => 0xf008, # point to associated byte counts
  830. },
  831. 0xf008 => {
  832. Name => 'StripByteCounts',
  833. OffsetPair => 0xf007, # point to associated offsets
  834. },
  835. # 0xf009 - values: 0, 3
  836. 0xf00a => 'BlackLevel', #9
  837. # 0xf00b ?
  838. 0xf00c => 'WB_GRBLevelsStandard', #9 (GRBXGRBX; X=17 is standard illuminant A, X=21 is D65)
  839. 0xf00d => 'WB_GRBLevelsAuto', #9
  840. 0xf00e => 'WB_GRBLevels',
  841. # 0xf00f ?
  842. );
  843. # information found in FFMV atom of MOV videos
  844. %Image::ExifTool::FujiFilm::FFMV = (
  845. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  846. GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
  847. FIRST_ENTRY => 0,
  848. NOTES => 'Information found in the FFMV atom of MOV videos.',
  849. 0 => {
  850. Name => 'MovieStreamName',
  851. Format => 'string[34]',
  852. },
  853. );
  854. # tags in FujiFilm QuickTime videos (ref PH)
  855. # (similar information in Kodak,Minolta,Nikon,Olympus,Pentax and Sanyo videos)
  856. %Image::ExifTool::FujiFilm::MOV = (
  857. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  858. GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
  859. FIRST_ENTRY => 0,
  860. NOTES => 'This information is found in MOV videos from some FujiFilm cameras.',
  861. 0x00 => {
  862. Name => 'Make',
  863. Format => 'string[24]',
  864. },
  865. 0x18 => {
  866. Name => 'Model',
  867. Description => 'Camera Model Name',
  868. Format => 'string[16]',
  869. },
  870. 0x2e => { # (NC)
  871. Name => 'ExposureTime',
  872. Format => 'int32u',
  873. ValueConv => '$val ? 1 / $val : 0',
  874. PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
  875. },
  876. 0x32 => {
  877. Name => 'FNumber',
  878. Format => 'rational64u',
  879. PrintConv => 'sprintf("%.1f",$val)',
  880. },
  881. 0x3a => { # (NC)
  882. Name => 'ExposureCompensation',
  883. Format => 'rational64s',
  884. PrintConv => '$val ? sprintf("%+.1f", $val) : 0',
  885. },
  886. );
  887. #------------------------------------------------------------------------------
  888. # decode information from FujiFilm face recognition information
  889. # Inputs: 0) ExifTool object reference, 1) dirInfo reference, 2) tag table ref
  890. # Returns: 1
  891. sub ProcessFaceRec($$$)
  892. {
  893. my ($et, $dirInfo, $tagTablePtr) = @_;
  894. my $dataPt = $$dirInfo{DataPt};
  895. my $dataPos = $$dirInfo{DataPos} + ($$dirInfo{Base} || 0);
  896. my $dirStart = $$dirInfo{DirStart};
  897. my $dirLen = $$dirInfo{DirLen};
  898. my $pos = $dirStart;
  899. my $end = $dirStart + $dirLen;
  900. my ($i, $n, $p, $val);
  901. $et->VerboseDir('FaceRecInfo');
  902. for ($i=1; ; ++$i) {
  903. last if $pos + 8 > $end;
  904. my $off = Get32u($dataPt, $pos) + $dirStart;
  905. my $len = Get32u($dataPt, $pos + 4);
  906. last if $len==0 or $off>$end or $off+$len>$end or $len < 62;
  907. # values observed for each offset (always zero if not listed):
  908. # 0=5; 3=1; 4=4; 6=1; 10-13=numbers(constant for a given registered face)
  909. # 15=16; 16=3; 18=1; 22=nameLen; 26=1; 27=16; 28=7; 30-33=nameLen(int32u)
  910. # 34-37=nameOffset(int32u); 38=32; 39=16; 40=4; 42=1; 46=0,2,4,8(category)
  911. # 50=33; 51=16; 52=7; 54-57=dateLen(int32u); 58-61=dateOffset(int32u)
  912. $n = Get32u($dataPt, $off + 30);
  913. $p = Get32u($dataPt, $off + 34) + $dirStart;
  914. last if $p < $dirStart or $p + $n > $end;
  915. $val = substr($$dataPt, $p, $n);
  916. $et->HandleTag($tagTablePtr, "Face${i}Name", $val,
  917. DataPt => $dataPt,
  918. DataPos => $dataPos,
  919. Start => $p,
  920. Size => $n,
  921. );
  922. $n = Get32u($dataPt, $off + 54);
  923. $p = Get32u($dataPt, $off + 58) + $dirStart;
  924. last if $p < $dirStart or $p + $n > $end;
  925. $val = substr($$dataPt, $p, $n);
  926. $val =~ s/(\d{4})(\d{2})(\d{2})/$1:$2:$2/;
  927. $et->HandleTag($tagTablePtr, "Face${i}Birthday", $val,
  928. DataPt => $dataPt,
  929. DataPos => $dataPos,
  930. Start => $p,
  931. Size => $n,
  932. );
  933. $et->HandleTag($tagTablePtr, "Face${i}Category", undef,
  934. DataPt => $dataPt,
  935. DataPos => $dataPos,
  936. Start => $off + 46,
  937. Size => 1,
  938. );
  939. $pos += 8;
  940. }
  941. return 1;
  942. }
  943. #------------------------------------------------------------------------------
  944. # get information from FujiFilm RAF directory
  945. # Inputs: 0) ExifTool object reference, 1) dirInfo reference, 2) tag table ref
  946. # Returns: 1 if this was a valid FujiFilm directory
  947. sub ProcessFujiDir($$$)
  948. {
  949. my ($et, $dirInfo, $tagTablePtr) = @_;
  950. my $raf = $$dirInfo{RAF};
  951. my $offset = $$dirInfo{DirStart};
  952. $raf->Seek($offset, 0) or return 0;
  953. my ($buff, $index);
  954. $raf->Read($buff, 4) or return 0;
  955. my $entries = unpack 'N', $buff;
  956. $entries < 256 or return 0;
  957. $et->Options('Verbose') and $et->VerboseDir('Fuji', $entries);
  958. SetByteOrder('MM');
  959. my $pos = $offset + 4;
  960. for ($index=0; $index<$entries; ++$index) {
  961. $raf->Read($buff,4) or return 0;
  962. $pos += 4;
  963. my ($tag, $len) = unpack 'nn', $buff;
  964. my ($val, $vbuf);
  965. $raf->Read($vbuf, $len) or return 0;
  966. my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
  967. if ($tagInfo and $$tagInfo{Format}) {
  968. $val = ReadValue(\$vbuf, 0, $$tagInfo{Format}, $$tagInfo{Count}, $len);
  969. next unless defined $val;
  970. } elsif ($len == 4) {
  971. # interpret unknown 4-byte values as int32u
  972. $val = Get32u(\$vbuf, 0);
  973. } else {
  974. # treat other unknown values as binary data
  975. $val = \$vbuf;
  976. }
  977. $et->HandleTag($tagTablePtr, $tag, $val,
  978. Index => $index,
  979. DataPt => \$vbuf,
  980. DataPos => $pos,
  981. Size => $len,
  982. TagInfo => $tagInfo,
  983. );
  984. $pos += $len;
  985. }
  986. return 1;
  987. }
  988. #------------------------------------------------------------------------------
  989. # write information to FujiFilm RAW file (RAF)
  990. # Inputs: 0) ExifTool object reference, 1) dirInfo reference
  991. # Returns: 1 on success, 0 if this wasn't a valid RAF file, or -1 on write error
  992. sub WriteRAF($$)
  993. {
  994. my ($et, $dirInfo) = @_;
  995. my $raf = $$dirInfo{RAF};
  996. my ($hdr, $jpeg, $outJpeg, $offset, $err, $buff);
  997. $raf->Read($hdr,0x94) == 0x94 or return 0;
  998. $hdr =~ /^FUJIFILM/ or return 0;
  999. my $ver = substr($hdr, 0x3c, 4);
  1000. $ver =~ /^\d{4}$/ or return 0;
  1001. # get the position and size of embedded JPEG
  1002. my ($jpos, $jlen) = unpack('x84NN', $hdr);
  1003. # check to be sure the JPEG starts in the expected location
  1004. if ($jpos > 0x94 or $jpos < 0x68 or $jpos & 0x03) {
  1005. $et->Error("Unsupported or corrupted RAF image (version $ver)");
  1006. return 1;
  1007. }
  1008. # check to make sure this version of RAF has been tested
  1009. unless ($testedRAF{$ver}) {
  1010. $et->Warn("RAF version $ver not yet tested", 1);
  1011. }
  1012. # read the embedded JPEG
  1013. unless ($raf->Seek($jpos, 0) and $raf->Read($jpeg, $jlen) == $jlen) {
  1014. $et->Error('Error reading RAF meta information');
  1015. return 1;
  1016. }
  1017. # use same write directories as JPEG
  1018. $et->InitWriteDirs('JPEG');
  1019. # rewrite the embedded JPEG in memory
  1020. my %jpegInfo = (
  1021. Parent => 'RAF',
  1022. RAF => new File::RandomAccess(\$jpeg),
  1023. OutFile => \$outJpeg,
  1024. );
  1025. $$et{FILE_TYPE} = 'JPEG';
  1026. my $success = $et->WriteJPEG(\%jpegInfo);
  1027. $$et{FILE_TYPE} = 'RAF';
  1028. unless ($success and $outJpeg) {
  1029. $et->Error("Invalid RAF format");
  1030. return 1;
  1031. }
  1032. return -1 if $success < 0;
  1033. # rewrite the RAF image
  1034. SetByteOrder('MM');
  1035. my $jpegLen = length $outJpeg;
  1036. # pad JPEG to an even 4 bytes (ALWAYS use padding as Fuji does)
  1037. my $pad = "\0" x (4 - ($jpegLen % 4));
  1038. # update JPEG size in header (size without padding)
  1039. Set32u(length($outJpeg), \$hdr, 0x58);
  1040. # get pointer to start of the next RAF block
  1041. my $nextPtr = Get32u(\$hdr, 0x5c);
  1042. # determine the length of padding at the end of the original JPEG
  1043. my $oldPadLen = $nextPtr - ($jpos + $jlen);
  1044. if ($oldPadLen) {
  1045. if ($oldPadLen > 1000000 or $oldPadLen < 0 or
  1046. not $raf->Seek($jpos+$jlen, 0) or
  1047. $raf->Read($buff, $oldPadLen) != $oldPadLen)
  1048. {
  1049. $et->Error('Bad RAF pointer at 0x5c');
  1050. return 1;
  1051. }
  1052. # make sure padding is only zero bytes (can be >100k for HS10)
  1053. # (have seen non-null padding in X-Pro1)
  1054. if ($buff =~ /[^\0]/) {
  1055. return 1 if $et->Error('Non-null bytes found in padding', 2);
  1056. }
  1057. }
  1058. # calculate offset difference due to change in JPEG size
  1059. my $ptrDiff = length($outJpeg) + length($pad) - ($jlen + $oldPadLen);
  1060. # update necessary pointers in header
  1061. foreach $offset (0x5c, 0x64, 0x78, 0x80) {
  1062. last if $offset >= $jpos; # some versions have a short header
  1063. my $oldPtr = Get32u(\$hdr, $offset);
  1064. next unless $oldPtr; # don't update if pointer is zero
  1065. Set32u($oldPtr + $ptrDiff, \$hdr, $offset);
  1066. }
  1067. # write the new header
  1068. my $outfile = $$dirInfo{OutFile};
  1069. Write($outfile, substr($hdr, 0, $jpos)) or $err = 1;
  1070. # write the updated JPEG plus padding
  1071. Write($outfile, $outJpeg, $pad) or $err = 1;
  1072. # copy over the rest of the RAF image
  1073. unless ($raf->Seek($nextPtr, 0)) {
  1074. $et->Error('Error reading RAF image');
  1075. return 1;
  1076. }
  1077. while ($raf->Read($buff, 65536)) {
  1078. Write($outfile, $buff) or $err = 1, last;
  1079. }
  1080. return $err ? -1 : 1;
  1081. }
  1082. #------------------------------------------------------------------------------
  1083. # get information from FujiFilm RAW file (RAF)
  1084. # Inputs: 0) ExifTool object reference, 1) dirInfo reference
  1085. # Returns: 1 if this was a valid RAF file
  1086. sub ProcessRAF($$)
  1087. {
  1088. my ($et, $dirInfo) = @_;
  1089. my ($buff, $jpeg, $warn, $offset);
  1090. my $raf = $$dirInfo{RAF};
  1091. $raf->Read($buff,0x5c) == 0x5c or return 0;
  1092. $buff =~ /^FUJIFILM/ or return 0;
  1093. my ($jpos, $jlen) = unpack('x84NN', $buff);
  1094. $jpos & 0x8000 and return 0;
  1095. $raf->Seek($jpos, 0) or return 0;
  1096. $raf->Read($jpeg, $jlen) == $jlen or return 0;
  1097. $et->SetFileType();
  1098. $et->FoundTag('RAFVersion', substr($buff, 0x3c, 4));
  1099. # extract information from embedded JPEG
  1100. my %dirInfo = (
  1101. Parent => 'RAF',
  1102. RAF => new File::RandomAccess(\$jpeg),
  1103. );
  1104. $$et{BASE} += $jpos;
  1105. my $rtnVal = $et->ProcessJPEG(\%dirInfo);
  1106. $$et{BASE} -= $jpos;
  1107. $et->FoundTag('PreviewImage', \$jpeg) if $rtnVal;
  1108. # extract information from Fuji RAF and TIFF directories
  1109. my ($rafNum, $ifdNum) = ('','');
  1110. foreach $offset (0x5c, 0x64, 0x78, 0x80) {
  1111. last if $offset >= $jpos;
  1112. unless ($raf->Seek($offset, 0) and $raf->Read($buff, 4)) {
  1113. $warn = 1;
  1114. last;
  1115. }
  1116. my $start = unpack('N',$buff);
  1117. next unless $start;
  1118. if ($offset == 0x64 or $offset == 0x80) {
  1119. # parse FujiIFD directory
  1120. %dirInfo = (
  1121. RAF => $raf,
  1122. Base => $start,
  1123. );
  1124. $$et{SET_GROUP1} = "FujiIFD$ifdNum";
  1125. my $tagTablePtr = GetTagTable('Image::ExifTool::FujiFilm::IFD');
  1126. # this is TIFF-format data only for some models, so no warning if it fails
  1127. $et->ProcessTIFF(\%dirInfo, $tagTablePtr, \&Image::ExifTool::ProcessTIFF);
  1128. delete $$et{SET_GROUP1};
  1129. $ifdNum = ($ifdNum || 1) + 1;
  1130. } else {
  1131. # parse RAF directory
  1132. %dirInfo = (
  1133. RAF => $raf,
  1134. DirStart => $start,
  1135. );
  1136. $$et{SET_GROUP1} = "RAF$rafNum";
  1137. my $tagTablePtr = GetTagTable('Image::ExifTool::FujiFilm::RAF');
  1138. $et->ProcessDirectory(\%dirInfo, $tagTablePtr) or $warn = 1;
  1139. delete $$et{SET_GROUP1};
  1140. $rafNum = ($rafNum || 1) + 1;
  1141. }
  1142. }
  1143. $warn and $et->Warn('Possibly corrupt RAF information');
  1144. return $rtnVal;
  1145. }
  1146. 1; # end
  1147. __END__
  1148. =head1 NAME
  1149. Image::ExifTool::FujiFilm - Read/write FujiFilm maker notes and RAF images
  1150. =head1 SYNOPSIS
  1151. This module is loaded automatically by Image::ExifTool when required.
  1152. =head1 DESCRIPTION
  1153. This module contains definitions required by Image::ExifTool to interpret
  1154. FujiFilm maker notes in EXIF information, and to read/write FujiFilm RAW
  1155. (RAF) images.
  1156. =head1 AUTHOR
  1157. Copyright 2003-2016, Phil Harvey (phil at owl.phy.queensu.ca)
  1158. This library is free software; you can redistribute it and/or modify it
  1159. under the same terms as Perl itself.
  1160. =head1 REFERENCES
  1161. =over 4
  1162. =item L<http://park2.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html>
  1163. =item L<http://homepage3.nifty.com/kamisaka/makernote/makernote_fuji.htm>
  1164. =item L<http://www.cybercom.net/~dcoffin/dcraw/>
  1165. =item (...plus testing with my own FinePix 2400 Zoom)
  1166. =back
  1167. =head1 ACKNOWLEDGEMENTS
  1168. Thanks to Michael Meissner, Paul Samuelson and Jens Duttke for help decoding
  1169. some FujiFilm information.
  1170. =head1 SEE ALSO
  1171. L<Image::ExifTool::TagNames/FujiFilm Tags>,
  1172. L<Image::ExifTool(3pm)|Image::ExifTool>
  1173. =cut