Samsung.pm 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168
  1. #------------------------------------------------------------------------------
  2. # File: Samsung.pm
  3. #
  4. # Description: Samsung EXIF maker notes tags
  5. #
  6. # Revisions: 2010/03/01 - P. Harvey Created
  7. #
  8. # References: 1) Tae-Sun Park private communication
  9. # 2) http://www.cybercom.net/~dcoffin/dcraw/
  10. # 3) Pascal de Bruijn private communication (NX100)
  11. # 4) Jaroslav Stepanek via rt.cpan.org
  12. # 5) Niels Kristian Bech Jensen private communication
  13. # 6) Nick Livchits private communication
  14. # 7) Iliah Borg private communcation (LibRaw)
  15. #------------------------------------------------------------------------------
  16. package Image::ExifTool::Samsung;
  17. use strict;
  18. use vars qw($VERSION %samsungLensTypes);
  19. use Image::ExifTool qw(:DataAccess :Utils);
  20. use Image::ExifTool::Exif;
  21. $VERSION = '1.31';
  22. sub WriteSTMN($$$);
  23. sub ProcessINFO($$$);
  24. sub ProcessSamsungIFD($$$);
  25. # Samsung LensType lookup
  26. %samsungLensTypes = (
  27. # (added "Samsung NX" in all of these lens names - ref 4)
  28. 0 => 'Built-in or Manual Lens', #PH (EX1, WB2000)
  29. 1 => 'Samsung NX 30mm F2 Pancake',
  30. 2 => 'Samsung NX 18-55mm F3.5-5.6 OIS', # (also version II, ref 1)
  31. 3 => 'Samsung NX 50-200mm F4-5.6 ED OIS',
  32. # what about the non-OIS version of the 18-55,
  33. # which was supposed to be available before the 20-50? - PH
  34. 4 => 'Samsung NX 20-50mm F3.5-5.6 ED', #PH/4
  35. 5 => 'Samsung NX 20mm F2.8 Pancake', #PH
  36. 6 => 'Samsung NX 18-200mm F3.5-6.3 ED OIS', #4
  37. 7 => 'Samsung NX 60mm F2.8 Macro ED OIS SSA', #1
  38. 8 => 'Samsung NX 16mm F2.4 Pancake', #1/4
  39. 9 => 'Samsung NX 85mm F1.4 ED SSA', #4
  40. 10 => 'Samsung NX 45mm F1.8', #3
  41. 11 => 'Samsung NX 45mm F1.8 2D/3D', #3
  42. 12 => 'Samsung NX 12-24mm F4-5.6 ED', #4
  43. 13 => 'Saumsun NX 16-50mm F2-2.8 S ED OIS', #forum3833
  44. 14 => 'Samsung NX 10mm F3.5 Fisheye', #5
  45. 15 => 'Samsung NX 16-50mm F3.5-5.6 Power Zoom ED OIS', #6
  46. 20 => 'Samsung NX 50-150mm F2.8 S ED OIS', #PH
  47. 21 => 'Samsung NX 300mm F2.8 ED OIS', #7
  48. );
  49. # range of values for Formats used in encrypted information
  50. my %formatMinMax = (
  51. int16u => [ 0, 65535 ],
  52. int32u => [ 0, 4294967295 ],
  53. int16s => [ -32768, 32767 ],
  54. int32s => [ -2147483648, 2147483647 ],
  55. );
  56. # Samsung "STMN" maker notes (ref PH)
  57. %Image::ExifTool::Samsung::Main = (
  58. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  59. WRITE_PROC => \&WriteSTMN,
  60. CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
  61. WRITABLE => 1,
  62. FORMAT => 'int32u',
  63. FIRST_ENTRY => 0,
  64. IS_OFFSET => [ 2 ], # tag 2 is 'IsOffset'
  65. IS_SUBDIR => [ 11 ],
  66. GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
  67. NOTES => q{
  68. Tags found in the binary "STMN" format maker notes written by a number of
  69. Samsung models.
  70. },
  71. 0 => {
  72. Name => 'MakerNoteVersion',
  73. Format => 'undef[8]',
  74. },
  75. 2 => {
  76. Name => 'PreviewImageStart',
  77. OffsetPair => 3, # associated byte count tagID
  78. DataTag => 'PreviewImage',
  79. IsOffset => 3,
  80. Protected => 2,
  81. },
  82. 3 => {
  83. Name => 'PreviewImageLength',
  84. OffsetPair => 2, # point to associated offset
  85. DataTag => 'PreviewImage',
  86. Protected => 2,
  87. },
  88. 11 => {
  89. Name => 'SamsungIFD',
  90. # Note: this is not always an IFD. In many models the string
  91. # "Park Byeongchan" is found at this location
  92. Condition => '$$valPt =~ /^[^\0]\0\0\0/',
  93. Format => 'undef[$size - 44]',
  94. SubDirectory => { TagTable => 'Image::ExifTool::Samsung::IFD' },
  95. },
  96. );
  97. %Image::ExifTool::Samsung::IFD = (
  98. PROCESS_PROC => \&ProcessSamsungIFD,
  99. NOTES => q{
  100. This is a standard-format IFD found in the maker notes of some Samsung
  101. models, except that the entry count is a 4-byte integer and the offsets are
  102. relative to the end of the IFD. Currently, no tags in this IFD are known,
  103. so the Unknown (-u) or Verbose (-v) option must be used to see this
  104. information.
  105. },
  106. GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
  107. # 0x0001 - undef[4000|4100]: starts with "MN_PRV" (or all zeros)
  108. # 0x0002 - undef[7000] : starts with "Kim Miae"
  109. # 0x0003 - undef[5000] : starts with "Lee BK"
  110. # 0x0004 - undef[500|2000] : starts with "IPCD" (or all zeros)
  111. # 0x0006 - undef[100|200] : starts with "MN_ADS" (or all zeros)
  112. );
  113. # Samsung maker notes (ref PH)
  114. %Image::ExifTool::Samsung::Type2 = (
  115. WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
  116. CHECK_PROC => \&Image::ExifTool::Exif::CheckExif,
  117. WRITABLE => 1,
  118. GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
  119. NOTES => 'Tags found in the EXIF-format maker notes of newer Samsung models.',
  120. 0x0001 => {
  121. Name => 'MakerNoteVersion',
  122. Writable => 'undef',
  123. Count => 4,
  124. },
  125. 0x0002 => {
  126. Name => 'DeviceType',
  127. Writable => 'int32u',
  128. PrintHex => 1,
  129. PrintConv => {
  130. 0x1000 => 'Compact Digital Camera',
  131. 0x2000 => 'High-end NX Camera',
  132. 0x3000 => 'HXM Video Camera',
  133. 0x12000 => 'Cell Phone',
  134. 0x300000 => 'SMX Video Camera',
  135. },
  136. },
  137. 0x0003 => {
  138. Name => 'SamsungModelID',
  139. Writable => 'int32u',
  140. PrintHex => 1,
  141. PrintConv => {
  142. 0x100101c => 'NX10',
  143. 0x1001226 => 'HMX-S10BP',
  144. 0x1001226 => 'HMX-S15BP',
  145. 0x1001233 => 'HMX-Q10',
  146. 0x1001234 => 'HMX-H300',
  147. 0x1001234 => 'HMX-H304',
  148. 0x100130c => 'NX100',
  149. 0x1001327 => 'NX11',
  150. 0x170104e => 'ES70, ES71 / VLUU ES70, ES71 / SL600',
  151. 0x1701052 => 'ES73 / VLUU ES73 / SL605',
  152. 0x1701300 => 'ES28 / VLUU ES28',
  153. 0x1701303 => 'ES74,ES75,ES78 / VLUU ES75,ES78',
  154. 0x2001046 => 'PL150 / VLUU PL150 / TL210 / PL151',
  155. 0x2001311 => 'PL120,PL121 / VLUU PL120,PL121',
  156. 0x2001315 => 'PL170,PL171 / VLUUPL170,PL171',
  157. 0x200131e => 'PL210, PL211 / VLUU PL210, PL211',
  158. 0x2701317 => 'PL20,PL21 / VLUU PL20,PL21',
  159. 0x2a0001b => 'WP10 / VLUU WP10 / AQ100',
  160. 0x3000000 => 'Various Models (0x3000000)',
  161. #0x3000000 => 'DV150F / DV151F / DV155F',
  162. #0x3000000 => 'NX mini',
  163. #0x3000000 => 'NX3000',
  164. #0x3000000 => 'ST150F / ST151F / ST152F',
  165. #0x3000000 => 'WB250F / WB251F / WB252F',
  166. #0x3000000 => 'WB30F / WB31F / WB32F',
  167. #0x3000000 => 'WB350F / WB351F / WB352F',
  168. #0x3000000 => 'WB800F',
  169. 0x3a00018 => 'Various Models (0x3a00018)',
  170. #0x3a00018 => 'ES30 / VLUU ES30',
  171. #0x3a00018 => 'ES80 / ES81',
  172. #0x3a00018 => 'PL200 / VLUU PL200',
  173. #0x3a00018 => 'PL80 / VLUU PL80 / SL630 / PL81',
  174. #0x3a00018 => 'PL90 / VLUU PL90',
  175. #0x3a00018 => 'WB1100F / WB1101F / WB1102F',
  176. #0x3a00018 => 'WB2200F',
  177. 0x400101f => 'ST1000 / ST1100 / VLUU ST1000 / CL65',
  178. 0x4001022 => 'ST550 / VLUU ST550 / TL225',
  179. 0x4001025 => 'Various Models (0x4001025)',
  180. #0x4001025 => 'DV300 / DV300F / DV305F',
  181. #0x4001025 => 'ST500 / VLUU ST500 / TL220',
  182. #0x4001025 => 'ST200 / ST200F / ST201 / ST201F / ST205F',
  183. 0x400103e => 'VLUU ST5500, ST5500, CL80',
  184. 0x4001041 => 'VLUU ST5000, ST5000, TL240',
  185. 0x4001043 => 'ST70 / VLUU ST70 / ST71',
  186. 0x400130a => 'Various Models (0x400130a)',
  187. #0x400130a => 'VLUU ST100, ST100',
  188. #0x400130a => 'VLUU ST600, ST600',
  189. #0x400130a => 'VLUU ST80, ST80',
  190. 0x400130e => 'ST90,ST91 / VLUU ST90,ST91',
  191. 0x4001313 => 'VLUU ST95, ST95',
  192. 0x4a00015 => 'VLUU ST60',
  193. 0x4a0135b => 'ST30, ST65 / VLUU ST65 / ST67',
  194. 0x5000000 => 'Various Models (0x5000000)',
  195. #0x5000000 => 'EX2F',
  196. #0x5000000 => 'NX1000',
  197. #0x5000000 => 'NX20',
  198. #0x5000000 => 'NX200',
  199. #0x5000000 => 'NX210',
  200. #0x5000000 => 'ST96',
  201. #0x5000000 => 'WB750',
  202. #0x5000000 => 'ST700',
  203. 0x5001038 => 'Various Models (0x5001038)',
  204. #0x5001038 => 'EK-GN120',
  205. #0x5001038 => 'HMX-E10',
  206. #0x5001038 => 'NX1',
  207. #0x5001038 => 'NX2000',
  208. #0x5001038 => 'NX30',
  209. #0x5001038 => 'NX300',
  210. #0x5001038 => 'WB2000',
  211. 0x500103a => 'WB650 / VLUU WB650 / WB660',
  212. 0x500103c => 'WB600 / VLUU WB600 / WB610',
  213. 0x500133e => 'WB150 / WB150F / WB152 / WB152F / WB151',
  214. 0x5a0000f => 'WB5000 / HZ25W',
  215. 0x6001036 => 'EX1',
  216. 0x700131c => 'VLUU SH100, SH100',
  217. 0x27127002 => 'SMX-C20N',
  218. },
  219. },
  220. # 0x0004 - undef[x] (SamsungContentsID?)
  221. # 0x000a - int32u (ContinuousShotMode?)
  222. # 0x000b - int16u (BestPhotoMode?)
  223. # 0x000c - int32u ? values: 0,1
  224. # 0x000e - int32u[2] (SoundMultiPicture?)
  225. # 0x0010 - rational64u ? values: undef,inf
  226. # 0x0020 - int16u[2] (ColorInfoDCM?)
  227. 0x0021 => { #1
  228. Name => 'PictureWizard',
  229. Writable => 'int16u',
  230. SubDirectory => { TagTable => 'Image::ExifTool::Samsung::PictureWizard' },
  231. },
  232. # 0x0022 - int32u (CaptureMode?)
  233. # 0x0023 - string: "0123456789" (PH) (placeholder for SerialNumber?)
  234. # 0x0025 - int32u (ImageCount?)
  235. # 0x002a - undef[4] (SNSDirectShare?)
  236. # 0x002f - string (GPSInfo01?)
  237. 0x0030 => { #1 (NX100 with GPS)
  238. Name => 'LocalLocationName',
  239. Writable => 'string',
  240. Format => 'undef',
  241. # this contains 2 place names (in Korean if in Korea), separated by a null+space
  242. # - terminate at double-null and replace nulls with newlines
  243. ValueConv => '$val=~s/\0\0.*//; $val=~s/\0 */\n/g; $val',
  244. ValueConvInv => '$val=~s/(\x0d\x0a|\x0d|\x0a)/\0 /g; $val . "\0\0"'
  245. },
  246. 0x0031 => { #1 (NX100 with GPS)
  247. Name => 'LocationName',
  248. Writable => 'string',
  249. },
  250. # 0x0032 - string (GPSInfo03)
  251. # 0x0033 - string (GPSInfo04)
  252. # 0x0034 - string (GPSInfo05)
  253. 0x0035 => {
  254. Name => 'PreviewIFD',
  255. Condition => '$$self{TIFF_TYPE} eq "SRW"', # (not an IFD in JPEG images)
  256. Groups => { 1 => 'PreviewIFD' },
  257. Flags => 'SubIFD',
  258. SubDirectory => {
  259. TagTable => 'Image::ExifTool::Nikon::PreviewIFD',
  260. ByteOrder => 'Unknown',
  261. Start => '$val',
  262. },
  263. },
  264. # 0x003a - int16u[2] (SmartLensInfo?)
  265. # 0x003b - int16u[2] (PhotoStyleSelectInfo?)
  266. # 0x003c - int16u (SmartRange?)
  267. # 0x003d - int16u[5] (SmartCropInfo?)
  268. # 0x003e - int32u (DualCapture?)
  269. # 0x003f - int16u[2] (SGIFInfo?)
  270. # 0x0040 - int32u (FavoriteTagging?) values: 0
  271. 0x0043 => { #1 (NC)
  272. Name => 'CameraTemperature',
  273. Groups => { 2 => 'Camera' },
  274. Writable => 'rational64s',
  275. # (DPreview samples all 0.2 C --> pre-production model)
  276. PrintConv => '"$val C"',
  277. PrintConvInv => '$val=~s/ ?C//; $val',
  278. },
  279. 0x0045 => { Name => 'RawCompressionMode', Writable => 'int32u' },
  280. # 0x004a - int32u[7] (ImageVerification?)
  281. # 0x004b - int32u[2] (RewindInfo?)
  282. # 0x0050 - int32u (ColorSpace? - inconsistent) values: 1
  283. # 0x0054 - int16u[2] (WeatherInfo?)
  284. # 0x0060 - undef (AEInfo?)
  285. # 0x0080 - undef (AFInfo?)
  286. # 0x00a0 - undef[8192] (AWBInfo1): white balance information (ref 1):
  287. # At byte 5788, the WBAdjust: "Adjust\0\X\0\Y\0\Z\xee\xea\xce\xab", where
  288. # Y = BA adjust (0=Blue7, 7=0, 14=Amber7), Z = MG (0=Magenta7, 7=0, 14=Green7)
  289. # 0x00a1 - undef (AWBInfo2?)
  290. # 0x00c0 - undef (IPCInfo?)
  291. # 0x00c7 - undef (SmartFunctionInfo?)
  292. # 0x00e0 - int16u (SceneResult?)
  293. # 0x00e1 - int16u[8] (SADebugInfo01?)
  294. # 0x00e1 - int16u[x] (SADebugInfo02?)
  295. 0x0100 => {
  296. Name => 'FaceDetect',
  297. Writable => 'int16u',
  298. PrintConv => { 0 => 'Off', 1 => 'On' }, # (NC)
  299. },
  300. # 0x0101 - int16u[6] (FaceDetectInfo?)
  301. # 0x0102 - int16u[x] (FaceDetectInfo?)
  302. 0x0120 => {
  303. Name => 'FaceRecognition',
  304. Writable => 'int32u',
  305. PrintConv => { 0 => 'Off', 1 => 'On' }, # (NC)
  306. },
  307. 0x0123 => { Name => 'FaceName', Writable => 'string' },
  308. # 0x140 - undef (LensInfo?)
  309. #
  310. # the following tags found only in SRW images
  311. #
  312. # 0xa000 - rational64u: 1 or 1.1 (ref PH) (MakerNoteVersion?)
  313. 0xa001 => { #1
  314. Name => 'FirmwareName',
  315. Groups => { 2 => 'Camera' },
  316. Writable => 'string',
  317. },
  318. # 0xa002 - string[30]: '0' or 'DY049P000000' (ref PH) (BodySerialNumber?)
  319. 0xa003 => { #1 (SRW images only)
  320. Name => 'LensType',
  321. Groups => { 2 => 'Camera' },
  322. Writable => 'int16u',
  323. Count => -1,
  324. PrintConv => [ \%samsungLensTypes ],
  325. },
  326. 0xa004 => { #1
  327. Name => 'LensFirmware',
  328. Groups => { 2 => 'Camera' },
  329. Writable => 'string',
  330. },
  331. 0xa005 => {
  332. Name => 'InternalLensSerialNumber', # Not the printed serial number (ref 1)
  333. Writable => 'string',
  334. },
  335. 0xa010 => { #1
  336. Name => 'SensorAreas',
  337. Groups => { 2 => 'Camera' },
  338. Notes => 'full and valid sensor areas',
  339. Writable => 'int32u',
  340. Count => 8,
  341. },
  342. 0xa011 => { #1
  343. Name => 'ColorSpace',
  344. Writable => 'int16u',
  345. PrintConv => {
  346. 0 => 'sRGB',
  347. 1 => 'Adobe RGB',
  348. },
  349. },
  350. 0xa012 => { #1
  351. Name => 'SmartRange',
  352. Writable => 'int16u',
  353. PrintConv => { 0 => 'Off', 1 => 'On' },
  354. },
  355. 0xa013 => { #1
  356. Name => 'ExposureCompensation',
  357. Writable => 'rational64s',
  358. },
  359. 0xa014 => { #1
  360. Name => 'ISO',
  361. Writable => 'int32u',
  362. },
  363. 0xa018 => { #1
  364. Name => 'ExposureTime',
  365. Writable => 'rational64u',
  366. PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
  367. PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)',
  368. },
  369. 0xa019 => { #1
  370. Name => 'FNumber',
  371. Priority => 0,
  372. Writable => 'rational64u',
  373. PrintConv => 'sprintf("%.1f",$val)',
  374. PrintConvInv => '$val',
  375. },
  376. 0xa01a => { #1
  377. Name => 'FocalLengthIn35mmFormat',
  378. Groups => { 2 => 'Camera' },
  379. Priority => 0,
  380. Format => 'int32u',
  381. ValueConv => '$val / 10',
  382. ValueConvInv => '$val * 10',
  383. PrintConv => '"$val mm"',
  384. PrintConvInv => '$val=~s/\s*mm$//;$val',
  385. },
  386. # 0xa01b - int32u (ImageCount?)
  387. # 0xa01b - int16u (LDCLens?)
  388. 0xa020 => { #1
  389. Name => 'EncryptionKey',
  390. Writable => 'int32u',
  391. Count => 11,
  392. Protected => 1,
  393. DataMember => 'EncryptionKey',
  394. RawConv => '$$self{EncryptionKey} = [ split(" ",$val) ]; $val',
  395. Notes => 'key used to decrypt the tags below',
  396. # value is "305 72 737 456 282 307 519 724 13 505 193"
  397. },
  398. 0xa021 => { #1
  399. Name => 'WB_RGGBLevelsUncorrected',
  400. Writable => 'int32u',
  401. Count => 4,
  402. Notes => 'these tags not corrected for WB_RGGBLevelsBlack',
  403. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0")',
  404. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0)',
  405. },
  406. 0xa022 => { #1
  407. Name => 'WB_RGGBLevelsAuto',
  408. Writable => 'int32u',
  409. Count => 4,
  410. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,-4)',
  411. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,4)',
  412. },
  413. 0xa023 => { #1
  414. Name => 'WB_RGGBLevelsIlluminator1',
  415. Writable => 'int32u',
  416. Count => 4,
  417. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,-8)',
  418. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,8)',
  419. },
  420. 0xa024 => { #1
  421. Name => 'WB_RGGBLevelsIlluminator2',
  422. Writable => 'int32u',
  423. Count => 4,
  424. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,-1)',
  425. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,1)',
  426. },
  427. #this doesn't seem correct
  428. #0xa025 => { #PH/1 (PostAEGain?)
  429. # Name => 'ColorTemperatureAuto',
  430. # Writable => 'int32u',
  431. # RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,6)',
  432. # RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,-6)',
  433. #},
  434. 0xa028 => { #2/PH
  435. Name => 'WB_RGGBLevelsBlack',
  436. Writable => 'int32s',
  437. Count => 4,
  438. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0")',
  439. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0)',
  440. },
  441. 0xa030 => { #1
  442. Name => 'ColorMatrix',
  443. Writable => 'int32s',
  444. Count => 9,
  445. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0)',
  446. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0")',
  447. },
  448. 0xa031 => { #1
  449. Name => 'ColorMatrixSRGB',
  450. Writable => 'int32s',
  451. Count => 9,
  452. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0)',
  453. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0")',
  454. },
  455. 0xa032 => { #1
  456. Name => 'ColorMatrixAdobeRGB',
  457. Writable => 'int32s',
  458. Count => 9,
  459. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0)',
  460. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0")',
  461. },
  462. 0xa033 => { #1
  463. Name => 'CbCrMatrixDefault',
  464. Writable => 'int32s',
  465. Count => 4,
  466. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0)',
  467. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0")',
  468. },
  469. 0xa034 => { #1
  470. Name => 'CbCrMatrix',
  471. Writable => 'int32s',
  472. Count => 4,
  473. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,4)',
  474. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,-4)',
  475. },
  476. 0xa035 => { #1
  477. Name => 'CbCrGainDefault',
  478. Writable => 'int32u',
  479. Count => 2,
  480. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0")',
  481. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0)',
  482. },
  483. 0xa036 => { #1
  484. Name => 'CbCrGain',
  485. Writable => 'int32u',
  486. Count => 2,
  487. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,-2)',
  488. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,2)',
  489. },
  490. 0xa040 => { #1
  491. Name => 'ToneCurveSRGBDefault',
  492. Writable => 'int32u',
  493. Count => 23,
  494. Notes => q{
  495. first value gives the number of tone curve entries. This is followed by an
  496. array of X coordinates then an array of Y coordinates
  497. },
  498. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0,"-0")',
  499. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0",0)',
  500. },
  501. 0xa041 => { #1
  502. Name => 'ToneCurveAdobeRGBDefault',
  503. Writable => 'int32u',
  504. Count => 23,
  505. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0,"-0")',
  506. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0",0)',
  507. },
  508. 0xa042 => { #1
  509. Name => 'ToneCurveSRGB',
  510. Writable => 'int32u',
  511. Count => 23,
  512. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0,"-0")',
  513. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0",0)',
  514. },
  515. 0xa043 => { #1
  516. Name => 'ToneCurveAdobeRGB',
  517. Writable => 'int32u',
  518. Count => 23,
  519. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0,"-0")',
  520. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0",0)',
  521. },
  522. 0xa048 => { #1
  523. Name => 'RawData',
  524. Unknown => 1,
  525. Writable => 'int32s',
  526. Count => 12,
  527. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0)',
  528. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0")',
  529. },
  530. 0xa050 => { #1
  531. Name => 'Distortion',
  532. Unknown => 1,
  533. Writable => 'int32s',
  534. Count => 8,
  535. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0)',
  536. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0")',
  537. },
  538. 0xa051 => { #1
  539. Name => 'ChromaticAberration',
  540. Unknown => 1,
  541. Writable => 'int16u',
  542. Count => 22,
  543. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0",-7,-3)',
  544. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0,7,3)',
  545. },
  546. 0xa052 => { #1
  547. Name => 'Vignetting',
  548. Unknown => 1,
  549. Writable => 'int16u',
  550. Count => 15,
  551. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0,"-0")',
  552. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0",0)',
  553. },
  554. 0xa053 => { #1
  555. Name => 'VignettingCorrection',
  556. Unknown => 1,
  557. Writable => 'int16u',
  558. Count => 15,
  559. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0,"-0")',
  560. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0",0)',
  561. },
  562. 0xa054 => { #1
  563. Name => 'VignettingSetting',
  564. Unknown => 1,
  565. Writable => 'int16u',
  566. Count => 15,
  567. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0,"-0")',
  568. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0",0)',
  569. },
  570. 0xa055 => { #1
  571. Name => 'Samsung_Type2_0xa055', # (DistortionCamera1st?)
  572. Unknown => 1,
  573. Hidden => 1,
  574. Writable => 'int32s',
  575. Count => 8,
  576. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,8)',
  577. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,-8)',
  578. },
  579. 0xa056 => { #1
  580. Name => 'Samsung_Type2_0xa056', # (DistortionCamera2nd?)
  581. Unknown => 1,
  582. Hidden => 1,
  583. Writable => 'int32s',
  584. Count => 8,
  585. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,5)',
  586. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,-5)',
  587. },
  588. 0xa057 => { #1
  589. Name => 'Samsung_Type2_0xa057', # (DistortionCameraSetting?)
  590. Unknown => 1,
  591. Hidden => 1,
  592. Writable => 'int32s',
  593. Count => 8,
  594. RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,2)',
  595. RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,-2)',
  596. },
  597. # 0xa060 - rational64u (CISTemperature?)
  598. # 0xa061 - int16u (Compression?)
  599. );
  600. # Picture Wizard information (ref 1)
  601. %Image::ExifTool::Samsung::PictureWizard = (
  602. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  603. WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
  604. CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
  605. WRITABLE => 1,
  606. FORMAT => 'int16u',
  607. FIRST_ENTRY => 0,
  608. GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
  609. 0 => {
  610. Name => 'PictureWizardMode',
  611. PrintConvColumns => 3,
  612. PrintConv => { #3
  613. 0 => 'Standard',
  614. 1 => 'Vivid',
  615. 2 => 'Portrait',
  616. 3 => 'Landscape',
  617. 4 => 'Forest',
  618. 5 => 'Retro',
  619. 6 => 'Cool',
  620. 7 => 'Calm',
  621. 8 => 'Classic',
  622. 9 => 'Custom1',
  623. 10 => 'Custom2',
  624. 11 => 'Custom3',
  625. 255 => 'n/a', #PH
  626. },
  627. },
  628. 1 => 'PictureWizardColor',
  629. 2 => {
  630. Name => 'PictureWizardSaturation',
  631. ValueConv => '$val - 4',
  632. ValueConvInv => '$val + 4',
  633. },
  634. 3 => {
  635. Name => 'PictureWizardSharpness',
  636. ValueConv => '$val - 4',
  637. ValueConvInv => '$val + 4',
  638. },
  639. 4 => {
  640. Name => 'PictureWizardContrast',
  641. ValueConv => '$val - 4',
  642. ValueConvInv => '$val + 4',
  643. },
  644. );
  645. # INFO tags in Samsung MP4 videos (ref PH)
  646. %Image::ExifTool::Samsung::INFO = (
  647. PROCESS_PROC => \&ProcessINFO,
  648. GROUPS => { 0 => 'MakerNotes', 2 => 'Video' },
  649. NOTES => q{
  650. This information is found in MP4 videos from Samsung models such as the
  651. SMX-C20N.
  652. },
  653. EFCT => 'Effect', # (guess)
  654. QLTY => 'Quality',
  655. # MDEL - value: 0
  656. # ASPT - value: 1, 2
  657. );
  658. # Samsung MP4 TAGS information (PH - from WP10 sample)
  659. # --> very similar to Sanyo MP4 information
  660. %Image::ExifTool::Samsung::MP4 = (
  661. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  662. GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
  663. NOTES => q{
  664. This information is found in Samsung MP4 videos from models such as the
  665. WP10.
  666. },
  667. 0x00 => {
  668. Name => 'Make',
  669. Format => 'string[24]',
  670. PrintConv => 'ucfirst(lc($val))',
  671. },
  672. 0x18 => {
  673. Name => 'Model',
  674. Description => 'Camera Model Name',
  675. Format => 'string[16]',
  676. },
  677. 0x2e => { # (NC)
  678. Name => 'ExposureTime',
  679. Format => 'int32u',
  680. ValueConv => '$val ? 10 / $val : 0',
  681. PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
  682. },
  683. 0x32 => {
  684. Name => 'FNumber',
  685. Format => 'rational64u',
  686. PrintConv => 'sprintf("%.1f",$val)',
  687. },
  688. 0x3a => { # (NC)
  689. Name => 'ExposureCompensation',
  690. Format => 'rational64s',
  691. PrintConv => '$val ? sprintf("%+.1f", $val) : 0',
  692. },
  693. 0x6a => {
  694. Name => 'ISO',
  695. Format => 'int32u',
  696. },
  697. 0x7d => {
  698. Name => 'Software',
  699. Format => 'string[32]',
  700. # (these tags are not at a constant offset for Olympus/Sanyo videos,
  701. # so just to be safe use this to validate subsequent tags)
  702. RawConv => q{
  703. $val =~ /^SAMSUNG/ or return undef;
  704. $$self{SamsungMP4} = 1;
  705. return $val;
  706. },
  707. },
  708. 0xf4 => {
  709. Name => 'Thumbnail',
  710. Condition => '$$self{SamsungMP4}',
  711. SubDirectory => {
  712. TagTable => 'Image::ExifTool::Samsung::Thumbnail',
  713. Base => '$start',
  714. },
  715. },
  716. );
  717. # thumbnail image information found in MP4 videos (similar in Olympus,Samsung,Sanyo)
  718. %Image::ExifTool::Samsung::Thumbnail = (
  719. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  720. GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
  721. FIRST_ENTRY => 0,
  722. FORMAT => 'int32u',
  723. 1 => 'ThumbnailWidth',
  724. 2 => 'ThumbnailHeight',
  725. 3 => 'ThumbnailLength',
  726. 4 => { Name => 'ThumbnailOffset', IsOffset => 1 },
  727. );
  728. # Samsung MP4 @sec information (PH - from WB30F sample)
  729. %Image::ExifTool::Samsung::sec = (
  730. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  731. GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
  732. NOTES => q{
  733. This information is found in the @sec atom of Samsung MP4 videos from models
  734. such as the WB30F.
  735. },
  736. 0x00 => {
  737. Name => 'Make',
  738. Format => 'string[32]',
  739. PrintConv => 'ucfirst(lc($val))',
  740. },
  741. 0x20 => {
  742. Name => 'Model',
  743. Description => 'Camera Model Name',
  744. Format => 'string[32]',
  745. },
  746. 0x200 => { Name => 'ThumbnailWidth', Format => 'int32u' },
  747. 0x204 => { Name => 'ThumbnailHeight', Format => 'int32u' },
  748. 0x208 => { Name => 'ThumbnailLength', Format => 'int32u' }, # (2 bytes too long in my sample)
  749. 0x20c => {
  750. Name => 'ThumbnailImage',
  751. Groups => { 2 => 'Preview' },
  752. Format => 'undef[$val{0x208}]',
  753. Notes => 'the THM image, embedded metadata is extracted as the first sub-document',
  754. SetBase => 1,
  755. RawConv => q{
  756. my $pt = $self->ValidateImage(\$val, $tag);
  757. if ($pt) {
  758. $$self{BASE} += 0x20c;
  759. $$self{DOC_NUM} = ++$$self{DOC_COUNT};
  760. $self->ExtractInfo($pt, { ReEntry => 1 });
  761. $$self{DOC_NUM} = 0;
  762. }
  763. return $pt;
  764. },
  765. },
  766. );
  767. # Samsung MP4 smta information (PH - from SM-C101 sample)
  768. %Image::ExifTool::Samsung::smta = (
  769. GROUPS => { 0 => 'MakerNotes', 2 => 'Video' },
  770. NOTES => q{
  771. This information is found in the smta atom of Samsung MP4 videos from models
  772. such as the Galaxy S4.
  773. },
  774. svss => {
  775. Name => 'SamsungSvss',
  776. SubDirectory => { TagTable => 'Image::ExifTool::Samsung::svss' },
  777. },
  778. # swtr - 4 bytes, all zero
  779. # scid - 8 bytes, all zero
  780. # saut - 4 bytes, all zero
  781. );
  782. # Samsung MP4 svss information (PH - from SM-C101 sample)
  783. %Image::ExifTool::Samsung::svss = (
  784. GROUPS => { 0 => 'MakerNotes', 2 => 'Video' },
  785. NOTES => q{
  786. This information is found in the svss atom of Samsung MP4 videos from models
  787. such as the Galaxy S4.
  788. },
  789. # junk - 10240 bytes, all zero
  790. );
  791. # thumbnail image information found in some MP4 videos
  792. %Image::ExifTool::Samsung::Thumbnail2 = (
  793. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  794. GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
  795. FIRST_ENTRY => 0,
  796. FORMAT => 'int32u',
  797. 1 => 'ThumbnailWidth',
  798. 2 => 'ThumbnailHeight',
  799. 3 => 'ThumbnailLength',
  800. 4 => { Name => 'ThumbnailOffset', IsOffset => 1 },
  801. );
  802. # information extracted from Samsung trailer (ie. Samsung SM-T805 "Sound & Shot" JPEG)
  803. %Image::ExifTool::Samsung::Trailer = (
  804. GROUPS => { 0 => 'MakerNotes', 2 => 'Other' },
  805. VARS => { NO_ID => 1 },
  806. NOTES => q{
  807. Tags extracted from the trailer of JPEG images written when using certain
  808. features (such as "Sound & Shot" or "Shot & More") from Samsung models such
  809. as the Galaxy S4 and Tab S.
  810. },
  811. # stuff written with "Shot & More" feature
  812. '0x0001' => { Name => 'EmbeddedImage', Groups => { 2 => 'Preview' }, Binary => 1 },
  813. '0x0001-name' => 'EmbeddedImageName',
  814. # 0x0830 - unknown (164004 bytes, name like "1165724808.pre")
  815. # stuff written with "Sound & Shot" feature
  816. '0x0100' => { Name => 'EmbeddedAudioFile', Binary => 1 },
  817. '0x0100-name' => 'EmbeddedAudioFileName',
  818. # 0x0800 - SoundShot_Meta_Info (contains only already-extracted sound shot name)
  819. );
  820. # Samsung composite tags
  821. %Image::ExifTool::Samsung::Composite = (
  822. GROUPS => { 2 => 'Image' },
  823. WB_RGGBLevels => {
  824. Require => {
  825. 0 => 'WB_RGGBLevelsUncorrected',
  826. 1 => 'WB_RGGBLevelsBlack',
  827. },
  828. ValueConv => q{
  829. my @a = split ' ', $val[0];
  830. my @b = split ' ', $val[1];
  831. $a[$_] -= $b[$_] foreach 0..$#a;
  832. return "@a";
  833. },
  834. },
  835. );
  836. # add our composite tags
  837. Image::ExifTool::AddCompositeTags('Image::ExifTool::Samsung');
  838. #------------------------------------------------------------------------------
  839. # Encrypt/Decrypt NX10 information
  840. # Inputs: 0) ExifTool ref, 1) value as a string of integers,
  841. # 2) tagInfo hash ref, 3-N) encryption salt values
  842. # Returns: encrypted/decrypted value
  843. # Notes:
  844. # 1) The encryption salt starts with '-' to reverse the encryption algorithm
  845. # 2) Additional salt values are provided when tag stores multiple arrays
  846. # (in which case the first value of the tag gives the array length)
  847. sub Crypt($$$@)
  848. {
  849. my ($et, $val, $tagInfo, @salt) = @_;
  850. my $key = $$et{EncryptionKey} or return undef;
  851. my $format = $$tagInfo{Writable} || $$tagInfo{Format} or return undef;
  852. return undef unless $formatMinMax{$format};
  853. my ($min, $max) = @{$formatMinMax{$format}};
  854. my @a = split ' ', $val;
  855. my $newSalt = (@salt > 1) ? 1 : 0; # skip length entry if this is an array
  856. my ($i, $sign, $salt, $start);
  857. for ($i=$newSalt; $i<@a; ++$i) {
  858. if ($i == $newSalt) {
  859. $start = $i;
  860. $salt = shift @salt;
  861. $sign = ($salt =~ s/^-//) ? -1 : 1;
  862. $newSalt += $a[0] if @salt;
  863. }
  864. $a[$i] += $sign * $$key[($salt+$i-$start) % scalar(@$key)];
  865. # handle integer wrap-around
  866. if ($sign > 0) {
  867. $a[$i] -= $max - $min + 1 if $a[$i] > $max;
  868. } else {
  869. $a[$i] += $max - $min + 1 if $a[$i] < $min;
  870. }
  871. }
  872. return "@a";
  873. }
  874. #------------------------------------------------------------------------------
  875. # Process Samsung MP4 INFO data
  876. # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
  877. # Returns: 1 on success
  878. sub ProcessINFO($$$)
  879. {
  880. my ($et, $dirInfo, $tagTablePtr) = @_;
  881. my $dataPt = $$dirInfo{DataPt};
  882. my $pos = $$dirInfo{DirStart};
  883. my $len = $$dirInfo{DirLen};
  884. my $end = $pos + $len;
  885. $et->VerboseDir('INFO', undef, $len);
  886. while ($pos + 8 <= $end) {
  887. my $tag = substr($$dataPt, $pos, 4);
  888. my $val = Get32u($dataPt, $pos + 4);
  889. unless ($$tagTablePtr{$tag}) {
  890. my $name = "Samsung_INFO_$tag";
  891. $name =~ tr/-_0-9a-zA-Z//dc;
  892. AddTagToTable($tagTablePtr, $tag, { Name => $name }) if $name;
  893. }
  894. $et->HandleTag($tagTablePtr, $tag, $val);
  895. $pos += 8;
  896. }
  897. return 1;
  898. }
  899. #------------------------------------------------------------------------------
  900. # Inputs: 0) ExifTool object ref, 1) source dirInfo ref, 2) tag table ref
  901. # Returns: true on success
  902. sub ProcessSamsungIFD($$$)
  903. {
  904. my ($et, $dirInfo, $tagTablePtr) = @_;
  905. my $len = $$dirInfo{DataLen};
  906. my $pos = $$dirInfo{DirStart};
  907. return 0 unless $pos + 4 < $len;
  908. my $dataPt = $$dirInfo{DataPt};
  909. my $buff = substr($$dataPt, $pos, 4);
  910. # this is not an IFD for many models
  911. # (the string "Park Byeongchan" is often found here)
  912. return 0 unless $buff =~ s/^([^\0])\0\0\0/$1\0$1\0/s;
  913. my $numEntries = ord $1;
  914. if ($$et{HTML_DUMP}) {
  915. my $pt = $$dirInfo{DirStart} + $$dirInfo{DataPos} + $$dirInfo{Base};
  916. $et->HDump($pt-44, 44, "MakerNotes header", 'Samsung');
  917. $et->HDump($pt, 4, "MakerNotes entries", "Format: int32u\nEntry count: $numEntries");
  918. $$dirInfo{NoDumpEntryCount} = 1;
  919. }
  920. substr($$dataPt, $pos, 4) = $buff; # insert bogus 2-byte entry count
  921. # offset base is at end of IFD
  922. my $shift = $$dirInfo{DirStart} + 4 + $numEntries * 12 + 4;
  923. $$dirInfo{Base} += $shift;
  924. $$dirInfo{DataPos} -= $shift;
  925. $$dirInfo{DirStart} += 2; # start at bogus entry count
  926. $$dirInfo{ZeroOffsetOK} = 1; # disable check for zero offset
  927. delete $$et{NO_UNKNOWN}; # (set for BinaryData, but not for EXIF IFD's)
  928. my $rtn = Image::ExifTool::Exif::ProcessExif($et, $dirInfo, $tagTablePtr);
  929. substr($$dataPt, $pos + 2, 1) = "\0"; # remove bogus count
  930. return $rtn;
  931. }
  932. #------------------------------------------------------------------------------
  933. # Read/write Samsung trailer (ie. "Sound & Shot" written by Galaxy Tab S (SM-T805))
  934. # Inputs: 0) ExifTool object reference, 1) dirInfo reference
  935. # Returns: 1 on success, 0 not valid Samsung trailer, or -1 error writing
  936. # - updates DataPos to point to start of Samsung trailer
  937. # - updates DirLen to existing trailer length
  938. sub ProcessSamsung($$$)
  939. {
  940. my ($et, $dirInfo) = @_;
  941. my $raf = $$dirInfo{RAF};
  942. my $offset = $$dirInfo{Offset} || 0;
  943. my $outfile = $$dirInfo{OutFile};
  944. my $verbose = $et->Options('Verbose');
  945. my $unknown = $et->Options('Unknown');
  946. my ($buff, $buf2, $index, $offsetPos, $audioNOff, $audioSize);
  947. return 0 unless $raf->Seek(-6-$offset, 2) and $raf->Read($buff, 6) == 6 and
  948. ($buff eq 'QDIOBS' or $buff eq "\0\0SEFT");
  949. my $endPos = $raf->Tell();
  950. $raf->Seek(-2, 1) or return 0 if $buff eq 'QDIOBS'; # rewind to before 'BS'
  951. my $blockEnd = $raf->Tell();
  952. SetByteOrder('II');
  953. # read blocks backward until we find the SEFH/SEFT block
  954. # (the only other block I have seen is QDIO/QDIO)
  955. SamBlock:
  956. for (;;) {
  957. last unless $raf->Seek($blockEnd-8, 0) and $raf->Read($buff, 8) == 8;
  958. my $type = substr($buff, 4);
  959. last unless $type =~ /^\w+$/;
  960. my $len = Get32u(\$buff, 0);
  961. last unless $len < 0x10000 and $len >= 4 and $len + 8 < $blockEnd;
  962. last unless $raf->Seek(-8-$len, 1) and $raf->Read($buff, $len) == $len;
  963. $blockEnd -= $len + 8;
  964. unless ($type eq 'SEFT') { # look for directory block (ends with "SEFT")
  965. next unless $outfile and $type eq 'QDIO';
  966. # QDIO block format:
  967. # 0 - 'QDIO'
  968. # 4 - int32u: 101 (version)
  969. # 8 - int32u: 1
  970. # 12 - int32u: absolute offset of audio file start (augh!!)
  971. # 16 - int32u: absolute offset of audio file end (augh!!)
  972. # 20 - int32u: 20 (QDIO block length minus 8)
  973. # 24 - 'QDIO'
  974. if ($len == 20) {
  975. # save position of audio file offset in QDIO block
  976. $offsetPos = $endPos - $raf->Tell() + $len - 12;
  977. } else {
  978. $et->Error('Unsupported Samsung trailer QDIO block', 1);
  979. }
  980. next;
  981. }
  982. last unless $buff =~ /^SEFH/ and $len >= 12; # validate SEFH header
  983. my $dirPos = $raf->Tell() - $len;
  984. # my $ver = Get32u(\$buff, 0x04); # version (=101)
  985. my $count = Get32u(\$buff, 0x08);
  986. last if 12 + 12 * $count > $len;
  987. my $tagTablePtr = GetTagTable('Image::ExifTool::Samsung::Trailer');
  988. # scan ahead quickly to look for the block where the data comes first
  989. # (have only seen this to be the first in the directory, but just in case)
  990. my $firstBlock = 0;
  991. for ($index=0; $index<$count; ++$index) {
  992. my $entry = 12 + 12 * $index;
  993. my $noff = Get32u(\$buff, $entry + 4); # negative offset
  994. $firstBlock = $noff if $firstBlock < $noff;
  995. }
  996. # save trailer position and length
  997. my $dataPos = $$dirInfo{DataPos} = $dirPos - $firstBlock;
  998. my $dirLen = $$dirInfo{DirLen} = $endPos - $dataPos;
  999. if (($verbose or $$et{HTML_DUMP}) and not $outfile) {
  1000. $et->DumpTrailer($dirInfo);
  1001. return 1 if $$et{HTML_DUMP};
  1002. }
  1003. # read through the SEFH/SEFT directory entries
  1004. for ($index=0; $index<$count; ++$index) {
  1005. my $entry = 12 + 12 * $index;
  1006. # first 2 bytes always 0 (may be part of block type)
  1007. my $type = Get16u(\$buff, $entry + 2); # block type
  1008. my $noff = Get32u(\$buff, $entry + 4); # negative offset
  1009. my $size = Get32u(\$buff, $entry + 8); # block size
  1010. last SamBlock if $noff > $dirPos or $size > $noff or $size < 8;
  1011. $firstBlock = $noff if $firstBlock < $noff;
  1012. if ($outfile) {
  1013. next unless $type == 0x0100 and not $audioNOff;
  1014. # save offset and length of first audio file for QDIO block
  1015. last unless $raf->Seek($dirPos-$noff, 0) and $raf->Read($buf2, 8) == 8;
  1016. $len = Get32u(\$buf2, 4);
  1017. $audioNOff = $noff - 8 - $len; # negative offset to start of audio data
  1018. $audioSize = $size - 8 - $len;
  1019. next;
  1020. }
  1021. # add unknown tags if necessary
  1022. my $tag = sprintf("0x%.4x", $type);
  1023. unless ($$tagTablePtr{$tag}) {
  1024. next unless $unknown or $verbose;
  1025. my %tagInfo = (
  1026. Name => "SamsungTrailer_$tag",
  1027. Description => "Samsung Trailer $tag",
  1028. Unknown => 1,
  1029. Binary => 1,
  1030. );
  1031. AddTagToTable($tagTablePtr, $tag, \%tagInfo);
  1032. my %tagInfo2 = (
  1033. Name => "SamsungTrailer_${tag}Name",
  1034. Description => "Samsung Trailer $tag Name",
  1035. Unknown => 1,
  1036. );
  1037. AddTagToTable($tagTablePtr, "$tag-name", \%tagInfo2);
  1038. }
  1039. last unless $raf->Seek($dirPos-$noff, 0) and $raf->Read($buf2, $size) == $size;
  1040. # (could validate the first 4 bytes of the block because they
  1041. # are the same as the first 4 bytes of the directory entry)
  1042. $len = Get32u(\$buf2, 4);
  1043. last if $len + 8 > $size;
  1044. # extract tag name and value
  1045. $et->HandleTag($tagTablePtr, "$tag-name", undef,
  1046. DataPt => \$buf2,
  1047. DataPos => $dirPos - $noff,
  1048. Start => 8,
  1049. Size => $len,
  1050. );
  1051. $et->HandleTag($tagTablePtr, $tag, undef,
  1052. DataPt => \$buf2,
  1053. DataPos => $dirPos - $noff,
  1054. Start => 8 + $len,
  1055. Size => $size - (8 + $len),
  1056. );
  1057. }
  1058. if ($outfile) {
  1059. last unless $raf->Seek($dataPos, 0) and $raf->Read($buff, $dirLen) == $dirLen;
  1060. # adjust the absolute offset in the QDIO block if necessary
  1061. if ($offsetPos and $audioNOff) {
  1062. # initialize the audio file start/end position in the QDIO block
  1063. my $newPos = Tell($outfile) + $dirPos - $audioNOff - $dataPos;
  1064. Set32u($newPos, \$buff, length($buff) - $offsetPos);
  1065. Set32u($newPos + $audioSize, \$buff, length($buff) - $offsetPos + 4);
  1066. # add a fixup so the calling routine can apply further shifts if necessary
  1067. require Image::ExifTool::Fixup;
  1068. my $fixup = $$dirInfo{Fixup};
  1069. $fixup or $fixup = $$dirInfo{Fixup} = new Image::ExifTool::Fixup;
  1070. $fixup->AddFixup(length($buff) - $offsetPos);
  1071. $fixup->AddFixup(length($buff) - $offsetPos + 4);
  1072. }
  1073. $et->VPrint(0, "Writing Samsung trailer ($dirLen bytes)\n") if $verbose;
  1074. Write($$dirInfo{OutFile}, $buff) or return -1;
  1075. return 1;
  1076. }
  1077. return 1;
  1078. }
  1079. $et->Warn('Error processing Samsung trailer',1);
  1080. return 0;
  1081. }
  1082. #------------------------------------------------------------------------------
  1083. # Write Samsung STMN maker notes
  1084. # Inputs: 0) ExifTool object ref, 1) source dirInfo ref, 2) tag table ref
  1085. # Returns: Binary data block or undefined on error
  1086. sub WriteSTMN($$$)
  1087. {
  1088. my ($et, $dirInfo, $tagTablePtr) = @_;
  1089. # create a Fixup for the PreviewImage
  1090. $$dirInfo{Fixup} = new Image::ExifTool::Fixup;
  1091. my $val = Image::ExifTool::WriteBinaryData($et, $dirInfo, $tagTablePtr);
  1092. # force PreviewImage into the trailer even if it fits in EXIF segment
  1093. $$et{PREVIEW_INFO}{IsTrailer} = 1 if $$et{PREVIEW_INFO};
  1094. return $val;
  1095. }
  1096. 1; # end
  1097. __END__
  1098. =head1 NAME
  1099. Image::ExifTool::Samsung - Samsung EXIF maker notes tags
  1100. =head1 SYNOPSIS
  1101. This module is loaded automatically by Image::ExifTool when required.
  1102. =head1 DESCRIPTION
  1103. This module contains definitions required by Image::ExifTool to interpret
  1104. Samsung maker notes in EXIF information.
  1105. =head1 AUTHOR
  1106. Copyright 2003-2016, Phil Harvey (phil at owl.phy.queensu.ca)
  1107. This library is free software; you can redistribute it and/or modify it
  1108. under the same terms as Perl itself.
  1109. =head1 REFERENCES
  1110. =over 4
  1111. =item L<http://www.cybercom.net/~dcoffin/dcraw/>
  1112. =back
  1113. =head1 ACKNOWLEDGEMENTS
  1114. Thanks to Tae-Sun Park for decoding a number of tags, and Pascal de Bruijn
  1115. for the PictureWizard values.
  1116. =head1 SEE ALSO
  1117. L<Image::ExifTool::TagNames/Samsung Tags>,
  1118. L<Image::ExifTool(3pm)|Image::ExifTool>
  1119. =cut